Merge lp:~adiroiban/launchpad/bug-127171 into lp:launchpad
- bug-127171
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Jeroen T. Vermeulen |
Approved revision: | not available |
Merged at revision: | not available |
Proposed branch: | lp:~adiroiban/launchpad/bug-127171 |
Merge into: | lp:launchpad |
Diff against target: |
802 lines (+226/-88) 18 files modified
lib/canonical/launchpad/security.py (+23/-9) lib/canonical/launchpad/testing/pages.py (+37/-4) lib/lp/registry/browser/product.py (+4/-2) lib/lp/registry/configure.zcml (+23/-11) lib/lp/registry/interfaces/distribution.py (+2/-2) lib/lp/registry/interfaces/product.py (+5/-5) lib/lp/registry/interfaces/project.py (+5/-4) lib/lp/translations/browser/configure.zcml (+8/-8) lib/lp/translations/browser/distribution.py (+3/-5) lib/lp/translations/browser/potemplate.py (+1/-1) lib/lp/translations/browser/product.py (+6/-6) lib/lp/translations/browser/project.py (+5/-5) lib/lp/translations/browser/translationgroup.py (+3/-4) lib/lp/translations/interfaces/translationgroup.py (+2/-2) lib/lp/translations/stories/translationgroups/46-test-distro-structured-permissions.txt (+1/-1) lib/lp/translations/stories/translationgroups/xx-change-translation-policy.txt (+92/-12) lib/lp/translations/templates/distribution-language-pack-admin-info.pt (+2/-2) lib/lp/translations/templates/hastranslationgroup-portlet-translation-groups-and-permission.pt (+4/-5) |
To merge this branch: | bzr merge lp:~adiroiban/launchpad/bug-127171 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jeroen T. Vermeulen (community) | code | Approve | |
Review via email: mp+19444@code.launchpad.net |
Commit message
+changetranslators becomes +settings, and rosetta admins can access it.
Description of the change
Adi Roiban (adiroiban) wrote : | # |
Jeroen T. Vermeulen (jtv) wrote : | # |
Fantastic branch and cover letter. Thanks for all the drive-by cleanups!
Don't worry about those lint reports; pylint gets confused sometimes.
I only have two very minor notes about the changes:
Line 410: I believe our policies nowadays for function, method, and class definitions with parameter lists that don't fit the line is to indent the next line to just behind the opening parenthesis. I hope the spacing comes across here, but:
{{{
409 +class IProject(
410 + ITranslationPol
}}}
...should be:
{{{
409 +class IProject(
410 + ITranslationPol
}}}
That is, ITranslationPolicy should be directly under IProjectPublic.
Line 551: When we wrap lists (of multiple items) to multiple lines, we keep the closing bracket on a line of its own. The last element in the list should have a trailing comma. So:
{{{
546 field_names = [
547 "translationgroup",
548 "translationper
549 - "translation_focus"
550 - ]
551 + "translation_
}}}
...was actually correct apart from the missing comma. It should be:
{{{
546 field_names = [
547 "translationgroup",
548 "translationper
549 - "translation_focus"
549 + "translation_
550 ]
}}}
Very minor comments indeed, but I could think of nothing else. :-)
Adi Roiban (adiroiban) wrote : | # |
În data de Mi, 17-02-2010 la 09:18 +0000, Jeroen T. Vermeulen a scris:
> Review: Approve code
> Fantastic branch and cover letter. Thanks for all the drive-by cleanups!
>
> Don't worry about those lint reports; pylint gets confused sometimes.
>
> I only have two very minor notes about the changes:
I have fixed and pushed the formating problems.
Can you please put this branch on queue for ec2 testings?
Many thanks!
--
Adi Roiban
Preview Diff
1 | === modified file 'lib/canonical/launchpad/security.py' |
2 | --- lib/canonical/launchpad/security.py 2010-02-10 23:14:56 +0000 |
3 | +++ lib/canonical/launchpad/security.py 2010-02-17 09:39:19 +0000 |
4 | @@ -496,6 +496,21 @@ |
5 | return user.in_admin or user.in_rosetta_experts |
6 | |
7 | |
8 | +class AdminProjectTranslations(AuthorizationBase): |
9 | + permission = 'launchpad.TranslationsAdmin' |
10 | + usedfor = IProject |
11 | + |
12 | + def checkAuthenticated(self, user): |
13 | + """Is the user able to manage `IProject` translations settings? |
14 | + |
15 | + Any Launchpad/Launchpad Translations administrator or owner is |
16 | + able to change translation settings for a project. |
17 | + """ |
18 | + return (user.isOwner(self.obj) or |
19 | + user.in_rosetta_experts or |
20 | + user.in_admin) |
21 | + |
22 | + |
23 | class AdminProductTranslations(AuthorizationBase): |
24 | permission = 'launchpad.TranslationsAdmin' |
25 | usedfor = IProduct |
26 | @@ -1100,8 +1115,7 @@ |
27 | usedfor = ICodeImportMachine |
28 | |
29 | |
30 | -class AdminDistributionTranslations(OnlyRosettaExpertsAndAdmins, |
31 | - EditDistributionByDistroOwnersOrAdmins): |
32 | +class AdminDistributionTranslations(AuthorizationBase): |
33 | """Class for deciding who can administer distribution translations. |
34 | |
35 | This class is used for `launchpad.TranslationsAdmin` privilege on |
36 | @@ -1115,9 +1129,9 @@ |
37 | def checkAuthenticated(self, user): |
38 | """Is the user able to manage `IDistribution` translations settings? |
39 | |
40 | - Any Launchpad/Launchpad Translations administrator or people allowed |
41 | - to edit distribution details are able to change translation settings |
42 | - for a distribution. |
43 | + Any Launchpad/Launchpad Translations administrator, translation group |
44 | + owner or a person allowed to edit distribution details is able to |
45 | + change translations settings for a distribution. |
46 | """ |
47 | # Translation group owner for a distribution is also a |
48 | # translations administrator for it. |
49 | @@ -1125,10 +1139,9 @@ |
50 | if translation_group and user.inTeam(translation_group.owner): |
51 | return True |
52 | else: |
53 | - return ( |
54 | - OnlyRosettaExpertsAndAdmins.checkAuthenticated(self, user) or |
55 | - EditDistributionByDistroOwnersOrAdmins.checkAuthenticated( |
56 | - self, user)) |
57 | + return (user.in_rosetta_experts or |
58 | + EditDistributionByDistroOwnersOrAdmins( |
59 | + self.obj).checkAuthenticated(user)) |
60 | |
61 | |
62 | class AdminPOTemplateDetails(OnlyRosettaExpertsAndAdmins): |
63 | @@ -1319,6 +1332,7 @@ |
64 | """ |
65 | return self.obj.canEdit(user) |
66 | |
67 | + |
68 | class AdminTranslationImportQueue(OnlyRosettaExpertsAndAdmins): |
69 | permission = 'launchpad.Admin' |
70 | usedfor = ITranslationImportQueue |
71 | |
72 | === modified file 'lib/canonical/launchpad/testing/pages.py' |
73 | --- lib/canonical/launchpad/testing/pages.py 2010-01-04 16:02:31 +0000 |
74 | +++ lib/canonical/launchpad/testing/pages.py 2010-02-17 09:39:19 +0000 |
75 | @@ -28,9 +28,11 @@ |
76 | from zope.component import getUtility |
77 | from zope.testbrowser.testing import Browser |
78 | from zope.testing import doctest |
79 | +from zope.security.proxy import removeSecurityProxy |
80 | |
81 | from canonical.launchpad.interfaces import ( |
82 | - IOAuthConsumerSet, OAUTH_REALM, ILaunchpadCelebrities) |
83 | + IOAuthConsumerSet, OAUTH_REALM, ILaunchpadCelebrities, |
84 | + TeamMembershipStatus) |
85 | from canonical.launchpad.testing.systemdocs import ( |
86 | LayeredDocFileSuite, SpecialOutputChecker, strip_prefix) |
87 | from canonical.launchpad.webapp import canonical_url |
88 | @@ -51,6 +53,7 @@ |
89 | sending both Basic Auth and cookie credentials raises an exception |
90 | (Bug 39881). |
91 | """ |
92 | + |
93 | def __init__(self, *args, **kw): |
94 | if kw.get('debug'): |
95 | self._debug = True |
96 | @@ -203,7 +206,9 @@ |
97 | |
98 | def find_tags_by_class(content, class_, only_first=False): |
99 | """Find and return one or more tags matching the given class(es)""" |
100 | + |
101 | match_classes = set(class_.split()) |
102 | + |
103 | def class_matcher(value): |
104 | if value is None: |
105 | return False |
106 | @@ -263,6 +268,7 @@ |
107 | for message in get_feedback_messages(content): |
108 | print message |
109 | |
110 | + |
111 | def print_table(content, columns=None, skip_rows=None, sep="\t"): |
112 | """Given a <table> print the content of each row. |
113 | |
114 | @@ -283,6 +289,7 @@ |
115 | if len(row_content) > 0: |
116 | print sep.join(row_content) |
117 | |
118 | + |
119 | def print_radio_button_field(content, name): |
120 | """Find the input called field.name, and print a friendly representation. |
121 | |
122 | @@ -457,7 +464,7 @@ |
123 | |
124 | def print_navigation_links(content): |
125 | """Print navigation menu urls.""" |
126 | - navigation_links = find_tag_by_id(content, 'navigation-tabs') |
127 | + navigation_links = find_tag_by_id(content, 'navigation-tabs') |
128 | if navigation_links is None: |
129 | print "No navigation links" |
130 | return |
131 | @@ -527,7 +534,7 @@ |
132 | |
133 | def print_batch_header(soup): |
134 | """Print the batch navigator header.""" |
135 | - navigation = soup.find('td', {'class' : 'batch-navigation-index'}) |
136 | + navigation = soup.find('td', {'class': 'batch-navigation-index'}) |
137 | print extract_text(navigation).encode('ASCII', 'backslashreplace') |
138 | |
139 | |
140 | @@ -669,18 +676,43 @@ |
141 | login('foo.bar@canonical.com') |
142 | try: |
143 | dtg_member = LaunchpadObjectFactory().makePerson( |
144 | + name='ubuntu-translations-coordinator', |
145 | email="dtg-member@ex.com", password="test") |
146 | except NameAlreadyTaken: |
147 | # We have already created the translations coordinator |
148 | pass |
149 | else: |
150 | - dtg = LaunchpadObjectFactory().makeTranslationGroup(owner=dtg_member) |
151 | + dtg = LaunchpadObjectFactory().makeTranslationGroup( |
152 | + name="ubuntu-translators", |
153 | + title="Ubuntu Translators", |
154 | + owner=dtg_member) |
155 | ubuntu = getUtility(ILaunchpadCelebrities).ubuntu |
156 | ubuntu.translationgroup = dtg |
157 | logout() |
158 | return setupBrowser(auth='Basic dtg-member@ex.com:test') |
159 | |
160 | |
161 | +def setupRosettaExpertBrowser(): |
162 | + """Testbrowser configured for Rosetta Experts.""" |
163 | + |
164 | + login('admin@canonical.com') |
165 | + try: |
166 | + rosetta_expert = LaunchpadObjectFactory().makePerson( |
167 | + name='rosetta-experts-member', |
168 | + email='re@ex.com', password='test') |
169 | + except NameAlreadyTaken: |
170 | + # We have already created an Rosetta expert |
171 | + pass |
172 | + else: |
173 | + rosetta_experts_team = removeSecurityProxy(getUtility( |
174 | + ILaunchpadCelebrities).rosetta_experts) |
175 | + rosetta_experts_team.addMember( |
176 | + rosetta_expert, reviewer=rosetta_experts_team, |
177 | + status=TeamMembershipStatus.ADMIN) |
178 | + logout() |
179 | + return setupBrowser(auth='Basic re@ex.com:test') |
180 | + |
181 | + |
182 | def stop(): |
183 | # Temporarily restore the real stdout. |
184 | old_stdout = sys.stdout |
185 | @@ -704,6 +736,7 @@ |
186 | 'launchpad-library', '') |
187 | test.globs['setupBrowser'] = setupBrowser |
188 | test.globs['setupDTCBrowser'] = setupDTCBrowser |
189 | + test.globs['setupRosettaExpertBrowser'] = setupRosettaExpertBrowser |
190 | test.globs['browser'] = setupBrowser() |
191 | test.globs['anon_browser'] = setupBrowser() |
192 | test.globs['user_browser'] = setupBrowser( |
193 | |
194 | === modified file 'lib/lp/registry/browser/product.py' |
195 | --- lib/lp/registry/browser/product.py 2010-01-21 02:16:15 +0000 |
196 | +++ lib/lp/registry/browser/product.py 2010-02-17 09:39:19 +0000 |
197 | @@ -174,6 +174,7 @@ |
198 | Requires the "product" attribute be set in the child |
199 | classes' action handler. |
200 | """ |
201 | + |
202 | def validate(self, data): |
203 | """Validate 'licenses' and 'license_info'. |
204 | |
205 | @@ -221,6 +222,7 @@ |
206 | "Launchpad", config.canonical.noreply_from_address) |
207 | license_titles = '\n'.join( |
208 | license.title for license in self.product.licenses) |
209 | + |
210 | def indent(text): |
211 | text = '\n '.join(line for line in text.split('\n')) |
212 | text = ' ' + text |
213 | @@ -524,7 +526,6 @@ |
214 | series_list.insert(0, self.product.development_focus) |
215 | return series_list |
216 | |
217 | - |
218 | @property |
219 | def sorted_series_list(self): |
220 | """Return a sorted list of series. |
221 | @@ -986,6 +987,7 @@ |
222 | Replaces the use of a (series, release) tuple so that it can be more |
223 | clearly addressed in the view class. |
224 | """ |
225 | + |
226 | def __init__(self, series, release): |
227 | self.series = series |
228 | self.release = release |
229 | @@ -1197,6 +1199,7 @@ |
230 | 'for this project first.', |
231 | canonical_url(self.context, rootsite="bugs"))) |
232 | |
233 | + |
234 | class ProductAdminView(ProductEditView, EditPrivateBugsMixin): |
235 | label = "Administer project details" |
236 | field_names = ["name", "owner", "active", "autoupdate", "private_bugs"] |
237 | @@ -1693,7 +1696,6 @@ |
238 | # StepView requires that its validate() method not be overridden, so make |
239 | # sure this calls the right method. validateStep() will call the license |
240 | # validation code. |
241 | - |
242 | def validate(self, data): |
243 | """See `MultiStepView`.""" |
244 | StepView.validate(self, data) |
245 | |
246 | === modified file 'lib/lp/registry/configure.zcml' |
247 | --- lib/lp/registry/configure.zcml 2010-02-16 20:36:48 +0000 |
248 | +++ lib/lp/registry/configure.zcml 2010-02-17 09:39:19 +0000 |
249 | @@ -273,9 +273,14 @@ |
250 | interface="canonical.launchpad.interfaces.IFAQCollection"/> |
251 | <allow |
252 | interface="canonical.launchpad.interfaces.IQuestionCollection"/> |
253 | + <allow |
254 | + interface="lp.translations.interfaces.translationgroup.ITranslationPolicy"/> |
255 | <require |
256 | permission="launchpad.Edit" |
257 | set_schema="lp.registry.interfaces.project.IProjectPublic"/> |
258 | + <require |
259 | + permission="launchpad.TranslationsAdmin" |
260 | + set_schema="lp.translations.interfaces.translationgroup.ITranslationPolicy"/> |
261 | |
262 | <!-- IStructuralSubscriptionTarget --> |
263 | |
264 | @@ -1081,9 +1086,7 @@ |
265 | redeemSubscriptionVoucher releaseroot |
266 | remote_product screenshotsurl |
267 | security_contact sourceforgeproject |
268 | - summary title translationgroup |
269 | - translationpermission translation_focus |
270 | - wikiurl"/> |
271 | + summary title wikiurl"/> |
272 | |
273 | <!-- mark 2006-04-10 I put "name" in the admin group because |
274 | with Bazaar now in place, lots of people can have personal |
275 | @@ -1100,6 +1103,12 @@ |
276 | permission="launchpad.Admin" |
277 | set_attributes="name autoupdate registrant"/> |
278 | <require |
279 | + permission="launchpad.TranslationsAdmin" |
280 | + set_attributes=" |
281 | + translation_focus |
282 | + translationgroup |
283 | + translationpermission"/> |
284 | + <require |
285 | permission="zope.Public" |
286 | attributes=" |
287 | qualifies_for_free_hosting"/> |
288 | @@ -1375,16 +1384,19 @@ |
289 | interface="lp.registry.interfaces.distribution.IDistributionDriverRestricted"/> |
290 | <require |
291 | permission="launchpad.Edit" |
292 | - set_attributes="displayname title summary description |
293 | - translation_focus translationgroup translationpermission |
294 | - driver members owner security_contact mirror_admin |
295 | - homepage_content icon logo mugshot enable_bug_expiration |
296 | - bug_reporting_guidelines official_blueprints |
297 | - official_malone official_rosetta official_answers |
298 | - official_bug_tags"/> |
299 | + set_attributes=" |
300 | + displayname title summary description driver |
301 | + members owner security_contact mirror_admin homepage_content |
302 | + icon logo mugshot enable_bug_expiration |
303 | + bug_reporting_guidelines official_blueprints official_malone |
304 | + official_rosetta official_answers official_bug_tags"/> |
305 | <require |
306 | permission="launchpad.TranslationsAdmin" |
307 | - set_attributes="language_pack_admin"/> |
308 | + set_attributes=" |
309 | + language_pack_admin |
310 | + translationgroup |
311 | + translationpermission |
312 | + translation_focus"/> |
313 | |
314 | <!-- IHasAliases --> |
315 | |
316 | |
317 | === modified file 'lib/lp/registry/interfaces/distribution.py' |
318 | --- lib/lp/registry/interfaces/distribution.py 2010-02-04 21:18:32 +0000 |
319 | +++ lib/lp/registry/interfaces/distribution.py 2010-02-17 09:39:19 +0000 |
320 | @@ -55,7 +55,7 @@ |
321 | ISpecificationTarget) |
322 | from lp.blueprints.interfaces.sprint import IHasSprints |
323 | from lp.translations.interfaces.translationgroup import ( |
324 | - IHasTranslationGroup) |
325 | + ITranslationPolicy) |
326 | from canonical.launchpad.webapp.interfaces import NameLookupFailed |
327 | from canonical.launchpad.validators.name import name_validator |
328 | from canonical.launchpad.fields import ( |
329 | @@ -90,7 +90,7 @@ |
330 | class IDistributionPublic( |
331 | IBugTarget, ICanGetMilestonesDirectly, IHasAppointedDriver, |
332 | IHasBuildRecords, IHasDrivers, IHasMentoringOffers, IHasMilestones, |
333 | - IHasOwner, IHasSecurityContact, IHasSprints, IHasTranslationGroup, |
334 | + IHasOwner, IHasSecurityContact, IHasSprints, ITranslationPolicy, |
335 | IKarmaContext, ILaunchpadUsage, IMakesAnnouncements, |
336 | IOfficialBugTagTargetPublic, IPillar, ISpecificationTarget): |
337 | """Public IDistribution properties.""" |
338 | |
339 | === modified file 'lib/lp/registry/interfaces/product.py' |
340 | --- lib/lp/registry/interfaces/product.py 2010-01-20 13:58:45 +0000 |
341 | +++ lib/lp/registry/interfaces/product.py 2010-02-17 09:39:19 +0000 |
342 | @@ -49,7 +49,7 @@ |
343 | from lp.registry.interfaces.karma import IKarmaContext |
344 | from canonical.launchpad.interfaces.launchpad import ( |
345 | IHasAppointedDriver, IHasDrivers, IHasExternalBugTracker, IHasIcon, |
346 | - IHasLogo, IHasMugshot,IHasSecurityContact, ILaunchpadUsage) |
347 | + IHasLogo, IHasMugshot, IHasSecurityContact, ILaunchpadUsage) |
348 | from lp.registry.interfaces.role import IHasOwner |
349 | from lp.registry.interfaces.milestone import ( |
350 | ICanGetMilestonesDirectly, IHasMilestones) |
351 | @@ -65,7 +65,7 @@ |
352 | ISpecificationTarget) |
353 | from lp.blueprints.interfaces.sprint import IHasSprints |
354 | from lp.translations.interfaces.translationgroup import ( |
355 | - IHasTranslationGroup) |
356 | + ITranslationPolicy) |
357 | from canonical.launchpad.validators import LaunchpadValidationError |
358 | from canonical.launchpad.validators.name import name_validator |
359 | from canonical.launchpad.webapp.interfaces import NameLookupFailed |
360 | @@ -179,8 +179,8 @@ |
361 | 'ACADEMIC', 'APACHE', 'ARTISTIC', 'ARTISTIC_2_0', |
362 | 'BSD', 'COMMON_PUBLIC', |
363 | 'CC_BY', 'CC_BY_SA', 'CC_0', 'ECLIPSE', |
364 | - 'EDUCATIONAL_COMMUNITY', 'AFFERO', 'GNU_GPL_V2','GNU_GPL_V3', |
365 | - 'GNU_LGPL_V2_1','GNU_LGPL_V3', 'MIT', 'MPL', 'OPEN_SOFTWARE', 'PERL', |
366 | + 'EDUCATIONAL_COMMUNITY', 'AFFERO', 'GNU_GPL_V2', 'GNU_GPL_V3', |
367 | + 'GNU_LGPL_V2_1', 'GNU_LGPL_V3', 'MIT', 'MPL', 'OPEN_SOFTWARE', 'PERL', |
368 | 'PHP', 'PUBLIC_DOMAIN', 'PYTHON', 'ZPL', |
369 | 'DONT_KNOW', 'OTHER_PROPRIETARY', 'OTHER_OPEN_SOURCE') |
370 | |
371 | @@ -338,7 +338,7 @@ |
372 | IHasBranchVisibilityPolicy, IHasDrivers, IHasExternalBugTracker, IHasIcon, |
373 | IHasLogo, IHasMentoringOffers, IHasMergeProposals, IHasMilestones, |
374 | IHasMugshot, IHasOwner, IHasSecurityContact, IHasSprints, |
375 | - IHasTranslationGroup, IKarmaContext, ILaunchpadUsage, IMakesAnnouncements, |
376 | + ITranslationPolicy, IKarmaContext, ILaunchpadUsage, IMakesAnnouncements, |
377 | IOfficialBugTagTargetPublic, IPillar, ISpecificationTarget): |
378 | """Public IProduct properties.""" |
379 | |
380 | |
381 | === modified file 'lib/lp/registry/interfaces/project.py' |
382 | --- lib/lp/registry/interfaces/project.py 2009-12-05 18:37:28 +0000 |
383 | +++ lib/lp/registry/interfaces/project.py 2010-02-17 09:39:19 +0000 |
384 | @@ -38,7 +38,7 @@ |
385 | IHasSpecifications) |
386 | from lp.blueprints.interfaces.sprint import IHasSprints |
387 | from lp.translations.interfaces.translationgroup import ( |
388 | - IHasTranslationGroup) |
389 | + ITranslationPolicy) |
390 | from lp.registry.interfaces.structuralsubscription import ( |
391 | IStructuralSubscriptionTarget) |
392 | from canonical.launchpad.validators.name import name_validator |
393 | @@ -63,8 +63,8 @@ |
394 | ICanGetMilestonesDirectly, IHasAppointedDriver, IHasBranches, IHasBugs, |
395 | IHasDrivers, IHasBranchVisibilityPolicy, IHasIcon, IHasLogo, |
396 | IHasMentoringOffers, IHasMergeProposals, IHasMilestones, IHasMugshot, |
397 | - IHasOwner, IHasSpecifications, IHasSprints, IHasTranslationGroup, |
398 | - IMakesAnnouncements, IKarmaContext, IPillar, IRootContext): |
399 | + IHasOwner, IHasSpecifications, IHasSprints, IMakesAnnouncements, |
400 | + IKarmaContext, IPillar, IRootContext): |
401 | """Public IProject properties.""" |
402 | |
403 | id = Int(title=_('ID'), readonly=True) |
404 | @@ -279,7 +279,8 @@ |
405 | """Return a ProjectSeries object with name `series_name`.""" |
406 | |
407 | |
408 | -class IProject(IProjectPublic, IStructuralSubscriptionTarget): |
409 | +class IProject(IProjectPublic, IStructuralSubscriptionTarget, |
410 | + ITranslationPolicy): |
411 | """A Project.""" |
412 | |
413 | export_as_webservice_entry('project_group') |
414 | |
415 | === modified file 'lib/lp/translations/browser/configure.zcml' |
416 | --- lib/lp/translations/browser/configure.zcml 2010-02-10 13:04:10 +0000 |
417 | +++ lib/lp/translations/browser/configure.zcml 2010-02-17 09:39:19 +0000 |
418 | @@ -75,7 +75,7 @@ |
419 | template="../templates/translations-macros.pt" |
420 | layer="canonical.launchpad.layers.TranslationsLayer"/> |
421 | <browser:page |
422 | - for="lp.translations.interfaces.translationgroup.IHasTranslationGroup" |
423 | + for="lp.translations.interfaces.translationgroup.ITranslationPolicy" |
424 | facet="translations" |
425 | permission="zope.Public" |
426 | name="+portlet-translation-groups-and-permission" |
427 | @@ -800,10 +800,10 @@ |
428 | template="../templates/hastranslationimports-index.pt" |
429 | layer="canonical.launchpad.layers.TranslationsLayer"/> |
430 | <browser:page |
431 | - name="+changetranslators" |
432 | + name="+settings" |
433 | for="lp.registry.interfaces.product.IProduct" |
434 | - class="lp.translations.browser.product.ProductChangeTranslatorsView" |
435 | - permission="launchpad.Edit" |
436 | + class="lp.translations.browser.product.ProductSettingsView" |
437 | + permission="launchpad.TranslationsAdmin" |
438 | template="../templates/set-translators.pt" |
439 | layer="canonical.launchpad.layers.TranslationsLayer"/> |
440 | <browser:pages |
441 | @@ -853,10 +853,10 @@ |
442 | class="lp.translations.browser.translations.HelpTranslateButtonView" |
443 | permission="zope.Public"/> |
444 | <browser:page |
445 | - name="+changetranslators" |
446 | + name="+settings" |
447 | for="lp.registry.interfaces.project.IProject" |
448 | - class="lp.translations.browser.project.ProjectChangeTranslatorsView" |
449 | - permission="launchpad.Edit" |
450 | + class="lp.translations.browser.project.ProjectSettingsView" |
451 | + permission="launchpad.TranslationsAdmin" |
452 | template="../templates/set-translators.pt" |
453 | layer="canonical.launchpad.layers.TranslationsLayer"/> |
454 | |
455 | @@ -891,7 +891,7 @@ |
456 | name="+settings" |
457 | for="lp.registry.interfaces.distribution.IDistribution" |
458 | class="lp.translations.browser.distribution.DistributionSettingsView" |
459 | - permission="launchpad.Edit" |
460 | + permission="launchpad.TranslationsAdmin" |
461 | template="../templates/set-translators.pt" |
462 | layer="canonical.launchpad.layers.TranslationsLayer"/> |
463 | <browser:page |
464 | |
465 | === modified file 'lib/lp/translations/browser/distribution.py' |
466 | --- lib/lp/translations/browser/distribution.py 2009-12-13 11:55:40 +0000 |
467 | +++ lib/lp/translations/browser/distribution.py 2010-02-17 09:39:19 +0000 |
468 | @@ -35,10 +35,10 @@ |
469 | link = canonical_url(self.context, rootsite='translations') |
470 | return Link(link, text) |
471 | |
472 | - @enabled_with_permission('launchpad.Edit') |
473 | + @enabled_with_permission('launchpad.TranslationsAdmin') |
474 | def settings(self): |
475 | - text = 'Settings' |
476 | - return Link('+settings', text) |
477 | + text = 'Change permissions' |
478 | + return Link('+settings', text, icon='edit') |
479 | |
480 | @enabled_with_permission('launchpad.TranslationsAdmin') |
481 | def language_pack_admin(self): |
482 | @@ -55,7 +55,6 @@ |
483 | |
484 | schema = IDistribution |
485 | label = "Select the language pack administrator" |
486 | - page_title = "Set language pack administrator" |
487 | field_names = ['language_pack_admin'] |
488 | |
489 | @property |
490 | @@ -111,7 +110,6 @@ |
491 | |
492 | class DistributionSettingsView(TranslationsMixin, DistributionEditView): |
493 | label = "Set permissions and policies" |
494 | - page_title = "Permissions and policies" |
495 | field_names = ["translationgroup", "translationpermission"] |
496 | |
497 | @property |
498 | |
499 | === modified file 'lib/lp/translations/browser/potemplate.py' |
500 | --- lib/lp/translations/browser/potemplate.py 2010-02-01 19:19:32 +0000 |
501 | +++ lib/lp/translations/browser/potemplate.py 2010-02-17 09:39:19 +0000 |
502 | @@ -257,7 +257,7 @@ |
503 | |
504 | @property |
505 | def group_parent(self): |
506 | - """Return a parent object implementing `IHasTranslationGroups`.""" |
507 | + """Return a parent object implementing `ITranslationPolicy`.""" |
508 | if self.context.productseries is not None: |
509 | return self.context.productseries.product |
510 | else: |
511 | |
512 | === modified file 'lib/lp/translations/browser/product.py' |
513 | --- lib/lp/translations/browser/product.py 2010-02-03 10:37:32 +0000 |
514 | +++ lib/lp/translations/browser/product.py 2010-02-17 09:39:19 +0000 |
515 | @@ -6,7 +6,7 @@ |
516 | __metaclass__ = type |
517 | |
518 | __all__ = [ |
519 | - 'ProductChangeTranslatorsView', |
520 | + 'ProductSettingsView', |
521 | 'ProductTranslationsMenu', |
522 | 'ProductView', |
523 | ] |
524 | @@ -38,10 +38,10 @@ |
525 | text = 'Import queue' |
526 | return Link('+imports', text) |
527 | |
528 | - @enabled_with_permission('launchpad.Edit') |
529 | + @enabled_with_permission('launchpad.TranslationsAdmin') |
530 | def settings(self): |
531 | - text = 'Settings' |
532 | - return Link('+changetranslators', text, icon='edit') |
533 | + text = 'Change permissions' |
534 | + return Link('+settings', text, icon='edit') |
535 | |
536 | @enabled_with_permission('launchpad.AnyPerson') |
537 | def translationdownload(self): |
538 | @@ -62,13 +62,13 @@ |
539 | return Link(link, text, icon='translation') |
540 | |
541 | |
542 | -class ProductChangeTranslatorsView(TranslationsMixin, ProductEditView): |
543 | +class ProductSettingsView(TranslationsMixin, ProductEditView): |
544 | label = "Set permissions and policies" |
545 | page_title = "Permissions and policies" |
546 | field_names = [ |
547 | "translationgroup", |
548 | "translationpermission", |
549 | - "translation_focus" |
550 | + "translation_focus", |
551 | ] |
552 | |
553 | @property |
554 | |
555 | === modified file 'lib/lp/translations/browser/project.py' |
556 | --- lib/lp/translations/browser/project.py 2009-09-17 12:45:52 +0000 |
557 | +++ lib/lp/translations/browser/project.py 2010-02-17 09:39:19 +0000 |
558 | @@ -6,7 +6,7 @@ |
559 | __metaclass__ = type |
560 | |
561 | __all__ = [ |
562 | - 'ProjectChangeTranslatorsView', |
563 | + 'ProjectSettingsView', |
564 | 'ProjectTranslationsMenu', |
565 | 'ProjectView', |
566 | ] |
567 | @@ -25,10 +25,10 @@ |
568 | facet = 'translations' |
569 | links = ['products', 'settings', 'overview'] |
570 | |
571 | - @enabled_with_permission('launchpad.Edit') |
572 | + @enabled_with_permission('launchpad.TranslationsAdmin') |
573 | def settings(self): |
574 | - text = 'Settings' |
575 | - return Link('+changetranslators', text, icon='edit') |
576 | + text = 'Change permissions' |
577 | + return Link('+settings', text, icon='edit') |
578 | |
579 | def products(self): |
580 | text = 'Products' |
581 | @@ -52,7 +52,7 @@ |
582 | return list(all_products - translatables) |
583 | |
584 | |
585 | -class ProjectChangeTranslatorsView(TranslationsMixin, ProjectEditView): |
586 | +class ProjectSettingsView(TranslationsMixin, ProjectEditView): |
587 | label = "Set permissions and policies" |
588 | page_title = "Permissions and policies" |
589 | field_names = ["translationgroup", "translationpermission"] |
590 | |
591 | === modified file 'lib/lp/translations/browser/translationgroup.py' |
592 | --- lib/lp/translations/browser/translationgroup.py 2010-02-16 20:36:48 +0000 |
593 | +++ lib/lp/translations/browser/translationgroup.py 2010-02-17 09:39:19 +0000 |
594 | @@ -29,8 +29,7 @@ |
595 | from canonical.launchpad.webapp.interfaces import NotFoundError |
596 | from canonical.launchpad.webapp import ( |
597 | action, canonical_url, GetitemNavigation, LaunchpadEditFormView, |
598 | - LaunchpadFormView |
599 | - ) |
600 | + LaunchpadFormView) |
601 | from canonical.launchpad.webapp.breadcrumb import Breadcrumb |
602 | |
603 | |
604 | @@ -77,10 +76,10 @@ |
605 | result.append({'lang': item.language.englishname, |
606 | 'person': item.translator, |
607 | 'code': item.language.code, |
608 | - 'language' : item.language, |
609 | + 'language': item.language, |
610 | 'datecreated': item.datecreated, |
611 | 'style_guide_url': item.style_guide_url, |
612 | - 'context' : item, |
613 | + 'context': item, |
614 | }) |
615 | result.sort(key=operator.itemgetter('lang')) |
616 | return result |
617 | |
618 | === modified file 'lib/lp/translations/interfaces/translationgroup.py' |
619 | --- lib/lp/translations/interfaces/translationgroup.py 2009-08-24 15:35:23 +0000 |
620 | +++ lib/lp/translations/interfaces/translationgroup.py 2010-02-17 09:39:19 +0000 |
621 | @@ -8,7 +8,7 @@ |
622 | __metaclass__ = type |
623 | |
624 | __all__ = [ |
625 | - 'IHasTranslationGroup', |
626 | + 'ITranslationPolicy', |
627 | 'ITranslationGroup', |
628 | 'ITranslationGroupSet', |
629 | 'TranslationPermission', |
630 | @@ -74,7 +74,7 @@ |
631 | to add suggestions.""") |
632 | |
633 | |
634 | -class IHasTranslationGroup(Interface): |
635 | +class ITranslationPolicy(Interface): |
636 | translationgroup = Choice( |
637 | title = _("Translation group"), |
638 | description = _("The translation group that helps review " |
639 | |
640 | === modified file 'lib/lp/translations/stories/translationgroups/46-test-distro-structured-permissions.txt' |
641 | --- lib/lp/translations/stories/translationgroups/46-test-distro-structured-permissions.txt 2009-09-12 07:25:21 +0000 |
642 | +++ lib/lp/translations/stories/translationgroups/46-test-distro-structured-permissions.txt 2010-02-17 09:39:19 +0000 |
643 | @@ -29,7 +29,7 @@ |
644 | ... and its associated project, GNOME. |
645 | |
646 | >>> admin_browser.open( |
647 | - ... 'http://translations.launchpad.dev/gnome/+changetranslators') |
648 | + ... 'http://translations.launchpad.dev/gnome/+settings') |
649 | >>> admin_browser.getControl('Translation group').displayValue = [ |
650 | ... 'Just a testing team'] |
651 | >>> admin_browser.getControl( |
652 | |
653 | === renamed file 'lib/lp/translations/stories/translationgroups/xx-product-translators.txt' => 'lib/lp/translations/stories/translationgroups/xx-change-translation-policy.txt' |
654 | --- lib/lp/translations/stories/translationgroups/xx-product-translators.txt 2009-09-18 15:42:19 +0000 |
655 | +++ lib/lp/translations/stories/translationgroups/xx-change-translation-policy.txt 2010-02-17 09:39:19 +0000 |
656 | @@ -1,13 +1,93 @@ |
657 | -The translation work for a product can be assigned to a translation group. |
658 | - |
659 | - >>> admin_browser.open( |
660 | - ... 'http://translations.launchpad.dev/evolution/+changetranslators') |
661 | - >>> print admin_browser.title |
662 | - Permissions and policies... |
663 | - |
664 | - >>> hint = find_tag_by_id(admin_browser.contents, 'form_extra_info') |
665 | - >>> print hint |
666 | - <p... |
667 | +Translations policy settings |
668 | +============================ |
669 | + |
670 | +A product owner, Rosetta expert, and Ubuntu translations coordinator |
671 | +browser is created. |
672 | + |
673 | + >>> login('admin@canonical.com') |
674 | + >>> product_owner = factory.makePerson( |
675 | + ... email="po@ex.com", password="test") |
676 | + >>> chestii = factory.makeProduct( |
677 | + ... name='chestii', owner=product_owner, official_rosetta=True) |
678 | + >>> logout() |
679 | + >>> dtc_browser = setupDTCBrowser() |
680 | + >>> re_browser = setupRosettaExpertBrowser() |
681 | + >>> po_browser = setupBrowser("Basic po@ex.com:test") |
682 | + |
683 | +Visiting the main products translations page, product owners and Rosetta |
684 | +administrators sees the "Change permissions" link, leading to the |
685 | +translations settings page. |
686 | + |
687 | + >>> re_browser.open( |
688 | + ... 'http://translations.launchpad.dev/chestii') |
689 | + >>> re_browser.getLink('Change permissions').click() |
690 | + >>> print re_browser.url |
691 | + http://translations.launchpad.dev/chestii/+settings |
692 | + |
693 | + >>> po_browser.open( |
694 | + ... 'http://translations.launchpad.dev/chestii') |
695 | + >>> po_browser.getLink('Change permissions').click() |
696 | + >>> print po_browser.url |
697 | + http://translations.launchpad.dev/chestii/+settings |
698 | + |
699 | +From the settings page, translations group and translation permissions |
700 | +can be changed. |
701 | + |
702 | + >>> hint = find_tag_by_id(re_browser.contents, 'form_extra_info') |
703 | + >>> print extract_text(hint) |
704 | Select the translation group that will be managing... |
705 | - ...The Evolution Groupware Application... |
706 | - ... |
707 | + |
708 | + >>> re_browser.getControl('Translation group').value = [ |
709 | + ... 'ubuntu-translators'] |
710 | + >>> re_browser.getControl('Translation permissions policy').value = [ |
711 | + ... 'CLOSED'] |
712 | + >>> re_browser.getControl('Change').click() |
713 | + >>> print re_browser.url |
714 | + http://translations.launchpad.dev/chestii |
715 | + >>> permissions = find_tag_by_id( |
716 | + ... re_browser.contents, 'translation-permissions') |
717 | + >>> print extract_text(permissions) |
718 | + Chestii is translated by Ubuntu Translators with Closed permissions. |
719 | + |
720 | +Other persons, including the translation group owners, will not see the link |
721 | +to translations policy page. |
722 | + |
723 | + >>> dtc_browser.open( |
724 | + ... 'http://translations.launchpad.dev/chestii') |
725 | + >>> dtc_browser.getLink('Change permissions') |
726 | + Traceback (most recent call last): |
727 | + ... |
728 | + LinkNotFoundError... |
729 | + |
730 | +An attempt to access the translations policy url will not be authorized. |
731 | + |
732 | + >>> browser.open( |
733 | + ... 'http://translations.launchpad.dev/chestii/+settings') |
734 | + Traceback (most recent call last): |
735 | + ... |
736 | + Unauthorized... |
737 | + |
738 | + |
739 | +Translations policy for distributions |
740 | +------------------------------------- |
741 | + |
742 | +Ubuntu translation coordinators will have access to translations policy page |
743 | +for Ubuntu and will be able to change it. |
744 | + |
745 | + >>> dtc_browser.open( |
746 | + ... 'http://translations.launchpad.dev/ubuntu') |
747 | + >>> dtc_browser.getLink('Change permissions').click() |
748 | + >>> print dtc_browser.url |
749 | + http://translations.launchpad.dev/ubuntu/+settings |
750 | + |
751 | + >>> dtc_browser.getControl('Translation group').value = [ |
752 | + ... 'ubuntu-translators'] |
753 | + >>> dtc_browser.getControl('Translation permissions policy').value = [ |
754 | + ... 'CLOSED'] |
755 | + >>> dtc_browser.getControl('Change').click() |
756 | + >>> print dtc_browser.url |
757 | + http://translations.launchpad.dev/ubuntu |
758 | + >>> permissions = find_tag_by_id( |
759 | + ... dtc_browser.contents, 'translation-permissions') |
760 | + >>> print extract_text(permissions) |
761 | + Ubuntu is translated by Ubuntu Translators with Closed permissions. |
762 | |
763 | === modified file 'lib/lp/translations/templates/distribution-language-pack-admin-info.pt' |
764 | --- lib/lp/translations/templates/distribution-language-pack-admin-info.pt 2009-09-13 20:24:35 +0000 |
765 | +++ lib/lp/translations/templates/distribution-language-pack-admin-info.pt 2010-02-17 09:39:19 +0000 |
766 | @@ -11,7 +11,7 @@ |
767 | >Mr. No |
768 | </span>. |
769 | <tal:admin |
770 | - condition="context/required:launchpad.Edit"> |
771 | + condition="context/required:launchpad.TranslationsAdmin"> |
772 | <a tal:attributes=" |
773 | href |
774 | context/fmt:url/+select-language-pack-admin" |
775 | @@ -19,7 +19,7 @@ |
776 | </tal:admin> |
777 | </p> |
778 | <tal:admin |
779 | - condition="context/required:launchpad.Edit"> |
780 | + condition="context/required:launchpad.TranslationsAdmin"> |
781 | <p tal:condition="not:context/language_pack_admin"> |
782 | <a tal:attributes=" |
783 | href |
784 | |
785 | === modified file 'lib/lp/translations/templates/hastranslationgroup-portlet-translation-groups-and-permission.pt' |
786 | --- lib/lp/translations/templates/hastranslationgroup-portlet-translation-groups-and-permission.pt 2009-09-10 18:47:57 +0000 |
787 | +++ lib/lp/translations/templates/hastranslationgroup-portlet-translation-groups-and-permission.pt 2010-02-17 09:39:19 +0000 |
788 | @@ -12,10 +12,9 @@ |
789 | tal:content="context/translationpermission/title">certain</a> |
790 | permissions. |
791 | </p> |
792 | - <div tal:condition="context/required:launchpad.Edit"> |
793 | - <a class="edit sprite" |
794 | - tal:define="link context/menu:navigation/settings" |
795 | - tal:attributes="href link/url" |
796 | - >Change permissions</a> |
797 | + <div tal:condition="context/required:launchpad.TranslationsAdmin"> |
798 | + <a tal:replace="structure context/menu:translations/settings/fmt:link"> |
799 | + Change permissions |
800 | + </a> |
801 | </div> |
802 | </div> |
= Bug 127171 =
A Translations Expert (or Rosetta Admin, or the other way around) cannot access the "Change translators" page.
For example, if he/she goes to: https:/ /translations. launchpad. net/pmount/ +translations, the Change translators option is shown, but clicking it result in:
Not allowed here
Sorry, you don't have permission to access this page.
You are logged in as [...]
== Proposed fix ==
Allow Rosetta Admins to edit translation options for a project, a product and a distribution.
== Pre-implementation notes ==
After the fix for bug #422056 landed on edge, the Change translator page has been generalized and it does not include only option to change translations.
Talking with Danilo we decided to rename this page to +settings (see bug 516317).
Talking with Danilo, and as noted in the bug comments, Rosetta Experts should have access to both Product and Distribution settings. Translation group owners should not be able to edit project translation settings.
While Ubuntu is the only distribution using Launchpad Translations, the owners of a translation group will have access only to distributions (to help Ubuntu Translations Coordinators) not to projects using that translation group.
Talking with Jeroen, we decided to rename IHasTranslation Group to ITranslationPolicy as it makes more sense.
== Implementation details == ertBrowser( ) to simplify such tests. I have also improved the previous code for creating a translation group owner browser.
Since we are going to add more pagetests for Rosetta Experts, I have added setupRosettaExp
The launchpad. TranslationAdmi n permission was added for IProduct, IProject and IDistribution allowing Launchpad Admin, Rosetta Admins and owners to edit translation related attributes.
I did not touch the code popping in the lint warnings. Any advice for fixing them is much appreciated.
== Tests ==
lp-test -t permission -t policy
== Demo and Q/A ==
Log in as Rosetta admin (ex <email address hidden>).
Go to a product or project translations page: /translations. launchpad. dev/evolution /translations. launchpad. dev/gnome
ie. https:/
https:/
You should see the „Change permissions” link, be able to access the page and change the values from that page.
Same story for a distribution page: /translations. launchpad. dev/ubuntu
https:/
Login as a normal user you should not be able to see the link of edit the page.
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files: /launchpad/ security. py /launchpad/ testing/ pages.py registry/ configure. zcml registry/ browser/ product. py registry/ interfaces/ distribution. py registry/ interfaces/ product. py registry/ interfaces/ project. py translations/ browser/ configure. zcml translations/ browser/ distribution. py translations/ browser/ potemplate. py translations/ browser/ product. py translations/ browser/ project. py translations/ browser/ translationgrou p.py translations/ interfaces/ translationgrou p.py translations/ stories/ translation. ..
lib/canonical
lib/canonical
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/