Merge lp:~edwin-grubbs/launchpad/bug-230801-renewing-membership into lp:launchpad/db-devel

Proposed by Edwin Grubbs
Status: Merged
Approved by: Edwin Grubbs
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~edwin-grubbs/launchpad/bug-230801-renewing-membership
Merge into: lp:launchpad/db-devel
Diff against target: 949 lines (+296/-79)
39 files modified
lib/lp/archiveuploader/nascentuploadfile.py (+1/-1)
lib/lp/archiveuploader/tests/nascentuploadfile.txt (+71/-0)
lib/lp/bugs/templates/bug-portlet-subscribers.pt (+1/-1)
lib/lp/bugs/templates/bugtarget-filebug-submit-bug.pt (+1/-1)
lib/lp/bugs/templates/bugtarget-portlet-bugfilters.pt (+1/-1)
lib/lp/bugs/templates/bugtarget-portlet-bugtags.pt (+1/-1)
lib/lp/bugs/templates/bugtask-index.pt (+3/-3)
lib/lp/bugs/templates/bugtask-tasks-and-nominations-table-row.pt (+1/-1)
lib/lp/bugs/templates/bugtasks-and-nominations-table.pt (+1/-1)
lib/lp/bugs/templates/official-bug-target-manage-tags.pt (+1/-1)
lib/lp/code/templates/branch-import-details.pt (+1/-1)
lib/lp/code/templates/branch-index.pt (+1/-1)
lib/lp/code/templates/branch-listing.pt (+1/-1)
lib/lp/code/templates/branch-portlet-subscribers.pt (+1/-1)
lib/lp/code/templates/branch-related-bugs-specs.pt (+1/-1)
lib/lp/code/templates/branchmergeproposal-generic-listing.pt (+1/-1)
lib/lp/registry/browser/person.py (+4/-1)
lib/lp/registry/browser/tests/productrelease-views.txt (+1/-1)
lib/lp/registry/templates/object-timeline-graph.pt (+1/-1)
lib/lp/registry/templates/person-macros.pt (+1/-1)
lib/lp/registry/templates/product-new.pt (+1/-1)
lib/lp/registry/templates/productrelease-add-from-series.pt (+1/-1)
lib/lp/registry/templates/teammembership-index.pt (+1/-1)
lib/lp/registry/templates/timeline-macros.pt (+1/-1)
lib/lp/soyuz/templates/archive-edit-dependencies.pt (+1/-1)
lib/lp/soyuz/templates/archive-macros.pt (+1/-1)
lib/lp/soyuz/templates/archive-packages.pt (+1/-1)
lib/lp/soyuz/templates/archive-subscribers.pt (+1/-1)
lib/lp/translations/browser/language.py (+8/-0)
lib/lp/translations/stories/distroseries/xx-distroseries-templates.txt (+56/-13)
lib/lp/translations/stories/productseries/xx-productseries-templates.txt (+27/-18)
lib/lp/translations/stories/standalone/xx-language.txt (+68/-7)
lib/lp/translations/templates/language-index.pt (+9/-4)
lib/lp/translations/templates/object-templates.pt (+20/-3)
lib/lp/translations/templates/pofile-export.pt (+1/-1)
lib/lp/translations/templates/pofile-translate.pt (+1/-1)
lib/lp/translations/templates/translation-import-queue-macros.pt (+1/-1)
lib/lp/translations/templates/translationimportqueueentry-index.pt (+1/-1)
lib/lp/translations/templates/translationmessage-translate.pt (+1/-1)
To merge this branch: bzr merge lp:~edwin-grubbs/launchpad/bug-230801-renewing-membership
Reviewer Review Type Date Requested Status
Michael Nelson (community) code Approve
Review via email: mp+15610@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Edwin Grubbs (edwin-grubbs) wrote :

Summary
-------

This branch fixes an oops caused by the user double clicking
on the /~$user/+expiringmembership/$team form's submit button.

The view class now checks if the membership can be renewed
before calling the method in the model that raises the exception.

The view still displays the message saying that the membership has been
renewed, because it is very unlikely that the user would be able to try to
renew an unrenewable membership without double clicking, since the form will
not show up on the page if the membership will not be expiring within seven
days.

Tests
-----

./bin/test -vvt 'xx-member-renewed-membership.txt|teammembership-email-notification.txt'

Demo and Q/A
------------

* Log in as <email address hidden>
* Open http://launchpad.dev/~guadamen/+members
  * Edit Foo Bar's membership.
  * Set the expiration within 7 days in the future.
    (Surprisingly, you can set the team's admin's membership to expire, and
     before this fix the admin would get the same exception when double
     clicking to renew the membership.)
* Open http://launchpad.dev/~name16/+expiringmembership/guadamen
  * Double click on the Renew button.
  * Instead of an OOPS, you should the person index page with a notice
    that the membership has been renewed to some time next year.

Revision history for this message
Michael Nelson (michael.nelson) wrote :

> Demo and Q/A
> ------------
>
> * Log in as <email address hidden>
> * Open http://launchpad.dev/~guadamen/+members
> * Edit Foo Bar's membership.
> * Set the expiration within 7 days in the future.
> (Surprisingly, you can set the team's admin's membership to expire, and
> before this fix the admin would get the same exception when double
> clicking to renew the membership.)
> * Open http://launchpad.dev/~name16/+expiringmembership/guadamen
> * Double click on the Renew button.

In addition, I had to first set the "invite them to renew their own membership" option on the group before I could renew.

> * Instead of an OOPS, you should the person index page with a notice
> that the membership has been renewed to some time next year.

Nice - I couldn't actually reproduce the problem with Chromium (double-click protection? ;-) , but with Firefox I could.

Not worth worrying about at all, but if you click really really quickly (or perhaps it has to do with the number of clicks and overloading the dev server) you can get more than one notification.

Great! Thanks Edwin.

<EdwinGrubbs> noodles775, al-maisan: can one of you review my tiny branch? https://code.edge.launchpad.net/~edwin-grubbs/launchpad/bug-230801-renewing-membership/+merge/15610
* beuno is now known as beuno-lunch
<noodles775> EdwinGrubbs: sure!
* noodles775 is loving the 4 or 5 liners :)
<noodles775> EdwinGrubbs: is this targeted to db-devel for a reason? (or are you planning on landing it on devel?)
<EdwinGrubbs> noodles775: I'm planning on landing it on devel after pqm opens, and I wanted to prevent merge conflicts later, since devel still didn't have some of the revisions when I started the branch.
* stub has quit ("Leaving.")
<noodles775> k

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/archiveuploader/nascentuploadfile.py'
2--- lib/lp/archiveuploader/nascentuploadfile.py 2009-11-10 13:09:26 +0000
3+++ lib/lp/archiveuploader/nascentuploadfile.py 2009-12-07 23:15:25 +0000
4@@ -690,7 +690,7 @@
5 tar_checker.ancient_files[first_file])
6 yield UploadError(
7 "%s: has %s file(s) with a time stamp too "
8- "far into the future (e.g. %s [%s])."
9+ "far in the past (e.g. %s [%s])."
10 % (self.filename, len(ancient_files), first_file,
11 timestamp))
12 return
13
14=== modified file 'lib/lp/archiveuploader/tests/nascentuploadfile.txt'
15--- lib/lp/archiveuploader/tests/nascentuploadfile.txt 2009-07-08 08:38:05 +0000
16+++ lib/lp/archiveuploader/tests/nascentuploadfile.txt 2009-12-07 23:15:25 +0000
17@@ -539,6 +539,77 @@
18
19 == DebBinaryUploadFile ==
20
21+DebBinaryUploadFile models a binary .deb file.
22+
23+ >>> from lp.archiveuploader.nascentuploadfile import (
24+ ... DebBinaryUploadFile)
25+ >>> ed_deb_path = datadir('ed_0.2-20_i386.deb')
26+ >>> ed_binary_deb = DebBinaryUploadFile(ed_deb_path,
27+ ... 'e31eeb0b6b3b87e1ea79378df864ffff',
28+ ... 15, 'main/editors', 'important', 'foo', '1.2',
29+ ... ed_mixed_changes, modified_insecure_policy,
30+ ... mock_logger_quiet)
31+
32+Like the other files it can be verified:
33+
34+ >>> list(ed_binary_deb.verify())
35+ []
36+
37+Verification checks that the specified section matches the section in the
38+changes file:
39+
40+ >>> ed_binary_deb = DebBinaryUploadFile(ed_deb_path,
41+ ... 'e31eeb0b6b3b87e1ea79378df864ffff',
42+ ... 15, 'main/net', 'important', 'foo', '1.2',
43+ ... ed_mixed_changes, modified_insecure_policy,
44+ ... mock_logger_quiet)
45+ >>> list(ed_binary_deb.verify())
46+ [UploadError('ed_0.2-20_i386.deb control file lists section as
47+ main/editors but changes file has main/net.',)]
48+
49+It also checks the priority against the changes file:
50+
51+ >>> ed_binary_deb = DebBinaryUploadFile(ed_deb_path,
52+ ... 'e31eeb0b6b3b87e1ea79378df864ffff',
53+ ... 15, 'main/editors', 'extra', 'foo', '1.2',
54+ ... ed_mixed_changes, modified_insecure_policy,
55+ ... mock_logger_quiet)
56+ >>> list(ed_binary_deb.verify())
57+ [UploadError('ed_0.2-20_i386.deb control file lists priority as important
58+ but changes file has extra.',)]
59+
60+The timestamp of the files in the .deb are tested against the policy for being
61+too new:
62+
63+ >>> old_only_policy = getPolicy(
64+ ... name='insecure', distro='ubuntu', distroseries='hoary')
65+ >>> old_only_policy.can_upload_binaries = True
66+ >>> old_only_policy.future_time_grace = -5 * 365 * 24 * 60 * 60
67+
68+ >>> ed_binary_deb = DebBinaryUploadFile(ed_deb_path,
69+ ... 'e31eeb0b6b3b87e1ea79378df864ffff',
70+ ... 15, 'main/editors', 'important', 'foo', '1.2',
71+ ... ed_mixed_changes, old_only_policy,
72+ ... mock_logger_quiet)
73+ >>> list(ed_binary_deb.verifyDebTimestamp())
74+ [UploadError('ed_0.2-20_i386.deb: has 26 file(s) with a time stamp too
75+ far into the future (e.g. control [Thu Jan 3 19:29:01 2008]).',)]
76+
77+... as well as for being too old:
78+
79+ >>> new_only_policy = getPolicy(
80+ ... name='insecure', distro='ubuntu', distroseries='hoary')
81+ >>> new_only_policy.can_upload_binaries = True
82+ >>> new_only_policy.earliest_year = 2010
83+ >>> ed_binary_deb = DebBinaryUploadFile(ed_deb_path,
84+ ... 'e31eeb0b6b3b87e1ea79378df864ffff',
85+ ... 15, 'main/editors', 'important', 'foo', '1.2',
86+ ... ed_mixed_changes, new_only_policy,
87+ ... mock_logger_quiet)
88+ >>> list(ed_binary_deb.verify())
89+ [UploadError('ed_0.2-20_i386.deb: has 26 file(s) with a time stamp too
90+ far in the past (e.g. control [Thu Jan 3 19:29:01 2008]).',)]
91+
92
93 == UDebBinaryUploadFile ==
94
95
96=== modified file 'lib/lp/bugs/templates/bug-portlet-subscribers.pt'
97--- lib/lp/bugs/templates/bug-portlet-subscribers.pt 2009-11-26 03:13:32 +0000
98+++ lib/lp/bugs/templates/bug-portlet-subscribers.pt 2009-12-07 23:15:25 +0000
99@@ -25,7 +25,7 @@
100 <img src="/@@/spinner" />
101 </div>
102 <script type="text/javascript">
103- YUI().use('io-base', 'node', 'bugs.bugtask_index', function(Y) {
104+ LPS.use('io-base', 'node', 'bugs.bugtask_index', function(Y) {
105 // Must be done inline here to ensure the load event fires.
106 // This is a work around for a YUI3 issue with event handling.
107 var subscription_link = Y.one('.menu-link-subscription');
108
109=== modified file 'lib/lp/bugs/templates/bugtarget-filebug-submit-bug.pt'
110--- lib/lp/bugs/templates/bugtarget-filebug-submit-bug.pt 2009-10-01 12:09:37 +0000
111+++ lib/lp/bugs/templates/bugtarget-filebug-submit-bug.pt 2009-12-07 23:15:25 +0000
112@@ -14,7 +14,7 @@
113 tal:define="lp_js string:${icingroot}/build"
114 tal:attributes="src string:${lp_js}/bugs/filebug-dupefinder.js"></script>
115 <script type="text/javascript">
116- YUI().use('base', 'node', 'oop', 'event', 'bugs.dupe_finder', function(Y) {
117+ LPS.use('base', 'node', 'oop', 'event', 'bugs.dupe_finder', function(Y) {
118 Y.bugs.setup_dupe_finder();
119 });
120 </script>
121
122=== modified file 'lib/lp/bugs/templates/bugtarget-portlet-bugfilters.pt'
123--- lib/lp/bugs/templates/bugtarget-portlet-bugfilters.pt 2009-11-04 13:56:17 +0000
124+++ lib/lp/bugs/templates/bugtarget-portlet-bugfilters.pt 2009-12-07 23:15:25 +0000
125@@ -12,7 +12,7 @@
126 <img src="/@@/spinner" />
127 </div>
128 <script type="text/javascript">
129- YUI().use('io-base', 'node', function(Y) {
130+ LPS.use('io-base', 'node', function(Y) {
131 Y.on('domready', function() {
132 var portlet = Y.one('#portlet-bugfilters');
133 Y.one('#bugfilters-portlet-spinner').setStyle('display', 'block');
134
135=== modified file 'lib/lp/bugs/templates/bugtarget-portlet-bugtags.pt'
136--- lib/lp/bugs/templates/bugtarget-portlet-bugtags.pt 2009-11-04 13:56:17 +0000
137+++ lib/lp/bugs/templates/bugtarget-portlet-bugtags.pt 2009-12-07 23:15:25 +0000
138@@ -9,7 +9,7 @@
139 <a id="tags-content-link"
140 tal:attributes="href context/fmt:url/+bugtarget-portlet-tags-content"></a>
141 <script type="text/javascript">
142- YUI().use('io-base', 'node', function(Y) {
143+ LPS.use('io-base', 'node', function(Y) {
144 Y.on('domready', function() {
145 Y.one('#tags-portlet-spinner').setStyle('display', 'block');
146
147
148=== modified file 'lib/lp/bugs/templates/bugtask-index.pt'
149--- lib/lp/bugs/templates/bugtask-index.pt 2009-11-30 17:57:15 +0000
150+++ lib/lp/bugs/templates/bugtask-index.pt 2009-12-07 23:15:25 +0000
151@@ -37,7 +37,7 @@
152 </script>
153 </tal:devmode>
154 <script type="text/javascript">
155- YUI().use('base', 'node', 'oop', 'event', 'bugs.bugtask_index',
156+ LPS.use('base', 'node', 'oop', 'event', 'bugs.bugtask_index',
157 'code.branchmergeproposal.popupdiff', function(Y) {
158 Y.bugs.setup_bugtask_index();
159 Y.on('load', function(e) {
160@@ -155,7 +155,7 @@
161 <img src="/@@/spinner" id="tags-edit-spinner" style="display: none" />
162 <a href="+edit" title="Edit tags" id="edit-tags-trigger" class="sprite edit"></a>
163 <script type="text/javascript">
164- YUI().use('event', 'node', 'bugs.bug_tags_entry', function(Y) {
165+ LPS.use('event', 'node', 'bugs.bug_tags_entry', function(Y) {
166 // XXX intellectronica 2009-04-16 bug #362309:
167 // The load event fires very late on bug pages that take a
168 // long time to render, but we prefer to use it since the
169@@ -295,7 +295,7 @@
170 button.style.display = 'none';
171 </script>
172 <script type="text/javascript">
173- YUI().use('lp.comment', function(Y) {
174+ LPS.use('lp.comment', function(Y) {
175 var comment = new Y.lp.Comment();
176 comment.render();
177 });
178
179=== modified file 'lib/lp/bugs/templates/bugtask-tasks-and-nominations-table-row.pt'
180--- lib/lp/bugs/templates/bugtask-tasks-and-nominations-table-row.pt 2009-11-03 15:32:31 +0000
181+++ lib/lp/bugs/templates/bugtask-tasks-and-nominations-table-row.pt 2009-12-07 23:15:25 +0000
182@@ -185,7 +185,7 @@
183 class="bugtasks-table-row-init-script"
184 tal:condition="not:view/many_bugtasks"
185 tal:content="string:
186- YUI().use('event', 'bugs.bugtask_index', function(Y) {
187+ LPS.use('event', 'bugs.bugtask_index', function(Y) {
188 Y.on('load',
189 function(e) {
190 Y.bugs.setup_bugtask_row(${view/js_config});
191
192=== modified file 'lib/lp/bugs/templates/bugtasks-and-nominations-table.pt'
193--- lib/lp/bugs/templates/bugtasks-and-nominations-table.pt 2009-09-02 22:13:06 +0000
194+++ lib/lp/bugs/templates/bugtasks-and-nominations-table.pt 2009-12-07 23:15:25 +0000
195@@ -88,7 +88,7 @@
196 </span>
197
198 <script type="text/javascript" tal:content="string:
199- YUI().use('event', 'bugs.bugtask_index', function(Y) {
200+ LPS.use('event', 'bugs.bugtask_index', function(Y) {
201 Y.on('load', function(e) {
202 Y.bugs.setup_me_too(${view/current_user_affected_js_status});
203 }, window);
204
205=== modified file 'lib/lp/bugs/templates/official-bug-target-manage-tags.pt'
206--- lib/lp/bugs/templates/official-bug-target-manage-tags.pt 2009-09-04 17:03:00 +0000
207+++ lib/lp/bugs/templates/official-bug-target-manage-tags.pt 2009-12-07 23:15:25 +0000
208@@ -31,7 +31,7 @@
209 </script>
210 <script tal:replace="structure view/tags_js_data" />
211 <script type="text/javascript">
212- YUI().use('event', 'bugs.official_bug_tag_management', function(Y) {
213+ LPS.use('event', 'bugs.official_bug_tag_management', function(Y) {
214 Y.on('domready', function(e) {
215 Y.bugs.setup_official_bug_tag_management();
216 });
217
218=== modified file 'lib/lp/code/templates/branch-import-details.pt'
219--- lib/lp/code/templates/branch-import-details.pt 2009-11-04 13:56:17 +0000
220+++ lib/lp/code/templates/branch-import-details.pt 2009-12-07 23:15:25 +0000
221@@ -32,7 +32,7 @@
222 Try again
223 </a>
224 <script type="text/javascript">
225- YUI().use('event', 'node', function(Y) {
226+ LPS.use('event', 'node', function(Y) {
227 Y.on("domready", function () { Y.one('#tryagainlink').setStyle('display', 'inline') });
228 });
229 </script>
230
231=== modified file 'lib/lp/code/templates/branch-index.pt'
232--- lib/lp/code/templates/branch-index.pt 2009-11-17 05:07:41 +0000
233+++ lib/lp/code/templates/branch-index.pt 2009-12-07 23:15:25 +0000
234@@ -47,7 +47,7 @@
235 </tal:devmode>
236 <script type="text/javascript"
237 tal:content="string:
238- YUI().use('node', 'event', 'widget', 'plugin', 'overlay',
239+ LPS.use('node', 'event', 'widget', 'plugin', 'overlay',
240 'lazr.choiceedit', 'code.branchstatus',
241 'code.branchmergeproposal.popupdiff',
242 function(Y) {
243
244=== modified file 'lib/lp/code/templates/branch-listing.pt'
245--- lib/lp/code/templates/branch-listing.pt 2009-11-04 13:56:17 +0000
246+++ lib/lp/code/templates/branch-listing.pt 2009-12-07 23:15:25 +0000
247@@ -41,7 +41,7 @@
248 }
249 registerLaunchpadFunction(hookUpFilterSubmission);
250
251-YUI().use('io-base', 'node', 'json-parse', function(Y) {
252+LPS.use('io-base', 'node', 'json-parse', function(Y) {
253
254 function doUpdate(transaction_id, response, args) {
255 json_values = Y.JSON.parse(response.responseText);
256
257=== modified file 'lib/lp/code/templates/branch-portlet-subscribers.pt'
258--- lib/lp/code/templates/branch-portlet-subscribers.pt 2009-11-04 13:56:17 +0000
259+++ lib/lp/code/templates/branch-portlet-subscribers.pt 2009-12-07 23:15:25 +0000
260@@ -41,7 +41,7 @@
261 string:&lt;script id='milestone-script' type='text/javascript'&gt;" />
262 <!--
263
264- YUI().use('io-base', 'node', 'code.branchsubscription', function(Y) {
265+ LPS.use('io-base', 'node', 'code.branchsubscription', function(Y) {
266
267 if(Y.UA.ie) {
268 Y.one('#subscriber-list').set('innerHTML',
269
270=== modified file 'lib/lp/code/templates/branch-related-bugs-specs.pt'
271--- lib/lp/code/templates/branch-related-bugs-specs.pt 2009-09-08 21:42:45 +0000
272+++ lib/lp/code/templates/branch-related-bugs-specs.pt 2009-12-07 23:15:25 +0000
273@@ -42,7 +42,7 @@
274 string:&lt;script id='branchlink-script' type='text/javascript'&gt;" />
275 <!--
276
277- YUI().use('io-base', 'code.branchlinks', function(Y) {
278+ LPS.use('io-base', 'code.branchlinks', function(Y) {
279
280 if(Y.UA.ie) {
281 return;
282
283=== modified file 'lib/lp/code/templates/branchmergeproposal-generic-listing.pt'
284--- lib/lp/code/templates/branchmergeproposal-generic-listing.pt 2009-11-04 13:56:17 +0000
285+++ lib/lp/code/templates/branchmergeproposal-generic-listing.pt 2009-12-07 23:15:25 +0000
286@@ -24,7 +24,7 @@
287 </form>
288 <script type="text/javascript">
289
290-YUI().use('node', function(Y) {
291+LPS.use('node', function(Y) {
292
293 function submit_filter() {
294 Y.one('#filter_form').submit();
295
296=== modified file 'lib/lp/registry/browser/person.py'
297--- lib/lp/registry/browser/person.py 2009-11-21 14:45:26 +0000
298+++ lib/lp/registry/browser/person.py 2009-12-07 23:15:25 +0000
299@@ -548,7 +548,10 @@
300 @action(_("Renew"), name="renew")
301 def renew_action(self, action, data):
302 member = self.context.person
303- member.renewTeamMembership(self.context.team)
304+ # This if-statement prevents an exception if the user
305+ # double clicks on the submit button.
306+ if self.context.canBeRenewedByMember():
307+ member.renewTeamMembership(self.context.team)
308 self.request.response.addInfoNotification(
309 _("Membership renewed until ${date}.", mapping=dict(
310 date=self.context.dateexpires.strftime('%Y-%m-%d'))))
311
312=== modified file 'lib/lp/registry/browser/tests/productrelease-views.txt'
313--- lib/lp/registry/browser/tests/productrelease-views.txt 2009-09-11 16:00:24 +0000
314+++ lib/lp/registry/browser/tests/productrelease-views.txt 2009-12-07 23:15:25 +0000
315@@ -130,7 +130,7 @@
316 >>> script = find_tag_by_id(view.render(), 'milestone-script')
317 >>> print script
318 <script id="milestone-script" type="text/javascript">
319- YUI().use(... 'lp.milestoneoverlay'...
320+ LPS.use(... 'lp.milestoneoverlay'...
321 var milestone_form_uri = '.../app/simple/+addmilestone/++form++';
322 var series_uri = '/app/simple';
323 ...
324
325=== modified file 'lib/lp/registry/templates/object-timeline-graph.pt'
326--- lib/lp/registry/templates/object-timeline-graph.pt 2009-11-24 09:30:01 +0000
327+++ lib/lp/registry/templates/object-timeline-graph.pt 2009-12-07 23:15:25 +0000
328@@ -32,7 +32,7 @@
329 include_inactive = false;
330 }
331
332- YUI().use('registry.timeline', 'node', function(Y) {
333+ LPS.use('registry.timeline', 'node', function(Y) {
334 Y.on('domready', function(e) {
335 if (Y.UA.ie) {
336 return;
337
338=== modified file 'lib/lp/registry/templates/person-macros.pt'
339--- lib/lp/registry/templates/person-macros.pt 2009-11-04 13:56:17 +0000
340+++ lib/lp/registry/templates/person-macros.pt 2009-12-07 23:15:25 +0000
341@@ -190,7 +190,7 @@
342 condition="private_prefix">
343 <script type="text/javascript"
344 tal:content="string:
345- YUI().use('node', 'event', function(Y) {
346+ LPS.use('node', 'event', function(Y) {
347 // Prepend/remove 'private-' from team name based on visibility
348 // setting. User can choose to edit it back out, if they wish.
349 function visibility_on_change(e) {
350
351=== modified file 'lib/lp/registry/templates/product-new.pt'
352--- lib/lp/registry/templates/product-new.pt 2009-11-04 13:56:17 +0000
353+++ lib/lp/registry/templates/product-new.pt 2009-12-07 23:15:25 +0000
354@@ -14,7 +14,7 @@
355 * details widgets until the user states that the project they are
356 * registering is not a duplicate.
357 */
358-YUI().use('node', 'lazr.effects', function(Y) {
359+LPS.use('node', 'lazr.effects', function(Y) {
360 Y.on('domready', function() {
361 /* These two regexps serve slightly different purposes. The first
362 * finds the leftmost run of valid url characters for the autofill
363
364=== modified file 'lib/lp/registry/templates/productrelease-add-from-series.pt'
365--- lib/lp/registry/templates/productrelease-add-from-series.pt 2009-11-04 13:56:17 +0000
366+++ lib/lp/registry/templates/productrelease-add-from-series.pt 2009-12-07 23:15:25 +0000
367@@ -14,7 +14,7 @@
368 <tal:script
369 replace="structure
370 string:&lt;script id='milestone-script' type='text/javascript'&gt;" />
371- YUI().use('node', 'lp.milestoneoverlay', function (Y) {
372+ LPS.use('node', 'lp.milestoneoverlay', function (Y) {
373
374 // This is a value for the SELECT OPTION which is passed with
375 // the SELECT's "change" event. It includes some symbols that are not
376
377=== modified file 'lib/lp/registry/templates/teammembership-index.pt'
378--- lib/lp/registry/templates/teammembership-index.pt 2009-11-04 13:56:17 +0000
379+++ lib/lp/registry/templates/teammembership-index.pt 2009-12-07 23:15:25 +0000
380@@ -20,7 +20,7 @@
381 use-macro="context/@@launchpad_widget_macros/yui2calendar-dependencies" />
382
383 <script type="text/javascript">
384- YUI().use('node', 'lp.calendar', function(Y) {
385+ LPS.use('node', 'lp.calendar', function(Y) {
386 // Ensure that when the picker is used the radio button switches
387 // from 'Never' to 'On' and the expiry field is enabled.
388 Y.on("available", function(e) {
389
390=== modified file 'lib/lp/registry/templates/timeline-macros.pt'
391--- lib/lp/registry/templates/timeline-macros.pt 2009-11-04 13:56:17 +0000
392+++ lib/lp/registry/templates/timeline-macros.pt 2009-12-07 23:15:25 +0000
393@@ -35,7 +35,7 @@
394 if (auto_resize == 'true') {
395 timeline_url += 'resize_frame=timeline-iframe&';
396 }
397- YUI().use('node', function(Y) {
398+ LPS.use('node', function(Y) {
399 if (Y.UA.ie) {
400 return;
401 }
402
403=== modified file 'lib/lp/soyuz/templates/archive-edit-dependencies.pt'
404--- lib/lp/soyuz/templates/archive-edit-dependencies.pt 2009-11-12 17:26:17 +0000
405+++ lib/lp/soyuz/templates/archive-edit-dependencies.pt 2009-12-07 23:15:25 +0000
406@@ -62,7 +62,7 @@
407 </div> <!-- launchpad_form -->
408
409 <script type="text/javascript">
410- YUI().use("node", function(Y) {
411+ LPS.use("node", function(Y) {
412
413 // Highlight (setting bold font-weight) the label for the
414 // selected option in a given NodesList. Assumes the input is
415
416=== modified file 'lib/lp/soyuz/templates/archive-macros.pt'
417--- lib/lp/soyuz/templates/archive-macros.pt 2009-11-04 19:59:16 +0000
418+++ lib/lp/soyuz/templates/archive-macros.pt 2009-12-07 23:15:25 +0000
419@@ -10,7 +10,7 @@
420 </tal:comment>
421
422 <script type="text/javascript">
423-YUI().use('node', 'io-base', 'lazr.anim', 'soyuz-base', function(Y) {
424+LPS.use('node', 'io-base', 'lazr.anim', 'soyuz-base', function(Y) {
425
426
427 /*
428
429=== modified file 'lib/lp/soyuz/templates/archive-packages.pt'
430--- lib/lp/soyuz/templates/archive-packages.pt 2009-11-04 13:56:17 +0000
431+++ lib/lp/soyuz/templates/archive-packages.pt 2009-12-07 23:15:25 +0000
432@@ -23,7 +23,7 @@
433 </tal:devmode>
434 <script type="text/javascript" id="repository-size-update"
435 tal:condition="view/archive_url">
436-YUI().use('io-base', 'lazr.anim', 'node', 'soyuz-base',
437+LPS.use('io-base', 'lazr.anim', 'node', 'soyuz-base',
438 'soyuz.update_archive_build_statuses', function(Y) {
439
440
441
442=== modified file 'lib/lp/soyuz/templates/archive-subscribers.pt'
443--- lib/lp/soyuz/templates/archive-subscribers.pt 2009-09-29 07:21:40 +0000
444+++ lib/lp/soyuz/templates/archive-subscribers.pt 2009-12-07 23:15:25 +0000
445@@ -98,7 +98,7 @@
446 </form>
447 </div><!-- class="portlet" -->
448 <script type="text/javascript" id="setup-archivesubscribers-index">
449- YUI().use('soyuz.archivesubscribers_index', function(Y) {
450+ LPS.use('soyuz.archivesubscribers_index', function(Y) {
451 Y.soyuz.setup_archivesubscribers_index();
452 });
453 </script>
454
455=== modified file 'lib/lp/translations/browser/language.py'
456--- lib/lp/translations/browser/language.py 2009-10-31 11:06:44 +0000
457+++ lib/lp/translations/browser/language.py 2009-12-07 23:15:25 +0000
458@@ -29,6 +29,7 @@
459 enabled_with_permission, GetitemNavigation, LaunchpadEditFormView,
460 LaunchpadFormView, LaunchpadView, Link, NavigationMenu)
461 from lp.translations.utilities.pluralforms import make_friendly_plural_forms
462+from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
463
464 from canonical.widgets import LabeledMultiCheckBoxWidget
465
466@@ -202,6 +203,13 @@
467
468 return pluralforms_list
469
470+ @property
471+ def add_question_url(self):
472+ rosetta = getUtility(ILaunchpadCelebrities).lp_translations
473+ return canonical_url(
474+ rosetta,
475+ view_name='+addquestion',
476+ rootsite='answers')
477
478 class LanguageAdminView(LaunchpadEditFormView):
479 """Handle an admin form submission."""
480
481=== modified file 'lib/lp/translations/stories/distroseries/xx-distroseries-templates.txt'
482--- lib/lp/translations/stories/distroseries/xx-distroseries-templates.txt 2009-10-30 10:09:17 +0000
483+++ lib/lp/translations/stories/distroseries/xx-distroseries-templates.txt 2009-12-07 23:15:25 +0000
484@@ -1,11 +1,15 @@
485-= Templates view for DistroSeries =
486+
487+
488+Templates view for DistroSeries
489+===============================
490
491 The +templates view for DistroSeries gives an overview of the translation
492 templates in this series and provides easy access to the various subpages of
493 each template.
494
495
496-== Getting there ==
497+Getting there
498+-------------
499
500 To get to the listing of all templates, one needs to use the link
501 from the distribution series translations page.
502@@ -16,7 +20,45 @@
503 >>> print user_browser.url
504 http://translations.launchpad.dev/ubuntu/hoary/+templates
505
506-== The templates table ==
507+The templates table
508+-------------------
509+
510+Full template listing for a distribution series is reached by following
511+a link from the distribution series translations page.
512+
513+ >>> anon_browser.open(
514+ ... 'http://translations.launchpad.dev/ubuntu/hoary')
515+ >>> anon_browser.getLink('full list of templates').click()
516+
517+Full listing of templates shows source package name, template name and
518+the date of last update for this distribution series.
519+
520+ >>> table = find_tag_by_id(anon_browser.contents, 'templates_table')
521+ >>> print extract_text(table)
522+ Source package Template name Last update
523+ evolution disabled-template 2007-01-05
524+ evolution evolution-2.2 2005-05-06
525+ evolution man 2006-08-14
526+ mozilla pkgconf-mozilla 2005-05-06
527+ pmount man 2006-08-14
528+ pmount pmount 2005-05-06
529+
530+
531+Logged-in users will see a link from distro series
532+ >>> user_browser.open(
533+ ... 'http://translations.launchpad.dev/ubuntu/hoary')
534+ >>> user_browser.getLink('full list of templates').click()
535+
536+Logged-in users can also choose to download all translations for each
537+of the templates.
538+
539+ >>> table = find_tag_by_id(user_browser.contents, 'templates_table')
540+ >>> print extract_text(table)
541+ Source package Template name Last update Actions
542+ evolution disabled-template 2007-01-05 Download
543+ ...
544+ mozilla pkgconf-mozilla 2005-05-06 Download
545+ ...
546
547 Administrator can see all editing options.
548
549@@ -28,16 +70,17 @@
550
551 >>> table = find_tag_by_id(admin_browser.contents, 'templates_table')
552 >>> print extract_text(table)
553- Source package Template name Actions
554- evolution disabled-template Edit Upload Download Administer
555- evolution evolution-2.2 Edit Upload Download Administer
556- evolution man Edit Upload Download Administer
557- mozilla pkgconf-mozilla Edit Upload Download Administer
558- pmount man Edit Upload Download Administer
559- pmount pmount Edit Upload Download Administer
560-
561-
562-== Links to the templates ==
563+ Source package Template name Last update Actions
564+ evolution disabled-template 2007-01-05 Edit Upload Download Administer
565+ evolution evolution-2.2 2005-05-06 Edit Upload Download Administer
566+ evolution man 2006-08-14 Edit Upload Download Administer
567+ mozilla pkgconf-mozilla 2005-05-06 Edit Upload Download Administer
568+ pmount man 2006-08-14 Edit Upload Download Administer
569+ pmount pmount 2005-05-06 Edit Upload Download Administer
570+
571+
572+Links to the templates
573+----------------------
574
575 Clicking on a template name will take the user to that template's overview
576 page.
577
578=== modified file 'lib/lp/translations/stories/productseries/xx-productseries-templates.txt'
579--- lib/lp/translations/stories/productseries/xx-productseries-templates.txt 2009-10-30 10:09:17 +0000
580+++ lib/lp/translations/stories/productseries/xx-productseries-templates.txt 2009-12-07 23:15:25 +0000
581@@ -1,13 +1,18 @@
582-= Templates view for ProductSeries =
583+
584+
585+Templates view for ProductSeries
586+================================
587
588 The +templates view for ProductSeries gives an overview of the translation
589 templates in this series and provides easy access to the various subpages of
590 each template.
591
592-== Preparation ==
593-
594-To test the ordering of templates in the listing, we need another template
595-that is new but must appear at the top of the list.
596+
597+Preparation
598+-----------
599+
600+To test the ordering of templates in the listing, we need another
601+template that is new but must appear at the top of the list.
602
603 >>> login('foo.bar@canonical.com')
604 >>> from zope.component import getUtility
605@@ -18,7 +23,9 @@
606 ... name='at-the-top')
607 >>> logout()
608
609-== Getting there ==
610+
611+Getting there
612+-------------
613
614 To get to the listing of all templates, one needs to use the link
615 from the product series translations page.
616@@ -30,16 +37,17 @@
617 http://translations.launchpad.dev/evolution/trunk/+templates
618
619
620-== The templates table ==
621+The templates table
622+-------------------
623
624 The page shows a table of all templates and links to their subpages.
625
626 >>> table = find_tag_by_id(user_browser.contents, 'templates_table')
627 >>> print extract_text(table)
628- Template name Actions
629- at-the-top Download
630- evolution-2.2 Download
631- evolution-2.2-test Download
632+ Template name Last update Actions
633+ at-the-top ... Download
634+ evolution-2.2 2005-08-25 Download
635+ evolution-2.2-test 2006-12-13 Download
636
637 If an administrator views this page, links to the templates admin page are
638 shown, too.
639@@ -48,13 +56,14 @@
640 ... 'http://translations.launchpad.dev/evolution/trunk/+templates')
641 >>> table = find_tag_by_id(admin_browser.contents, 'templates_table')
642 >>> print extract_text(table)
643- Template name Actions
644- at-the-top Edit Upload Download Administer
645- evolution-2.2 Edit Upload Download Administer
646- evolution-2.2-test Edit Upload Download Administer
647-
648-
649-== Links to the templates ==
650+ Template name Last update Actions
651+ at-the-top ... Edit Upload Download Administer
652+ evolution-2.2 2005-08-25 Edit Upload Download Administer
653+ evolution-2.2-test 2006-12-13 Edit Upload Download Administer
654+
655+
656+Links to the templates
657+----------------------
658
659 Clicking on a template name will take the user to that template's overview
660 page.
661
662=== modified file 'lib/lp/translations/stories/standalone/xx-language.txt'
663--- lib/lp/translations/stories/standalone/xx-language.txt 2009-10-31 11:06:44 +0000
664+++ lib/lp/translations/stories/standalone/xx-language.txt 2009-12-07 23:15:25 +0000
665@@ -1,6 +1,15 @@
666+
667+
668+Languages view
669+==============
670+
671 Here is the tale of languages. We will see how to create, find and edit
672 them.
673
674+
675+Getting there
676+-------------
677+
678 Launchpad Translations has a main page.
679
680 >>> admin_browser.open('http://translations.launchpad.dev/')
681@@ -11,7 +20,12 @@
682 >>> print admin_browser.url
683 http://translations.launchpad.dev/+languages
684
685-Following the link, there is a form to add new languages.
686+
687+Adding new languages
688+--------------------
689+
690+Following the link from the translations main page, there is a form to
691+add new languages.
692
693 >>> admin_browser.getLink('Add new language').click()
694 >>> print admin_browser.url
695@@ -65,11 +79,16 @@
696 ...
697 LinkNotFoundError
698
699- >>> user_browser.open('http://translations.launchpad.dev/+languages/+add')
700+ >>> user_browser.open(
701+ ... 'http://translations.launchpad.dev/+languages/+add')
702 Traceback (most recent call last):
703 ...
704 Unauthorized:...
705
706+
707+Searching for a language
708+------------------------
709+
710 From the top languages page, anyone can find languages.
711
712 >>> browser.open('http://translations.launchpad.dev/+languages')
713@@ -82,7 +101,11 @@
714 >>> print browser.url
715 http://translations.launchpad.dev/+languages/+index?find=Spanish
716
717-And following one of the found languages, we can see a brief information
718+
719+Read language information
720+-------------------------
721+
722+Following one of the found languages, we can see a brief information
723 about the selected language.
724
725 >>> browser.getLink('Spanish').click()
726@@ -128,14 +151,50 @@
727 ...Uruguay...
728 ...Venezuela...
729
730- >>> topcontributors_portlet = find_portlet(browser.contents, 'Top contributors')
731+ >>> topcontributors_portlet = find_portlet(
732+ ... browser.contents, 'Top contributors')
733 >>> print topcontributors_portlet
734 <...
735 ...Carlos Perelló Marín...
736
737+Our test sample data does not know about plural forms of
738+Abkhazian and about countries where this language is spoken.
739+
740+We will see a note about missing plural forms and a link to Rosetta
741+add question page for informing Rosetta admin about the right plural
742+form.
743+
744+ >>> browser.open('http://translations.launchpad.dev/+languages/ab')
745+ >>> print extract_text(find_portlet(browser.contents, 'Plural forms'
746+ ... ).renderContents())
747+ Plural forms
748+ Unfortunately, Launchpad doesn't know the plural
749+ form information for this language...
750+
751+ >>> print browser.getLink(id='plural_question').url
752+ http://answers.launchpad.dev/rosetta/+addquestion
753+
754+We will see a note that Launchpad does not know in which countries
755+this language is spoken and a link to add question page for informing
756+Rosetta admin about the countries where this page is officially spoken.
757+
758+ >>> countries_portlet = find_portlet(browser.contents, 'Countries')
759+ >>> print countries_portlet
760+ <...
761+ Abkhazian is not registered as being spoken in any
762+ country...
763+
764+ >>> print browser.getLink(id='country_question').url
765+ http://answers.launchpad.dev/rosetta/+addquestion
766+
767+
768+Edit language information
769+-------------------------
770+
771 Finally, there is the edit form to change language basic information.
772
773- >>> user_browser.open('http://translations.launchpad.dev/+languages/es')
774+ >>> user_browser.open(
775+ ... 'http://translations.launchpad.dev/+languages/es')
776 >>> print user_browser.url
777 http://translations.launchpad.dev/+languages/es
778
779@@ -146,7 +205,8 @@
780 ...
781 LinkNotFoundError
782
783- >>> user_browser.open('http://translations.launchpad.dev/+languages/es/+admin')
784+ >>> user_browser.open(
785+ ... 'http://translations.launchpad.dev/+languages/es/+admin')
786 Traceback (most recent call last):
787 ...
788 Unauthorized:...
789@@ -155,7 +215,8 @@
790
791 >>> from canonical.launchpad.testing.pages import strip_label
792
793- >>> admin_browser.open('http://translations.launchpad.dev/+languages/es')
794+ >>> admin_browser.open(
795+ ... 'http://translations.launchpad.dev/+languages/es')
796 >>> print admin_browser.url
797 http://translations.launchpad.dev/+languages/es
798
799
800=== modified file 'lib/lp/translations/templates/language-index.pt'
801--- lib/lp/translations/templates/language-index.pt 2009-09-17 14:45:59 +0000
802+++ lib/lp/translations/templates/language-index.pt 2009-12-07 23:15:25 +0000
803@@ -43,8 +43,10 @@
804 <p class="helpwanted">
805 Unfortunately, Launchpad doesn't know the plural form
806 information for this language. If you know it, please open a
807- <a href="/rosetta/+addticket">ticket</a> with that information,
808- so we can add it to Launchpad.
809+ <a id='plural_question'
810+ tal:attributes="href view/add_question_url"
811+ >question</a>
812+ with that information, so we can add it to Launchpad.
813 </p>
814 </tal:has_not_pluralforms>
815 </div>
816@@ -124,8 +126,11 @@
817 </tal:language>
818 is not registered as being spoken in any country. If you know
819 about a country that officially speaks this language, please
820- open a <a href="/rosetta/+addticket">ticket</a> with that
821- information, so we can add it to Launchpad.
822+ open a
823+ <a id='country_question'
824+ tal:attributes="href view/add_question_url"
825+ >question</a>
826+ with that information, so we can add it to Launchpad.
827 </p>
828 </tal:has_not_countries>
829 </div>
830
831=== modified file 'lib/lp/translations/templates/object-templates.pt'
832--- lib/lp/translations/templates/object-templates.pt 2009-11-24 19:23:52 +0000
833+++ lib/lp/translations/templates/object-templates.pt 2009-12-07 23:15:25 +0000
834@@ -26,16 +26,16 @@
835 </style>
836 <style tal:condition="view/is_distroseries" type="text/css">
837 #templates_table {
838- width: 72em;
839+ width: 79em;
840 }
841 </style>
842 <style tal:condition="not:view/is_distroseries" type="text/css">
843 #templates_table {
844- width: 50em;
845+ width: 58em;
846 }
847 </style>
848 <script language="JavaScript" type="text/javascript">
849- YUI().use('node-base', 'event-delegate', function(Y) {
850+ LPS.use('node-base', 'event-delegate', function(Y) {
851 Y.on('domready', function(e) {
852 Y.all('#templates_table .template_links').addClass(
853 'inactive_links');
854@@ -75,6 +75,7 @@
855 <th tal:condition="view/is_distroseries"
856 class="sourcepackage_column">Source package</th>
857 <th class="template_column">Template name</th>
858+ <th class="lastupdate_column">Last update</th>
859 <th class="actions_column"
860 tal:condition="context/required:launchpad.AnyPerson">
861 Actions</th>
862@@ -88,6 +89,22 @@
863 </td>
864 <td class="template_column"><a tal:attributes="href template/fmt:url"
865 tal:content="template/name">Template name</a></td>
866+ <td class="lastupdate_column">
867+ <span class="sortkey"
868+ tal:condition="template/date_last_updated"
869+ tal:content="template/date_last_updated/fmt:datetime">
870+ time sort key
871+ </span>
872+ <span class="lastupdate_column"
873+ tal:condition="template/date_last_updated"
874+ tal:attributes="
875+ title template/date_last_updated/fmt:datetime"
876+ tal:content="
877+ template/date_last_updated/fmt:approximatedate"
878+ >
879+ 2009-09-23
880+ </span>
881+ </td>
882 <td class="actions_column"
883 tal:condition="context/required:launchpad.AnyPerson">
884 <div class="template_links">
885
886=== modified file 'lib/lp/translations/templates/pofile-export.pt'
887--- lib/lp/translations/templates/pofile-export.pt 2009-11-10 21:04:19 +0000
888+++ lib/lp/translations/templates/pofile-export.pt 2009-12-07 23:15:25 +0000
889@@ -13,7 +13,7 @@
890 }
891 </style>
892 <script type="text/javascript">
893- YUI().use('node', 'event', function(Y){
894+ LPS.use('node', 'event', function(Y){
895 Y.on('domready', function(){
896 // The pochanged option is only available for the PO format.
897 var formatlist = Y.one('#div_format select');
898
899=== modified file 'lib/lp/translations/templates/pofile-translate.pt'
900--- lib/lp/translations/templates/pofile-translate.pt 2009-11-04 19:59:16 +0000
901+++ lib/lp/translations/templates/pofile-translate.pt 2009-12-07 23:15:25 +0000
902@@ -20,7 +20,7 @@
903 <script type="text/javascript">
904 registerLaunchpadFunction(insertAllExpansionButtons);
905
906- YUI().use('node', 'cookie', 'anim', 'lp.pofile', function(Y) {
907+ LPS.use('node', 'cookie', 'anim', 'lp.pofile', function(Y) {
908
909 var hide_notification = function(node) {
910 var hide_anim = new Y.Anim({
911
912=== modified file 'lib/lp/translations/templates/translation-import-queue-macros.pt'
913--- lib/lp/translations/templates/translation-import-queue-macros.pt 2009-11-20 14:15:34 +0000
914+++ lib/lp/translations/templates/translation-import-queue-macros.pt 2009-12-07 23:15:25 +0000
915@@ -18,7 +18,7 @@
916 </script>
917
918 <script type="text/javascript">
919- YUI().use( 'translations', 'event', function(Y) {
920+ LPS.use( 'translations', 'event', function(Y) {
921 Y.on('domready', function(e) {
922 Y.translations.initialize_import_queue_page(Y);
923 });
924
925=== modified file 'lib/lp/translations/templates/translationimportqueueentry-index.pt'
926--- lib/lp/translations/templates/translationimportqueueentry-index.pt 2009-11-04 13:56:17 +0000
927+++ lib/lp/translations/templates/translationimportqueueentry-index.pt 2009-12-07 23:15:25 +0000
928@@ -14,7 +14,7 @@
929 }
930 </style>
931 <script type="text/javascript">
932- YUI().use('node', 'lazr.anim', function(Y) {
933+ LPS.use('node', 'lazr.anim', function(Y) {
934 var fields = {'POT':
935 ['field.name', 'field.translation_domain',
936 'field.languagepack'],
937
938=== modified file 'lib/lp/translations/templates/translationmessage-translate.pt'
939--- lib/lp/translations/templates/translationmessage-translate.pt 2009-09-17 07:28:30 +0000
940+++ lib/lp/translations/templates/translationmessage-translate.pt 2009-12-07 23:15:25 +0000
941@@ -18,7 +18,7 @@
942 tal:define="lp_js string:${icingroot}/build"
943 tal:attributes="src string:${lp_js}/translations/pofile.js"></script>
944 <script type="text/javascript">
945- YUI().use('node', 'lp.pofile', function(Y) {
946+ LPS.use('node', 'lp.pofile', function(Y) {
947 Y.on('domready', Y.lp.pofile.setupSuggestionDismissal);
948 });
949 </script>

Subscribers

People subscribed via source and target branches

to status/vote changes: