Merge lp:~adiroiban/launchpad/bug-509252-take-2 into lp:launchpad
- bug-509252-take-2
- Merge into devel
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Henning Eggers | ||||
Approved revision: | not available | ||||
Merged at revision: | not available | ||||
Proposed branch: | lp:~adiroiban/launchpad/bug-509252-take-2 | ||||
Merge into: | lp:launchpad | ||||
Diff against target: |
760 lines (+184/-213) 11 files modified
lib/canonical/launchpad/security.py (+0/-15) lib/lp/registry/browser/distroseries.py (+9/-17) lib/lp/registry/browser/sourcepackage.py (+8/-4) lib/lp/registry/doc/distroseries.txt (+18/-76) lib/lp/registry/interfaces/distroseries.py (+4/-13) lib/lp/registry/model/distroseries.py (+12/-37) lib/lp/translations/browser/browser_helpers.py (+4/-6) lib/lp/translations/browser/distroseries.py (+52/-29) lib/lp/translations/browser/tests/distroseries-views.txt (+69/-11) lib/lp/translations/stories/distroseries/xx-distroseries-translations.txt (+3/-5) lib/lp/translations/templates/distroseries-langchart.pt (+5/-0) |
||||
To merge this branch: | bzr merge lp:~adiroiban/launchpad/bug-509252-take-2 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Henning Eggers (community) | code | Approve | |
Michael Nelson (community) | code | Needs Information | |
Review via email: mp+19484@code.launchpad.net |
Commit message
Refactor checkTranslatio
Description of the change
Adi Roiban (adiroiban) wrote : | # |
Michael Nelson (michael.nelson) wrote : | # |
Hi Adi,
Thanks for all the cleanups that you've done in this branch.
After reading the recent email discussion at:
https:/
and particularly BjornT's message:
https:/
I don't think putting the security check into a browser helper is the way to go.
As outlined in the above email:
"The current solution is to have this code in model code, and have the
security adapter ask the model. No code duplication really."
this ensures that any security can be applied not only in the view, but also via other modes of access (API), even if they are not yet enabled.
As it turns out in your code, it seems most of IDistroSeries.
So I wonder if we can do something like this:
http://
That is, simply add a launchpad.View check for IDistroSeriesLa
if not check_permission(
could be replaced simply by:
if not check_permission(
that way you'd have all the security in the right place, separate from the error generation (ie. translation_
I'm not 100%, but as far as I can see, the above should do what you're after while at the same time keeping all the security code in the one place. But I'll check with Henninge to be sure (hence marking this as needs info).
IRC log of conversation starts at:
http://
Michael Nelson (michael.nelson) wrote : | # |
OK, I spoke to Adi, and he said that the security for IDistroSeriesLa
Without this, I can't see a way to keep these security checks encapsulated in security.py or on the model. I'm going to have to defer to Danilo or Henninge.
Henning Eggers (henninge) wrote : | # |
Hi Adi,
thanks for cleaning this up. Your code is almost good, I'd just ask two changes of you.
I agree with Michael's point that check_distroser
The code in check_distroser
Something that was already wrong before this branch but that should be cleaned up is this: DistroSeriesVie
So my first request is that you find a new implementation for DistroSeriesVie
My other request is that you move check_distroser
Finally I noticed DistroSeries.
Thanks. ;-)
Adi Roiban (adiroiban) wrote : | # |
DistroSeriesVie
<metal:
If we want to remove this behavior, we would need to raise those exception in Distribution URL traversal for series... and then things will get a bit complicated as those exception should be raised only for „translations” facet.
-------
There are a couple of view tests in translations/
-----
Thanks for the getDistroSeries
Henning Eggers (henninge) wrote : | # |
Hi Adi,
sorry for not replying but I had expected that you push an updated branch with whatever changes you see possible.
I did not know that metal tags are being used to raise exceptions and I am pretty sure that should not be that way. If you think it's too much work to improve that in this branch, I can understand that. Please file a bug so that it gets done at some later time.
So, a new push to the branch would be the next thing to get the review forward.
Cheers,
Henning
Adi Roiban (adiroiban) wrote : | # |
Hi,
Don't worry about the communication problem ... be happy :)
I have opened a new bug for TAL expression used for raising an exception.
I have merged the tests for translation permissions.
Here is the diff. Thanks!
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -37,10 +37,8 @@
from lp.services.
from lp.registry.
from lp.registry.
-from lp.translations
+from lp.translations
check_
-from lp.translations
- IDistroSeriesLa
from lp.services.
from lp.registry.
Structural
@@ -81,19 +79,12 @@
except IndexError:
# Unknown language code.
raise NotFoundError
- distroserieslang = self.context.
- if distroserieslang is None:
- # There is no IDistroSeriesLa
- # but we still need to list it as an available language, so we
- # generate a dummy one so users have a chance to get to it in the
- # navigation and start adding translations for it.
- distroserieslangset = getUtility(
- distroserieslang = distroserieslan
- self.context, lang)
+ distroserieslang = self.context.
# Check if user is able to view the translations for
- # this distribution series
+ # this distribution series language.
+ # If not, raise TranslationUnav
return distroserieslang
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -40,7 +40,7 @@
from lp.registry.
from lp.registry.
from lp.registry.
-from lp.translations
+from lp.translations
check_
from lp.translations
from canonical.launchpad import _
@@ -68,7 +68,8 @@
# If we are able to view the translations for distribution series
# we should also be allowed to see them for a distribution
- # source package
+ # source package.
+ # If not, raise TranslationUnav
return sourcepackage_pots
=== modified file 'lib/lp/
Henning Eggers (henninge) wrote : | # |
Thanks, this looks much better. Unfortunately the diff shows conflicts, so I guess you need to merge devel and push again for the diff to be correct.
Also, is there no unit test that could go through all the different SeriesStatus values? Doing this in a doc test looks like it's in the wrong place. But please only do this if it is fairly easy. I think this branch is already old enough ... ;-)
Adi Roiban (adiroiban) wrote : | # |
În data de Mi, 24-02-2010 la 17:42 +0000, Henning Eggers a scris:
> Thanks, this looks much better. Unfortunately the diff shows
> conflicts, so I guess you need to merge devel and push again for the
> diff to be correct.
Conflict solved.
> Also, is there no unit test that could go through all the different
> SeriesStatus values? Doing this in a doc test looks like it's in the
> wrong place. But please only do this if it is fairly easy. I think
> this branch is already old enough ... ;-)
I was thinking that view unit tests should be put in:
lib/lp/
translations/
I have just moved those tests from registry/
file.
Are you saying that we should not write unit tests using doctest format?
Cheers
--
Adi Roiban
Henning Eggers (henninge) wrote : | # |
> Conflict solved.
Cool, looks good. ;)
> Are you saying that we should not write unit tests using doctest format?
Yes, at least that's what I do. They execute slower, don't they? But as you pointed out, the test was already there, so you just extended it. That's what I do, too ... ;) So you can keep it as it is if you want to.
Thanks for the extra comments in the code, btw. And all the clean-up work!
You have a double "allowed allowed" in there somewhere, btw.
Cheers,
Henning
Adi Roiban (adiroiban) wrote : | # |
În data de Mi, 24-02-2010 la 18:27 +0000, Henning Eggers a scris:
> Review: Approve code
> > Conflict solved.
>
> Cool, looks good. ;)
>
>
> > Are you saying that we should not write unit tests using doctest format?
>
> Yes, at least that's what I do. They execute slower, don't they? But
> as you pointed out, the test was already there, so you just extended
> it. That's what I do, too ... ;) So you can keep it as it is if you
> want to.
OK. This is not the only unit test written in doctest format.
$ ls lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
Maybe we should open a bug to convert all those test from doctest to
"pure" python code.
> Thanks for the extra comments in the code, btw. And all the clean-up
> work!
> You have a double "allowed allowed" in there somewhere, btw.
Typo fixed and pushed.
When you have time, can you please send this branch to ec2 test?
Kindest regards,
--
Adi Roiban
Henning Eggers (henninge) wrote : | # |
I am having trouble landing this. First, there is the current problem with ec2 test not sending emails, so the failure was kind of obscure. Secondly, after merging the current devel, it failed because "python-
Now, this error remains when running "make build":
ZopeXMLConf
ImportError: cannot import name check_distroser
Adi Roiban (adiroiban) wrote : | # |
Hm...
I did not get the „python-
I have fixed the problem and pushed the branch.
Preview Diff
1 | === modified file 'lib/canonical/launchpad/security.py' |
2 | --- lib/canonical/launchpad/security.py 2010-02-24 23:02:56 +0000 |
3 | +++ lib/canonical/launchpad/security.py 2010-03-01 23:03:20 +0000 |
4 | @@ -49,8 +49,6 @@ |
5 | from lp.registry.interfaces.distributionsourcepackage import ( |
6 | IDistributionSourcePackage) |
7 | from lp.registry.interfaces.distroseries import IDistroSeries |
8 | -from lp.translations.interfaces.distroserieslanguage import ( |
9 | - IDistroSeriesLanguage) |
10 | from lp.registry.interfaces.entitlement import IEntitlement |
11 | from lp.hardwaredb.interfaces.hwdb import ( |
12 | IHWDBApplication, IHWDevice, IHWDeviceClass, IHWDriver, IHWDriverName, |
13 | @@ -1664,19 +1662,6 @@ |
14 | self.obj.distribution).checkAuthenticated(user)) |
15 | |
16 | |
17 | -class AdminDistroSeriesLanguage(AuthorizationBase): |
18 | - permission = 'launchpad.TranslationsAdmin' |
19 | - usedfor = IDistroSeriesLanguage |
20 | - |
21 | - def checkAuthenticated(self, user): |
22 | - """Is the user able to manage `IDistroSeriesLanguage` translations. |
23 | - |
24 | - Distribution managers can also manage IDistroSeriesLanguage |
25 | - """ |
26 | - return (AdminDistroSeriesTranslations( |
27 | - self.obj.distroseries).checkAuthenticated(user)) |
28 | - |
29 | - |
30 | class BranchSubscriptionEdit(AuthorizationBase): |
31 | permission = 'launchpad.Edit' |
32 | usedfor = IBranchSubscription |
33 | |
34 | === modified file 'lib/lp/registry/browser/distroseries.py' |
35 | --- lib/lp/registry/browser/distroseries.py 2010-02-26 19:15:17 +0000 |
36 | +++ lib/lp/registry/browser/distroseries.py 2010-03-01 23:03:20 +0000 |
37 | @@ -37,8 +37,8 @@ |
38 | from lp.services.worlddata.interfaces.country import ICountry |
39 | from lp.registry.interfaces.series import SeriesStatus |
40 | from lp.registry.interfaces.distroseries import IDistroSeries |
41 | -from lp.translations.interfaces.distroserieslanguage import ( |
42 | - IDistroSeriesLanguageSet) |
43 | +from lp.translations.browser.distroseries import ( |
44 | + check_distroseries_translations_viewable) |
45 | from lp.services.worlddata.interfaces.language import ILanguageSet |
46 | from lp.registry.browser.structuralsubscription import ( |
47 | StructuralSubscriptionMenuMixin, |
48 | @@ -48,7 +48,6 @@ |
49 | from canonical.launchpad.webapp import ( |
50 | StandardLaunchpadFacets, GetitemNavigation, action, custom_widget) |
51 | from canonical.launchpad.webapp.batching import BatchNavigator |
52 | -from canonical.launchpad.webapp.authorization import check_permission |
53 | from canonical.launchpad.webapp.breadcrumb import Breadcrumb |
54 | from canonical.launchpad.webapp.launchpadform import ( |
55 | LaunchpadEditFormView, LaunchpadFormView) |
56 | @@ -80,20 +79,13 @@ |
57 | except IndexError: |
58 | # Unknown language code. |
59 | raise NotFoundError |
60 | - distroserieslang = self.context.getDistroSeriesLanguage(lang) |
61 | - |
62 | - if distroserieslang is None: |
63 | - # There is no IDistroSeriesLanguage yet for this IDistroSeries, |
64 | - # but we still need to list it as an available language, so we |
65 | - # generate a dummy one so users have a chance to get to it in the |
66 | - # navigation and start adding translations for it. |
67 | - distroserieslangset = getUtility(IDistroSeriesLanguageSet) |
68 | - distroserieslang = distroserieslangset.getDummy( |
69 | - self.context, lang) |
70 | - |
71 | - if not check_permission( |
72 | - 'launchpad.TranslationsAdmin', distroserieslang): |
73 | - self.context.checkTranslationsViewable() |
74 | + |
75 | + distroserieslang = self.context.getDistroSeriesLanguageOrDummy(lang) |
76 | + |
77 | + # Check if user is able to view the translations for |
78 | + # this distribution series language. |
79 | + # If not, raise TranslationUnavailable. |
80 | + check_distroseries_translations_viewable(self.context) |
81 | |
82 | return distroserieslang |
83 | |
84 | |
85 | === modified file 'lib/lp/registry/browser/sourcepackage.py' |
86 | --- lib/lp/registry/browser/sourcepackage.py 2010-02-23 19:43:58 +0000 |
87 | +++ lib/lp/registry/browser/sourcepackage.py 2010-03-01 23:03:20 +0000 |
88 | @@ -52,7 +52,6 @@ |
89 | action, ApplicationMenu, custom_widget, GetitemNavigation, |
90 | LaunchpadFormView, Link, redirection, StandardLaunchpadFacets, stepto) |
91 | from canonical.launchpad.webapp import canonical_url |
92 | -from canonical.launchpad.webapp.authorization import check_permission |
93 | from canonical.launchpad.webapp.breadcrumb import Breadcrumb |
94 | from canonical.launchpad.webapp.menu import structured |
95 | |
96 | @@ -70,9 +69,13 @@ |
97 | distroseries=self.context.distroseries, |
98 | sourcepackagename=self.context.sourcepackagename) |
99 | |
100 | - if not check_permission( |
101 | - 'launchpad.TranslationsAdmin', sourcepackage_pots): |
102 | - self.context.distroseries.checkTranslationsViewable() |
103 | + # If we are able to view the translations for distribution series |
104 | + # we should also be allowed to see them for a distribution |
105 | + # source package. |
106 | + # If not, raise TranslationUnavailable. |
107 | + from lp.translations.browser.distroseries import ( |
108 | + check_distroseries_translations_viewable) |
109 | + check_distroseries_translations_viewable(self.context.distroseries) |
110 | |
111 | return sourcepackage_pots |
112 | |
113 | @@ -92,6 +95,7 @@ |
114 | |
115 | class SourcePackageBreadcrumb(Breadcrumb): |
116 | """Builds a breadcrumb for an `ISourcePackage`.""" |
117 | + |
118 | @property |
119 | def text(self): |
120 | return smartquote('"%s" source package') % (self.context.name) |
121 | |
122 | === modified file 'lib/lp/registry/doc/distroseries.txt' |
123 | --- lib/lp/registry/doc/distroseries.txt 2010-02-25 16:27:34 +0000 |
124 | +++ lib/lp/registry/doc/distroseries.txt 2010-03-01 23:03:20 +0000 |
125 | @@ -1,4 +1,5 @@ |
126 | -= DistroSeries = |
127 | +DistroSeries |
128 | +============ |
129 | |
130 | From the DerivationOverview spec |
131 | <https://launchpad.canonical.com/DerivationOverview>: |
132 | @@ -200,7 +201,8 @@ |
133 | True |
134 | |
135 | |
136 | -== Package searching == |
137 | +Package searching |
138 | +----------------- |
139 | |
140 | You can search through binary packages publishing in a distribution |
141 | release by using the searchPackages method, which uses magical fti: |
142 | @@ -223,7 +225,8 @@ |
143 | DistroSeriesBinaryPackage: at |
144 | |
145 | |
146 | -== DistroSeriess have components and sections == |
147 | +DistroSeriess have components and sections |
148 | +------------------------------------------ |
149 | |
150 | A distroseries has some number of components and/or sections which |
151 | are valid for that distroseries. These selections are used by (among |
152 | @@ -286,7 +289,8 @@ |
153 | partner |
154 | |
155 | |
156 | -== DistroSeries can be initialised from their parents == |
157 | +DistroSeries can be initialised from their parents |
158 | +-------------------------------------------------- |
159 | |
160 | When a distroseries is derived from another distroseries (be it a |
161 | derivative distribution, or simply the next release in a sequence from |
162 | @@ -396,74 +400,8 @@ |
163 | netapplet |
164 | |
165 | |
166 | -Hiding translations |
167 | -------------------- |
168 | - |
169 | -The hide_all_translations flag, if set, hides a distroseries' |
170 | -translations in the user interface. The check for visibility happens in |
171 | -checkTranslationsViewable. |
172 | - |
173 | - >>> untranslatable_series = factory.makeDistroRelease() |
174 | - >>> untranslatable_series.hide_all_translations = False |
175 | - |
176 | -When translations are visible, checkTranslationsViewable() completes |
177 | -normally. |
178 | - |
179 | - >>> from canonical.launchpad.webapp.interfaces import ( |
180 | - ... TranslationUnavailable) |
181 | - >>> def get_visibility_notice(series): |
182 | - ... """Print the notice about series' translations being hidden.""" |
183 | - ... try: |
184 | - ... series.checkTranslationsViewable() |
185 | - ... except TranslationUnavailable, e: |
186 | - ... return str(e) |
187 | - ... return None |
188 | - |
189 | - >>> print get_visibility_notice(untranslatable_series) |
190 | - None |
191 | - |
192 | -But when translations are hidden, it raises TranslationUnavailable. |
193 | - |
194 | - >>> untranslatable_series.hide_all_translations = True |
195 | - >>> print get_visibility_notice(untranslatable_series) |
196 | - Translations for this release series... |
197 | - |
198 | -Exactly what message is displayed depends on the series' status. |
199 | - |
200 | - >>> untranslatable_series.status = SeriesStatus.EXPERIMENTAL |
201 | - >>> print get_visibility_notice(untranslatable_series) |
202 | - Translations for this release series are not available yet. |
203 | - |
204 | - >>> untranslatable_series.status = SeriesStatus.DEVELOPMENT |
205 | - >>> print get_visibility_notice(untranslatable_series) |
206 | - Translations for this release series are not available yet. |
207 | - |
208 | - >>> untranslatable_series.status = SeriesStatus.FROZEN |
209 | - >>> print get_visibility_notice(untranslatable_series) |
210 | - Translations for this release series are not currently available. |
211 | - Please come back soon. |
212 | - |
213 | - >>> untranslatable_series.status = SeriesStatus.CURRENT |
214 | - >>> print get_visibility_notice(untranslatable_series) |
215 | - Translations for this release series are not currently available. |
216 | - Please come back soon. |
217 | - |
218 | - >>> untranslatable_series.status = SeriesStatus.SUPPORTED |
219 | - >>> print get_visibility_notice(untranslatable_series) |
220 | - Translations for this release series are not currently available. |
221 | - Please come back soon. |
222 | - |
223 | - >>> untranslatable_series.status = SeriesStatus.OBSOLETE |
224 | - >>> print get_visibility_notice(untranslatable_series) |
225 | - This release series is obsolete. Its translations are no longer |
226 | - available. |
227 | - |
228 | - >>> untranslatable_series.status = SeriesStatus.FUTURE |
229 | - >>> print get_visibility_notice(untranslatable_series) |
230 | - Translations for this release series are not available yet. |
231 | - |
232 | - |
233 | -== Translatable Packages and Packaging == |
234 | +Translatable Packages and Packaging |
235 | +----------------------------------- |
236 | |
237 | You can easily find out what packages are translatable in a |
238 | distribution release: |
239 | @@ -668,7 +606,8 @@ |
240 | True |
241 | |
242 | |
243 | -== SourcePackagePublishingHistory == |
244 | +SourcePackagePublishingHistory |
245 | +------------------------------ |
246 | |
247 | IDistroSeries.getSourcePackagePublishing returns all the ISPPH |
248 | records for a given status in a given pocket. It makes easy to |
249 | @@ -1042,7 +981,8 @@ |
250 | thinclient-local-devices |
251 | |
252 | |
253 | -= Drivers = |
254 | +Drivers |
255 | +======= |
256 | |
257 | Distributions have drivers, who are people that have permission to approve |
258 | bugs and features for specific releases. The rules are that: |
259 | @@ -1124,7 +1064,8 @@ |
260 | mark |
261 | |
262 | |
263 | -== Lastest Uploads == |
264 | +Lastest Uploads |
265 | +--------------- |
266 | |
267 | IDistroSeries provides the 'getLatestUpload' method which returns a |
268 | list of the last 5 (five) IDistroSeriesSourcePackageRelease (IDRSPR) |
269 | @@ -1150,7 +1091,8 @@ |
270 | 0 |
271 | |
272 | |
273 | -== Getting build records for a distro series == |
274 | +Getting build records for a distro series |
275 | +----------------------------------------- |
276 | |
277 | IDistroSeries inherits the IHasBuildRecords interfaces and therefore provides |
278 | a getBuildRecords() method. |
279 | |
280 | === modified file 'lib/lp/registry/interfaces/distroseries.py' |
281 | --- lib/lp/registry/interfaces/distroseries.py 2010-02-27 10:19:18 +0000 |
282 | +++ lib/lp/registry/interfaces/distroseries.py 2010-03-01 23:03:20 +0000 |
283 | @@ -54,6 +54,7 @@ |
284 | from lp.translations.interfaces.languagepack import ILanguagePack |
285 | |
286 | |
287 | + |
288 | class DistroSeriesNameField(ContentNameField): |
289 | """A class to ensure `IDistroSeries` has unique names.""" |
290 | errormessage = _("%s is already in use by another series.") |
291 | @@ -132,6 +133,7 @@ |
292 | |
293 | class IDistroSeriesEditRestricted(Interface): |
294 | """IDistroSeries properties which require launchpad.Edit.""" |
295 | + |
296 | @rename_parameters_as(dateexpected='date_targeted') |
297 | @export_factory_operation( |
298 | IMilestone, ['name', 'dateexpected', 'summary', 'code_name']) |
299 | @@ -198,7 +200,7 @@ |
300 | Interface, # Really IDistribution, see circular import fix below. |
301 | title=_("Distribution"), required=True, |
302 | description=_("The distribution for which this is a series."))) |
303 | - named_version = Attribute('The combined display name and version.') |
304 | + named_version = Attribute('The combined display name and version.') |
305 | parent = Attribute('The structural parent of this series - the distro') |
306 | components = Attribute("The series components.") |
307 | upload_components = Attribute("The series components that can be " |
308 | @@ -240,7 +242,7 @@ |
309 | title=_("Defer translation imports"), |
310 | description=_("Suspends any translation imports for this series"), |
311 | default=True, |
312 | - required=True |
313 | + required=True, |
314 | ) |
315 | binarycount = Attribute("Binary Packages Counter") |
316 | |
317 | @@ -497,17 +499,6 @@ |
318 | :return: A result set containing `IPackageUpload` |
319 | """ |
320 | |
321 | - def checkTranslationsViewable(): |
322 | - """Raise `TranslationUnavailable` if translations are hidden. |
323 | - |
324 | - Checks the `hide_all_translations` flag. If it is set, these |
325 | - translations are not to be shown to the public. In that case an |
326 | - appropriate message is composed based on the series' `status`, |
327 | - and a `TranslationUnavailable` exception is raised. |
328 | - |
329 | - Simply returns if translations are not hidden. |
330 | - """ |
331 | - |
332 | def getUnlinkedTranslatableSourcePackages(): |
333 | """Return a list of source packages that can be translated in |
334 | this distribution series but which lack Packaging links. |
335 | |
336 | === modified file 'lib/lp/registry/model/distroseries.py' |
337 | --- lib/lp/registry/model/distroseries.py 2010-02-25 16:27:34 +0000 |
338 | +++ lib/lp/registry/model/distroseries.py 2010-03-01 23:03:20 +0000 |
339 | @@ -118,8 +118,7 @@ |
340 | from canonical.launchpad.mail import signed_message_from_string |
341 | from lp.registry.interfaces.person import validate_public_person |
342 | from canonical.launchpad.webapp.interfaces import ( |
343 | - IStoreSelector, MAIN_STORE, NotFoundError, SLAVE_FLAVOR, |
344 | - TranslationUnavailable) |
345 | + IStoreSelector, MAIN_STORE, NotFoundError, SLAVE_FLAVOR) |
346 | from lp.soyuz.interfaces.sourcepackageformat import ( |
347 | ISourcePackageFormatSelectionSet) |
348 | |
349 | @@ -134,7 +133,7 @@ |
350 | SeriesStatus.DEVELOPMENT, |
351 | SeriesStatus.FROZEN, |
352 | SeriesStatus.CURRENT, |
353 | - SeriesStatus.SUPPORTED |
354 | + SeriesStatus.SUPPORTED, |
355 | ] |
356 | |
357 | |
358 | @@ -162,7 +161,7 @@ |
359 | dbName='releasestatus', notNull=True, schema=SeriesStatus) |
360 | date_created = UtcDateTimeCol(notNull=False, default=UTC_NOW) |
361 | datereleased = UtcDateTimeCol(notNull=False, default=None) |
362 | - parent_series = ForeignKey( |
363 | + parent_series = ForeignKey( |
364 | dbName='parent_series', foreignKey='DistroSeries', notNull=False) |
365 | owner = ForeignKey( |
366 | dbName='owner', foreignKey='Person', |
367 | @@ -173,7 +172,7 @@ |
368 | lucilleconfig = StringCol(notNull=False, default=None) |
369 | changeslist = StringCol(notNull=False, default=None) |
370 | nominatedarchindep = ForeignKey( |
371 | - dbName='nominatedarchindep',foreignKey='DistroArchSeries', |
372 | + dbName='nominatedarchindep', foreignKey='DistroArchSeries', |
373 | notNull=False, default=None) |
374 | messagecount = IntCol(notNull=True, default=0) |
375 | binarycount = IntCol(notNull=True, default=DEFAULT) |
376 | @@ -751,7 +750,7 @@ |
377 | |
378 | # filter based on completion. see the implementation of |
379 | # Specification.is_complete() for more details |
380 | - completeness = Specification.completeness_clause |
381 | + completeness = Specification.completeness_clause |
382 | |
383 | if SpecificationFilter.COMPLETE in filter: |
384 | query += ' AND ( %s ) ' % completeness |
385 | @@ -886,29 +885,6 @@ |
386 | DistroSeriesSourcePackageRelease(self, release)) |
387 | for release in releases) |
388 | |
389 | - def checkTranslationsViewable(self): |
390 | - """See `IDistroSeries`.""" |
391 | - if not self.hide_all_translations: |
392 | - # Yup, viewable. |
393 | - return |
394 | - |
395 | - future = [ |
396 | - SeriesStatus.EXPERIMENTAL, |
397 | - SeriesStatus.DEVELOPMENT, |
398 | - SeriesStatus.FUTURE, |
399 | - ] |
400 | - if self.status in future: |
401 | - raise TranslationUnavailable( |
402 | - "Translations for this release series are not available yet.") |
403 | - elif self.status == SeriesStatus.OBSOLETE: |
404 | - raise TranslationUnavailable( |
405 | - "This release series is obsolete. Its translations are no " |
406 | - "longer available.") |
407 | - else: |
408 | - raise TranslationUnavailable( |
409 | - "Translations for this release series are not currently " |
410 | - "available. Please come back soon.") |
411 | - |
412 | def getTranslatableSourcePackages(self): |
413 | """See `IDistroSeries`.""" |
414 | query = """ |
415 | @@ -1069,13 +1045,12 @@ |
416 | SourcePackagePublishingHistory.archive IN %s AND |
417 | SourcePackagePublishingHistory.status=%s AND |
418 | SourcePackagePublishingHistory.pocket=%s |
419 | - """ % sqlvalues(self, archives, status, pocket) |
420 | + """ % sqlvalues(self, archives, status, pocket) |
421 | |
422 | if component: |
423 | clause += ( |
424 | " AND SourcePackagePublishingHistory.component=%s" |
425 | - % sqlvalues(component) |
426 | - ) |
427 | + % sqlvalues(component)) |
428 | |
429 | orderBy = ['SourcePackageName.name'] |
430 | clauseTables = ['SourcePackageRelease', 'SourcePackageName'] |
431 | @@ -1136,7 +1111,7 @@ |
432 | |
433 | clauseTables = ['BinaryPackagePublishingHistory', 'DistroArchSeries', |
434 | 'BinaryPackageRelease', 'BinaryPackageName', 'Build', |
435 | - 'SourcePackageRelease', 'SourcePackageName' ] |
436 | + 'SourcePackageRelease', 'SourcePackageName'] |
437 | |
438 | result = BinaryPackagePublishingHistory.select( |
439 | query, distinct=False, clauseTables=clauseTables, orderBy=orderBy) |
440 | @@ -1971,8 +1946,9 @@ |
441 | return '%s%s' % (self.name, pocketsuffix[pocket]) |
442 | |
443 | def isSourcePackageFormatPermitted(self, format): |
444 | - return getUtility(ISourcePackageFormatSelectionSet |
445 | - ).getBySeriesAndFormat(self, format) is not None |
446 | + return getUtility( |
447 | + ISourcePackageFormatSelectionSet).getBySeriesAndFormat( |
448 | + self, format) is not None |
449 | |
450 | |
451 | class DistroSeriesSet: |
452 | @@ -1990,8 +1966,7 @@ |
453 | result_set = store.using((DistroSeries, POTemplate)).find( |
454 | DistroSeries, |
455 | DistroSeries.hide_all_translations == False, |
456 | - DistroSeries.id == POTemplate.distroseriesID |
457 | - ).config(distinct=True) |
458 | + DistroSeries.id == POTemplate.distroseriesID).config(distinct=True) |
459 | # XXX: henninge 2009-02-11 bug=217644: Convert to sequence right here |
460 | # because ResultSet reports a wrong count() when using DISTINCT. Also |
461 | # ResultSet does not implement __len__(), which would make it more |
462 | |
463 | === modified file 'lib/lp/translations/browser/browser_helpers.py' |
464 | --- lib/lp/translations/browser/browser_helpers.py 2009-09-04 11:54:50 +0000 |
465 | +++ lib/lp/translations/browser/browser_helpers.py 2010-03-01 23:03:20 +0000 |
466 | @@ -30,16 +30,16 @@ |
467 | """Replace Rosetta escape sequences with the real characters.""" |
468 | return helpers.text_replaced(text, {'[tab]': '\t', |
469 | r'\[tab]': '[tab]', |
470 | - '[nbsp]' : u'\u00a0', |
471 | - r'\[nbsp]' : '[nbsp]' }) |
472 | + '[nbsp]': u'\u00a0', |
473 | + r'\[nbsp]': '[nbsp]'}) |
474 | |
475 | |
476 | def expand_rosetta_escapes(unicode_text): |
477 | """Replace characters needing a Rosetta escape sequences.""" |
478 | escapes = {u'\t': TranslationConstants.TAB_CHAR, |
479 | u'[tab]': TranslationConstants.TAB_CHAR_ESCAPED, |
480 | - u'\u00a0' : TranslationConstants.NO_BREAK_SPACE_CHAR, |
481 | - u'[nbsp]' : TranslationConstants.NO_BREAK_SPACE_CHAR_ESCAPED } |
482 | + u'\u00a0': TranslationConstants.NO_BREAK_SPACE_CHAR, |
483 | + u'[nbsp]': TranslationConstants.NO_BREAK_SPACE_CHAR_ESCAPED} |
484 | return helpers.text_replaced(unicode_text, escapes) |
485 | |
486 | |
487 | @@ -187,5 +187,3 @@ |
488 | raise UnrecognisedCFormatString(string) |
489 | |
490 | return segments |
491 | - |
492 | - |
493 | |
494 | === modified file 'lib/lp/translations/browser/distroseries.py' |
495 | --- lib/lp/translations/browser/distroseries.py 2010-02-02 15:32:00 +0000 |
496 | +++ lib/lp/translations/browser/distroseries.py 2010-03-01 23:03:20 +0000 |
497 | @@ -11,15 +11,16 @@ |
498 | 'DistroSeriesTranslationsAdminView', |
499 | 'DistroSeriesTranslationsMenu', |
500 | 'DistroSeriesView', |
501 | + 'check_distroseries_translations_viewable', |
502 | ] |
503 | |
504 | from zope.component import getUtility |
505 | |
506 | from canonical.cachedproperty import cachedproperty |
507 | from canonical.launchpad import helpers |
508 | -from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
509 | from canonical.launchpad.webapp import action |
510 | from canonical.launchpad.webapp.authorization import check_permission |
511 | +from canonical.launchpad.webapp.interfaces import TranslationUnavailable |
512 | from canonical.launchpad.webapp.launchpadform import LaunchpadEditFormView |
513 | from canonical.launchpad.webapp.menu import ( |
514 | Link, NavigationMenu, enabled_with_permission) |
515 | @@ -27,6 +28,7 @@ |
516 | canonical_url, LaunchpadView) |
517 | |
518 | from lp.registry.interfaces.distroseries import IDistroSeries |
519 | +from lp.registry.interfaces.series import SeriesStatus |
520 | from lp.translations.browser.translations import TranslationsMixin |
521 | from lp.translations.browser.potemplate import BaseSeriesTemplatesView |
522 | from lp.translations.interfaces.distroserieslanguage import ( |
523 | @@ -175,34 +177,11 @@ |
524 | self.context.version) |
525 | |
526 | def checkTranslationsViewable(self): |
527 | - """Check that these translations are visible to the current user. |
528 | - |
529 | - Launchpad admins, Translations admins, and users with admin |
530 | - rights on the `DistroSeries` are always allowed. For others |
531 | - this delegates to `IDistroSeries.checkTranslationsViewable`, |
532 | - which raises `TranslationUnavailable` if the translations are |
533 | - set to be hidden. |
534 | - |
535 | - :return: Returns normally if this series' translations are |
536 | - viewable to the current user. |
537 | - :raise TranslationUnavailable: if this series' translations are |
538 | - hidden and the user is not one of the limited caste that is |
539 | - allowed to access them. |
540 | - """ |
541 | - if check_permission('launchpad.TranslationsAdmin', self.context): |
542 | - # Anyone with admin rights on this series passes. This |
543 | - # includes Launchpad admins. |
544 | - return |
545 | - |
546 | - user = self.user |
547 | - experts = getUtility(ILaunchpadCelebrities).rosetta_experts |
548 | - if user is not None and user.inTeam(experts): |
549 | - # Translations admins also pass. |
550 | - return |
551 | - |
552 | - # Everyone else passes only if translations are viewable to the |
553 | - # public. |
554 | - self.context.checkTranslationsViewable() |
555 | + """ Check if user can view translations for this `IDistroSeries`""" |
556 | + |
557 | + # Is user allowed to see translations for this distroseries? |
558 | + # If not, raise TranslationUnavailable. |
559 | + check_distroseries_translations_viewable(self.context) |
560 | |
561 | def distroserieslanguages(self): |
562 | """Produces a list containing a DistroSeriesLanguage object for |
563 | @@ -271,3 +250,47 @@ |
564 | |
565 | def language_packs(self): |
566 | return Link('+language-packs', 'Language packs') |
567 | + |
568 | + |
569 | +def check_distroseries_translations_viewable(distroseries): |
570 | + """Check that these distribution series translations are visible. |
571 | + |
572 | + Launchpad admins, Translations admins, and users with admin |
573 | + rights on the `IDistroSeries` are always allowed. |
574 | + |
575 | + Checks the `hide_all_translations` flag. If it is set, these |
576 | + translations are not to be shown to the public. In that case an |
577 | + appropriate message is composed based on the series' `status`, |
578 | + and a `TranslationUnavailable` exception is raised. |
579 | + |
580 | + :return: Returns normally if this series' translations are |
581 | + viewable to the current user. |
582 | + :raise TranslationUnavailable: if this series' translations are |
583 | + hidden and the user is not one of the limited caste that is |
584 | + allowed to access them. |
585 | + """ |
586 | + |
587 | + if not distroseries.hide_all_translations: |
588 | + # Yup, viewable. |
589 | + return |
590 | + |
591 | + if check_permission( |
592 | + 'launchpad.TranslationsAdmin', distroseries): |
593 | + return |
594 | + |
595 | + future = [ |
596 | + SeriesStatus.EXPERIMENTAL, |
597 | + SeriesStatus.DEVELOPMENT, |
598 | + SeriesStatus.FUTURE, |
599 | + ] |
600 | + if distroseries.status in future: |
601 | + raise TranslationUnavailable( |
602 | + "Translations for this release series are not available yet.") |
603 | + elif distroseries.status == SeriesStatus.OBSOLETE: |
604 | + raise TranslationUnavailable( |
605 | + "This release series is obsolete. Its translations are no " |
606 | + "longer available.") |
607 | + else: |
608 | + raise TranslationUnavailable( |
609 | + "Translations for this release series are not currently " |
610 | + "available. Please come back soon.") |
611 | |
612 | === modified file 'lib/lp/translations/browser/tests/distroseries-views.txt' |
613 | --- lib/lp/translations/browser/tests/distroseries-views.txt 2009-12-13 11:55:40 +0000 |
614 | +++ lib/lp/translations/browser/tests/distroseries-views.txt 2010-03-01 23:03:20 +0000 |
615 | @@ -1,9 +1,9 @@ |
616 | -= DistroSeries translations view classes = |
617 | +DistroSeries translations view classes |
618 | +====================================== |
619 | + |
620 | +Let's use ubuntu/hoary for these tests. |
621 | |
622 | >>> from canonical.launchpad.webapp.servers import LaunchpadTestRequest |
623 | - |
624 | -Let's use ubuntu/hoary for these tests. |
625 | - |
626 | >>> from canonical.launchpad.interfaces import IDistributionSet |
627 | >>> from lp.registry.interfaces.series import SeriesStatus |
628 | >>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu') |
629 | @@ -15,7 +15,9 @@ |
630 | >>> login('foo.bar@canonical.com') |
631 | >>> hoary.status = SeriesStatus.CURRENT |
632 | |
633 | -== Hiding translations == |
634 | + |
635 | +Hiding translations |
636 | +------------------- |
637 | |
638 | Each distroseries has a switch that allows administrators to either |
639 | reveal its translations to the public or hide them from the public. |
640 | @@ -95,9 +97,65 @@ |
641 | release series are not currently available. Please come back soon. |
642 | |
643 | The same goes for anonymous users. |
644 | - |
645 | - >>> login(ANONYMOUS) |
646 | - >>> check_effect_of_hiding(hoary) |
647 | - User can access revealed translations. |
648 | - User can not access hidden translations: Translations for this |
649 | - release series are not currently available. Please come back soon. |
650 | +Exactly what message is displayed depends on the series' status. |
651 | + |
652 | + >>> login('foo.bar@canonical.com') |
653 | + >>> hoary.status = SeriesStatus.EXPERIMENTAL |
654 | + >>> login(ANONYMOUS) |
655 | + >>> check_effect_of_hiding(hoary) |
656 | + User can access revealed translations. |
657 | + User can not access hidden translations: |
658 | + Translations for this release series are not available yet. |
659 | + |
660 | + >>> login('foo.bar@canonical.com') |
661 | + >>> hoary.status = SeriesStatus.DEVELOPMENT |
662 | + >>> login(ANONYMOUS) |
663 | + >>> check_effect_of_hiding(hoary) |
664 | + User can access revealed translations. |
665 | + User can not access hidden translations: |
666 | + Translations for this release series are not available yet. |
667 | + |
668 | + >>> login('foo.bar@canonical.com') |
669 | + >>> hoary.status = SeriesStatus.FROZEN |
670 | + >>> login(ANONYMOUS) |
671 | + >>> check_effect_of_hiding(hoary) |
672 | + User can access revealed translations. |
673 | + User can not access hidden translations: |
674 | + Translations for this release series are not currently available. |
675 | + Please come back soon. |
676 | + |
677 | + >>> login('foo.bar@canonical.com') |
678 | + >>> hoary.status = SeriesStatus.CURRENT |
679 | + >>> login(ANONYMOUS) |
680 | + >>> check_effect_of_hiding(hoary) |
681 | + User can access revealed translations. |
682 | + User can not access hidden translations: |
683 | + Translations for this release series are not currently available. |
684 | + Please come back soon. |
685 | + |
686 | + >>> login('foo.bar@canonical.com') |
687 | + >>> hoary.status = SeriesStatus.SUPPORTED |
688 | + >>> login(ANONYMOUS) |
689 | + >>> check_effect_of_hiding(hoary) |
690 | + User can access revealed translations. |
691 | + User can not access hidden translations: |
692 | + Translations for this release series are not currently available. |
693 | + Please come back soon. |
694 | + |
695 | + >>> login('foo.bar@canonical.com') |
696 | + >>> hoary.status = SeriesStatus.OBSOLETE |
697 | + >>> login(ANONYMOUS) |
698 | + >>> check_effect_of_hiding(hoary) |
699 | + User can access revealed translations. |
700 | + User can not access hidden translations: |
701 | + This release series is obsolete. Its translations are no longer |
702 | + available. |
703 | + |
704 | + >>> login('foo.bar@canonical.com') |
705 | + >>> hoary.status = SeriesStatus.FUTURE |
706 | + >>> login(ANONYMOUS) |
707 | + >>> check_effect_of_hiding(hoary) |
708 | + User can access revealed translations. |
709 | + User can not access hidden translations: |
710 | + Translations for this release series are not available yet. |
711 | + |
712 | |
713 | === modified file 'lib/lp/translations/stories/distroseries/xx-distroseries-translations.txt' |
714 | --- lib/lp/translations/stories/distroseries/xx-distroseries-translations.txt 2009-12-21 17:18:12 +0000 |
715 | +++ lib/lp/translations/stories/distroseries/xx-distroseries-translations.txt 2010-03-01 23:03:20 +0000 |
716 | @@ -46,9 +46,7 @@ |
717 | ... but the link is available to administrators: |
718 | |
719 | >>> dtc_browser = setupDTCBrowser() |
720 | - |
721 | >>> dtc_browser.open('http://translations.launchpad.dev/ubuntu/hoary') |
722 | - |
723 | >>> dtc_browser.getLink('Change settings').click() |
724 | |
725 | Once the administrator hides all translations... |
726 | @@ -115,8 +113,8 @@ |
727 | non-administrative users. |
728 | |
729 | >>> user_browser.open( |
730 | - ... 'http://translations.launchpad.dev/ubuntu/hoary/+sources/evolution/' |
731 | - ... '+pots/evolution-2.2') |
732 | + ... 'http://translations.launchpad.dev/ubuntu/hoary/' |
733 | + ... '+sources/evolution/+pots/evolution-2.2') |
734 | Traceback (most recent call last): |
735 | ... |
736 | TranslationUnavailable: ... |
737 | @@ -126,7 +124,7 @@ |
738 | |
739 | >>> dtc_browser.open( |
740 | ... 'http://translations.launchpad.dev/ubuntu/hoary/' |
741 | - ... '+sources/evolution') |
742 | + ... '+sources/evolution/+pots/evolution-2.2') |
743 | |
744 | There is also an option to set/unset whether translation imports for a |
745 | distribution should be deferred. That option is set also from the same |
746 | |
747 | === modified file 'lib/lp/translations/templates/distroseries-langchart.pt' |
748 | --- lib/lp/translations/templates/distroseries-langchart.pt 2009-12-27 20:58:33 +0000 |
749 | +++ lib/lp/translations/templates/distroseries-langchart.pt 2010-03-01 23:03:20 +0000 |
750 | @@ -8,6 +8,11 @@ |
751 | <strong>Translations for this series are currently hidden.</strong> |
752 | |
753 | <!-- Bounce regular users to "translations unavailable" page. --> |
754 | + <tal:XXX condition="nothing"> |
755 | + 20100224 adiroiban bug=527069: The following tal:omit-tag is only |
756 | + used with the sole purpose of raising an exception. |
757 | + There should be a better solution for this problem. |
758 | + </tal:XXX> |
759 | <metal:check-available tal:omit-tag="view/checkTranslationsViewable" /> |
760 | </p> |
761 |
= Bug 509252 = /code.edge. launchpad. net/~adiroiban/ launchpad/ bug-340662- take-2/ +merge/ 17598) the POTemplateSubse tNavigation will render the AdminPOTemplate Subset useless.
After landing the fix for bug 340662 (https:/
We should clean the security.py.
AdminPOTemplate Subset was added to fix bug 497438
== Proposed fix ==
Remove unused classed from security.py and refactor
== Pre-implementation notes ==
Talking with Henning we decide not to include security checking code in the model. This is why the logic of showing translations of a series was spitted between the model and the view and the security checks were done in multiple places.
This restriction lead to a strange implementation where the check was done both in the view and the model and it was a source of confusion.
I merged this logic in a browser helper function and now the security check is only done once.
== Implementation details ==
These changes renders the AdminDistroSeri esLanguage class from security.py useless, so I have also removed it.
== Tests == translations -t distroseries-views
lp-test -t distroseries-
== Demo and Q/A == l10n-coordinato r). /launchpad. dev/~ubuntu- l10n-coordinato r
Make sure you are a member of Ubuntu Translation Coordinators team (ubuntu-
https:/
Go to the translation page for a distribution and hide translations for this series /translations. launchpad. dev/ubuntu/ hoary/+ admin
ie: https:/
Next go to the distribution series +template page /translations. launchpad. dev/ubuntu/ hoary/+ templates
https:/
You should see the Administer page for Evolution templates, including disabled-template .
As a member of Ubuntu Translation Coordinators team you should be able to administer them, just like for a normal series.
Login as a normal user you should see a page informing that the translations are currently closed
= 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 registry/ browser/ distroseries. py registry/ browser/ sourcepackage. py registry/ interfaces/ distroseries. py registry/ model/distroser ies.py translations/ browser/ browser_ helpers. py translations/ browser/ distroseries. py translations/ stories/ distroseries/ xx-distroseries -translations. txt
lib/canonical
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
== Pylint notices ==
lib/lp/ registry/ browser/ sourcepackage. py interface' (No module named restful)
29: [F0401] Unable to import 'lazr.restful.
lib/lp/ registry/ interfaces/ distroseries. py fields' (No module named restful) declarations' (No module named restful) sionField. _validate] Use super on an old style class blic.getPackage Uploads] Operator not preceded by a space =_("Return items that are more recent than this " False),
23: [F0401] Unable to import 'lazr.enum' (No module named enum)
50: [F0401] Unable to import 'lazr.restful.
51: [F0401] Unable to import 'lazr.restful.
117: [E1002, DistroSeriesVer
447: [C0322, IDistroSeriesPu
description
^
"timestamp."),
required=
status=Choice(
vocabulary= DBEnumeratedTyp e, _("Package Upload Status"),
title=
des...