Code review comment for lp:~henninge/launchpad/devel-487137-custom-language-codes

Revision history for this message
Henning Eggers (henninge) wrote :

Here is the incremental diff in relation to Adi's branch. This MP is only
about these changes.

1=== modified file 'lib/canonical/launchpad/security.py'
2--- lib/canonical/launchpad/security.py 2010-12-21 15:13:17 +0000
3+++ lib/canonical/launchpad/security.py 2010-12-22 12:03:59 +0000
4@@ -185,7 +185,6 @@
5 from lp.soyuz.interfaces.sourcepackagerelease import ISourcePackageRelease
6 from lp.translations.interfaces.customlanguagecode import (
7 ICustomLanguageCode,
8- IHasCustomLanguageCodes,
9 )
10 from lp.translations.interfaces.languagepack import ILanguagePack
11 from lp.translations.interfaces.pofile import IPOFile
12@@ -744,6 +743,7 @@
13 # with launchpad.View so that this adapter is used. For now, though, it's
14 # going to be used only on the webservice (which explicitly checks for
15 # launchpad.View) so that we don't leak memberships of private teams.
16+
17 class ViewTeamMembership(AuthorizationBase):
18 permission = 'launchpad.View'
19 usedfor = ITeamMembership
20@@ -1728,27 +1728,23 @@
21 usedfor = ILanguage
22
23
24-class AdminCustomLanguageCodes(OnlyRosettaExpertsAndAdmins):
25- """Controls administration of custom language codes.
26-
27- Rosetta experts and Launchpad administrators can administer custom
28- language codes.
29- """
30-
31- permission = 'launchpad.TranslationsAdmin'
32- usedfor = IHasCustomLanguageCodes
33-
34-
35-class AdminCustomLanguageCode(OnlyRosettaExpertsAndAdmins):
36+class AdminCustomLanguageCode(AuthorizationBase):
37 """Controls administration for a custom language code.
38
39- Rosetta experts and Launchpad administrators can administer a custom
40- language code.
41+ Whoever can admin a product's or distribution's translations can also
42+ admin the custom language codes for it.
43 """
44-
45 permission = 'launchpad.TranslationsAdmin'
46 usedfor = ICustomLanguageCode
47
48+ def checkAuthenticated(self, user):
49+ if self.obj.product is not None:
50+ return AdminProductTranslations(
51+ self.obj.product).checkAuthenticated(user)
52+ else:
53+ return AdminDistributionTranslations(
54+ self.obj.distribution).checkAuthenticated(user)
55+
56
57 class AccessBranch(AuthorizationBase):
58 """Controls visibility of branches.
59@@ -1839,6 +1835,12 @@
60 self.obj.distribution).checkAuthenticated(user))
61
62
63+class AdminDistributionSourcePackageTranslations(
64+ AdminDistroSeriesTranslations):
65+ """DistributionSourcePackage objects link to a distribution, too."""
66+ usedfor = IDistributionSourcePackage
67+
68+
69 class AdminProductSeriesTranslations(AuthorizationBase):
70 permission = 'launchpad.TranslationsAdmin'
71 usedfor = IProductSeries
72
73=== modified file 'lib/lp/translations/browser/configure.zcml'
74--- lib/lp/translations/browser/configure.zcml 2010-12-21 15:13:17 +0000
75+++ lib/lp/translations/browser/configure.zcml 2010-12-22 12:01:59 +0000
76@@ -941,7 +941,7 @@
77 for="lp.registry.interfaces.distribution.IDistribution"
78 permission="zope.Public"
79 template="../templates/translations-portlet-not-using-launchpad-extra.pt"
80- layer="lp.translations.publisher.TranslationsLayer"/>
81+ layer="lp.translations.publisher.TranslationsLayer"/>
82 <browser:page
83 name="+portlet-configuration"
84 for="lp.registry.interfaces.distribution.IDistribution"
85
86=== modified file 'lib/lp/translations/browser/customlanguagecode.py'
87--- lib/lp/translations/browser/customlanguagecode.py 2010-12-21 15:13:17 +0000
88+++ lib/lp/translations/browser/customlanguagecode.py 2010-12-22 12:03:05 +0000
89@@ -46,6 +46,7 @@
90
91 class CustomLanguageCodeBreadcrumb(Breadcrumb):
92 """Breadcrumb for a `CustomLanguageCode`."""
93+
94 @property
95 def text(self):
96 return smartquote(
97@@ -164,6 +165,7 @@
98 class HasCustomLanguageCodesTraversalMixin:
99 """Navigate from an `IHasCustomLanguageCodes` to a `CustomLanguageCode`.
100 """
101+
102 @stepthrough('+customcode')
103 def traverseCustomCode(self, name):
104 """Traverse +customcode URLs."""
105
106=== modified file 'lib/lp/translations/stories/standalone/custom-language-codes.txt'
107--- lib/lp/translations/stories/standalone/custom-language-codes.txt 2010-12-21 15:13:17 +0000
108+++ lib/lp/translations/stories/standalone/custom-language-codes.txt 2010-12-22 12:04:22 +0000
109@@ -38,16 +38,18 @@
110 >>> owner_browser = setupBrowser("Basic o@example.com:test")
111 >>> rosetta_admin_browser = setupRosettaExpertBrowser()
112
113-A Launchpad administrator or Rosetta expert sees the link to the custom
114-language codes on a project's main translations page.
115+The project's owner sees the link to the custom language codes on a project's
116+main translations page.
117
118- >>> admin_browser.open(product_page)
119- >>> tag = find_custom_language_codes_link(admin_browser)
120+ >>> owner_browser.open(product_page)
121+ >>> tag = find_custom_language_codes_link(owner_browser)
122 >>> print extract_text(tag.renderContents())
123 If necessary, you may
124 define custom language codes
125 for this project.
126
127+Translation admins also have access to this link.
128+
129 >>> rosetta_admin_browser.open(product_page)
130 >>> tag = find_custom_language_codes_link(rosetta_admin_browser)
131 >>> print extract_text(tag.renderContents())
132@@ -57,39 +59,37 @@
133
134 The link goes to the custom language codes management page.
135
136- >>> rosetta_admin_browser.getLink("define custom language codes").click()
137- >>> custom_language_codes_page = rosetta_admin_browser.url
138-
139-Non-admins, even the project's owner, don't see this link. We do not
140-advertise this feature, since the proper solution is generally to use
141-the right language codes.
142-
143- >>> owner_browser.open(product_page)
144- >>> print find_custom_language_codes_link(owner_browser)
145+ >>> owner_browser.getLink("define custom language codes").click()
146+ >>> custom_language_codes_page = owner_browser.url
147+
148+Other users don't see this link.
149+
150+ >>> user_browser.open(product_page)
151+ >>> print find_custom_language_codes_link(user_browser)
152 None
153
154 Initially the page shows no custom language codes for the project.
155
156- >>> tag = find_tag_by_id(rosetta_admin_browser.contents, 'empty')
157+ >>> tag = find_tag_by_id(owner_browser.contents, 'empty')
158 >>> print extract_text(tag.renderContents())
159 No custom language codes have been defined.
160
161-The admin can add a custom language code.
162-
163- >>> rosetta_admin_browser.getLink("Add a custom language code").click()
164- >>> add_page = rosetta_admin_browser.url
165-
166- >>> rosetta_admin_browser.getControl("Language code:").value = 'no'
167- >>> rosetta_admin_browser.getControl("Language:").value = ['nn']
168- >>> rosetta_admin_browser.getControl("Add").click()
169+There is a link to add a custom language code.
170+
171+ >>> owner_browser.getLink("Add a custom language code").click()
172+ >>> add_page = owner_browser.url
173+
174+ >>> owner_browser.getControl("Language code:").value = 'no'
175+ >>> owner_browser.getControl("Language:").value = ['nn']
176+ >>> owner_browser.getControl("Add").click()
177
178 This leads back to the custom language codes overview, where the new
179 code is now shown.
180
181- >>> rosetta_admin_browser.url == custom_language_codes_page
182+ >>> owner_browser.url == custom_language_codes_page
183 True
184
185- >>> tag = find_tag_by_id(rosetta_admin_browser.contents, 'nonempty')
186+ >>> tag = find_tag_by_id(owner_browser.contents, 'nonempty')
187 >>> print extract_text(tag.renderContents())
188 Foo uses the following custom language codes:
189 Code... ...maps to language
190@@ -98,8 +98,8 @@
191 There is an overview page for the custom code, though there's not much
192 to see there.
193
194- >>> rosetta_admin_browser.getLink("no").click()
195- >>> main = find_main_content(rosetta_admin_browser.contents)
196+ >>> owner_browser.getLink("no").click()
197+ >>> main = find_main_content(owner_browser.contents)
198 >>> print extract_text(main.renderContents())
199 Foo Translations Custom language code ...no...
200 For Foo, uploads with the language code
201@@ -111,79 +111,79 @@
202
203 The overview page leads back to the custom language codes overview.
204
205- >>> code_page = rosetta_admin_browser.url
206- >>> rosetta_admin_browser.getLink(
207+ >>> code_page = owner_browser.url
208+ >>> owner_browser.getLink(
209 ... "custom language codes overview").click()
210- >>> rosetta_admin_browser.url == custom_language_codes_page
211+ >>> owner_browser.url == custom_language_codes_page
212 True
213
214- >>> rosetta_admin_browser.open(code_page)
215+ >>> owner_browser.open(code_page)
216
217-There is also a link for removing codes. The admin follows the link and
218+There is also a link for removing codes. The owner follows the link and
219 removes the "no" custom language code.
220
221- >>> rosetta_admin_browser.getLink("remove custom language code").click()
222- >>> remove_page = rosetta_admin_browser.url
223- >>> rosetta_admin_browser.getControl("Remove").click()
224+ >>> owner_browser.getLink("remove custom language code").click()
225+ >>> remove_page = owner_browser.url
226+ >>> owner_browser.getControl("Remove").click()
227
228 This leads back to the overview page.
229
230- >>> rosetta_admin_browser.url == custom_language_codes_page
231+ >>> owner_browser.url == custom_language_codes_page
232 True
233
234- >>> tag = find_tag_by_id(rosetta_admin_browser.contents, 'empty')
235- >>> print extract_text(tag.renderContents())
236- No custom language codes have been defined.
237-
238-
239-Non-admin access
240-================
241-
242-A non-admin can see the page, actually, if they know the URL. This can
243-be convenient for debugging.
244-
245- >>> owner_browser.open(custom_language_codes_page)
246-
247 >>> tag = find_tag_by_id(owner_browser.contents, 'empty')
248 >>> print extract_text(tag.renderContents())
249 No custom language codes have been defined.
250
251+
252+Unprivileged access
253+===================
254+
255+A unprivileged user can see the page, actually, if they know the URL.
256+This can be convenient for debugging.
257+
258+ >>> user_browser.open(custom_language_codes_page)
259+
260+ >>> tag = find_tag_by_id(user_browser.contents, 'empty')
261+ >>> print extract_text(tag.renderContents())
262+ No custom language codes have been defined.
263+
264 However all they get is a read-only version of the page.
265
266- >>> owner_browser.getLink("Add a custom language code").click()
267+ >>> user_browser.getLink("Add a custom language code").click()
268 Traceback (most recent call last):
269 ...
270 LinkNotFoundError
271
272 The page for adding custom language codes is not accessible to them.
273
274+ >>> user_browser.open(add_page)
275+ Traceback (most recent call last):
276+ ...
277+ Unauthorized: ...
278+
279+And naturally, if the owner creates a custom language code again, an
280+unprivileged user can't remove it.
281+
282 >>> owner_browser.open(add_page)
283- Traceback (most recent call last):
284- ...
285- Unauthorized: ...
286-
287-And naturally, if an admin creates a custom language code again, a
288-non-admin can't remove it.
289-
290- >>> rosetta_admin_browser.open(add_page)
291- >>> rosetta_admin_browser.getControl("Language code:").value = 'no'
292- >>> rosetta_admin_browser.getControl("Language:").value = ['nn']
293- >>> rosetta_admin_browser.getControl("Add").click()
294-
295- >>> owner_browser.open(custom_language_codes_page)
296- >>> tag = find_tag_by_id(owner_browser.contents, 'nonempty')
297+ >>> owner_browser.getControl("Language code:").value = 'no'
298+ >>> owner_browser.getControl("Language:").value = ['nn']
299+ >>> owner_browser.getControl("Add").click()
300+
301+ >>> user_browser.open(custom_language_codes_page)
302+ >>> tag = find_tag_by_id(user_browser.contents, 'nonempty')
303 >>> print extract_text(tag.renderContents())
304 Foo uses the following custom language codes:
305 Code... ...maps to language
306 no Norwegian Nynorsk
307
308- >>> owner_browser.getLink("no").click()
309- >>> owner_browser.getLink("remove custom language code")
310+ >>> user_browser.getLink("no").click()
311+ >>> user_browser.getLink("remove custom language code")
312 Traceback (most recent call last):
313 ...
314 LinkNotFoundError
315
316- >>> owner_browser.open(remove_page)
317+ >>> user_browser.open(remove_page)
318 Traceback (most recent call last):
319 ...
320 Unauthorized: ...
321@@ -197,7 +197,8 @@
322 package--i.e. the combination of a distribution and a source package
323 name. However, since there is no Translations page for that type of
324 object (and we'd probably never go there if there were), the link is
325-shown on the source package page.
326+shown on the source package page. For distributions, the owner of the
327+distribution's translation group is a translations administrator.
328
329 >>> login(ANONYMOUS)
330 >>> from lp.registry.model.sourcepackage import SourcePackage
331@@ -219,38 +220,44 @@
332 ... distroseries=other_series,
333 ... sourcepackagename=package.sourcepackagename),
334 ... rootsite="translations")
335+ >>> translations_admin = factory.makePerson(
336+ ... email='ta@example.com', password='test')
337+ >>> translationgroup = factory.makeTranslationGroup(
338+ ... owner=translations_admin)
339+ >>> removeSecurityProxy(distro).translationgroup = translationgroup
340 >>> logout()
341
342- >>> rosetta_admin_browser.open(package_page)
343+ >>> translations_browser = setupBrowser("Basic ta@example.com:test")
344+ >>> translations_browser.open(package_page)
345
346 Of course in this case, the notice about there being no custom language
347 codes talks about a package, not a project.
348
349- >>> tag = find_custom_language_codes_link(rosetta_admin_browser)
350+ >>> tag = find_custom_language_codes_link(translations_browser)
351 >>> print extract_text(tag.renderContents())
352 If necessary, you may
353 define custom language codes
354 for this package.
355
356- >>> rosetta_admin_browser.getLink("define custom language codes").click()
357- >>> custom_language_codes_page = rosetta_admin_browser.url
358+ >>> translations_browser.getLink("define custom language codes").click()
359+ >>> custom_language_codes_page = translations_browser.url
360
361- >>> tag = find_tag_by_id(rosetta_admin_browser.contents, 'empty')
362+ >>> tag = find_tag_by_id(translations_browser.contents, 'empty')
363 >>> print extract_text(tag.renderContents())
364 No custom language codes have been defined.
365
366-Again, an admin can add a language code.
367-
368- >>> rosetta_admin_browser.getLink("Add a custom language code").click()
369- >>> add_page = rosetta_admin_browser.url
370-
371- >>> rosetta_admin_browser.getControl("Language code:").value = 'pt-br'
372- >>> rosetta_admin_browser.getControl("Language:").value = ['pt_BR']
373- >>> rosetta_admin_browser.getControl("Add").click()
374+A translations admin can add a language code.
375+
376+ >>> translations_browser.getLink("Add a custom language code").click()
377+ >>> add_page = translations_browser.url
378+
379+ >>> translations_browser.getControl("Language code:").value = 'pt-br'
380+ >>> translations_browser.getControl("Language:").value = ['pt_BR']
381+ >>> translations_browser.getControl("Add").click()
382
383 The language code is displayed.
384
385- >>> tag = find_tag_by_id(rosetta_admin_browser.contents, 'nonempty')
386+ >>> tag = find_tag_by_id(translations_browser.contents, 'nonempty')
387 >>> print extract_text(tag.renderContents())
388 bar in distro uses the following custom language codes:
389 Code... ...maps to language
390@@ -259,15 +266,15 @@
391 It's also displayed identically on the same package but in another
392 release series of the same distribution.
393
394- >>> rosetta_admin_browser.open(page_in_other_series)
395- >>> tag = find_custom_language_codes_link(rosetta_admin_browser)
396+ >>> translations_browser.open(page_in_other_series)
397+ >>> tag = find_custom_language_codes_link(translations_browser)
398 >>> print extract_text(tag.renderContents())
399 If necessary, you may
400 define custom language codes
401 for this package.
402
403- >>> rosetta_admin_browser.getLink("define custom language codes").click()
404- >>> tag = find_tag_by_id(rosetta_admin_browser.contents, 'nonempty')
405+ >>> translations_browser.getLink("define custom language codes").click()
406+ >>> tag = find_tag_by_id(translations_browser.contents, 'nonempty')
407 >>> print extract_text(tag.renderContents())
408 bar in distro uses the following custom language codes:
409 Code... ...maps to language
410@@ -276,13 +283,13 @@
411
412 The new code has a link there...
413
414- >>> rosetta_admin_browser.getLink("pt-br").click()
415+ >>> translations_browser.getLink("pt-br").click()
416
417 ...and can be deleted.
418
419- >>> rosetta_admin_browser.getLink("remove custom language code").click()
420- >>> rosetta_admin_browser.getControl("Remove").click()
421+ >>> translations_browser.getLink("remove custom language code").click()
422+ >>> translations_browser.getControl("Remove").click()
423
424- >>> tag = find_tag_by_id(rosetta_admin_browser.contents, 'empty')
425+ >>> tag = find_tag_by_id(translations_browser.contents, 'empty')
426 >>> print extract_text(tag.renderContents())
427 No custom language codes have been defined.

« Back to merge proposal