Merge lp:~jtv/launchpad/recife-pofile-owner-privs into lp:~launchpad/launchpad/recife

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Graham Binns
Approved revision: no longer in the source branch.
Merged at revision: 9175
Proposed branch: lp:~jtv/launchpad/recife-pofile-owner-privs
Merge into: lp:~launchpad/launchpad/recife
Diff against target: 640 lines (+142/-108)
9 files modified
lib/canonical/launchpad/security.py (+4/-7)
lib/lp/translations/browser/potemplate.py (+1/-3)
lib/lp/translations/interfaces/pofile.py (+0/-3)
lib/lp/translations/model/pofile.py (+10/-16)
lib/lp/translations/model/potemplate.py (+9/-7)
lib/lp/translations/stories/standalone/xx-pofile-export.txt (+7/-20)
lib/lp/translations/tests/test_pofile.py (+11/-0)
lib/lp/translations/tests/test_potemplate.py (+29/-4)
lib/lp/translations/tests/test_translatedlanguage.py (+71/-48)
To merge this branch: bzr merge lp:~jtv/launchpad/recife-pofile-owner-privs
Reviewer Review Type Date Requested Status
Graham Binns (community) code Approve
Review via email: mp+38827@code.launchpad.net

Commit message

Give POFile.owner no special privileges, and always set it to the creator.

Description of the change

Strip POFile.owner of its privileges
====================================

For the Recife feature branch, this branch implements a change to the privileges model. The change pertains to who gets edit rights to a translation as embodied by a POFile.

The details of that are quite complex. I leave most for my next branch. But one thing that bestows edit privileges to a user is ownership: the user who is (a member of) a POFile.owner can edit that POFile. But ownership of a POFile is somewhat arbitrary: just submitting a suggestion for instance can implicitly create a POFile in the database. Anyone can do it in almost anyone's project or package.

Having submitted the first suggestion to a translation should not make you an editor, and that is where the existing code does a little weasel dance: *if* you currently have edit rights, then you also become the owner of the POFile that you cause to be created. If you don't, ownership defaults to the Rosetta experts team. Nobody will ever notice… unless you later lose your edit rights for whatever reason. Then you'll arbitrarily stay able to edit those POFiles that you caused to be created, but not the others that you lost edit rights to. It's both complicated and pointless.

After discussion with all members of the Translations team at various times, this branch streamlines POFile.owner:
 * Implies no special privileges on the POFile.
 * Always gets set to whoever causes it to be created.
 * Is initialized during POFile construction, not with a separate method.
 * Effectively means "creator" (and may be renamed later).

It's not obvious but there were actually two places in the code that gave special rights to POFile.owner: the security.py class built on EditByOwnersOrAdmins (implicitly authorizing the context's owner) and POFile.canEditTranslations checked for it. My branch also removes duplication from those checks, concentrating them in POFile. Not ideal, but the checking code is complex enough that hiding it in security.py might hide performance problems.

I hit some circular imports between pofile and person, so you'll see me concentrate references to DummyPOFile here and there and do local imports. Not quite enough to create a new helper, I guess.

In the xx-pofile-export pagetest you'll see a stretch of test removed. That's because I added a unit test for the removed privilege; everything else that bit of test did was duplicated under a different login right afterwards.

To test this, you'll want a full Translations test:
{{{
make schema
./bin/test -vvc lp.translations
}}}

There's no lint left. The price is some diff pollution.

Jeroen

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/security.py'
2--- lib/canonical/launchpad/security.py 2010-10-14 15:22:46 +0000
3+++ lib/canonical/launchpad/security.py 2010-10-19 12:57:50 +0000
4@@ -1226,16 +1226,13 @@
5 usedfor = IPOFile
6
7
8-class EditPOFileDetails(EditByOwnersOrAdmins):
9+class EditPOFile(AuthorizationBase):
10+ permission = 'launchpad.Edit'
11 usedfor = IPOFile
12
13 def checkAuthenticated(self, user):
14- """Allow anyone that can edit translations, owner, experts and admis.
15- """
16-
17- return (EditByOwnersOrAdmins.checkAuthenticated(self, user) or
18- self.obj.canEditTranslations(user.person) or
19- user.in_rosetta_experts)
20+ """The `POFile` itself keeps track of this permission."""
21+ return self.obj.canEditTranslations(user.person)
22
23
24 class AdminTranslator(OnlyRosettaExpertsAndAdmins):
25
26=== modified file 'lib/lp/translations/browser/potemplate.py'
27--- lib/lp/translations/browser/potemplate.py 2010-09-30 03:22:18 +0000
28+++ lib/lp/translations/browser/potemplate.py 2010-10-19 12:57:50 +0000
29@@ -120,9 +120,7 @@
30 # XXX CarlosPerelloMarin 2006-04-20 bug=40275: We should
31 # check the kind of POST we got. A logout will also be a
32 # POST and we should not create a POFile in that case.
33- pofile = self.context.newPOFile(name)
34- pofile.setOwnerIfPrivileged(user)
35- return pofile
36+ return self.context.newPOFile(name, owner=user)
37
38
39 class POTemplateFacets(StandardLaunchpadFacets):
40
41=== modified file 'lib/lp/translations/interfaces/pofile.py'
42--- lib/lp/translations/interfaces/pofile.py 2010-10-14 08:04:21 +0000
43+++ lib/lp/translations/interfaces/pofile.py 2010-10-19 12:57:50 +0000
44@@ -237,9 +237,6 @@
45 def canEditTranslations(person):
46 """Whether the given person is able to add/edit translations."""
47
48- def setOwnerIfPrivileged(person):
49- """Set `owner` to `person`, provided `person` has edit rights."""
50-
51 def canAddSuggestions(person):
52 """Whether the given person is able to add new suggestions."""
53
54
55=== modified file 'lib/lp/translations/model/pofile.py'
56--- lib/lp/translations/model/pofile.py 2010-10-14 08:24:55 +0000
57+++ lib/lp/translations/model/pofile.py 2010-10-19 12:57:50 +0000
58@@ -68,7 +68,6 @@
59 )
60 from canonical.launchpad.webapp.publisher import canonical_url
61 from lp.registry.interfaces.person import validate_public_person
62-from lp.registry.model.person import Person
63 from lp.services.propertycache import cachedproperty
64 from lp.translations.interfaces.pofile import (
65 IPOFile,
66@@ -233,13 +232,10 @@
67 if _person_has_not_licensed_translations(person):
68 return False
69
70- # Finally, check whether the user is member of the translation team or
71- # owner for the given PO file.
72+ # Finally, check whether the user is a member of the translation team.
73 translators = [t.translator for t in pofile.translators]
74 return _check_translation_perms(
75- pofile.translationpermission,
76- translators,
77- person) or person.inTeam(pofile.owner)
78+ pofile.translationpermission, translators, person)
79
80
81 def _can_add_suggestions(pofile, person):
82@@ -316,11 +312,6 @@
83 """See `IPOFile`."""
84 return _can_add_suggestions(self, person)
85
86- def setOwnerIfPrivileged(self, person):
87- """See `IPOFile`."""
88- if self.canEditTranslations(person):
89- self.owner = person
90-
91 def getHeader(self):
92 """See `IPOFile`."""
93 translation_importer = getUtility(ITranslationImporter)
94@@ -599,6 +590,9 @@
95 @property
96 def contributors(self):
97 """See `IPOFile`."""
98+ # Avoid circular import.
99+ from lp.registry.model.person import Person
100+
101 # Translation credit messages are "translated" by
102 # rosetta_experts. Shouldn't show up in contributors lists
103 # though.
104@@ -1358,12 +1352,12 @@
105 UTC = pytz.timezone('UTC')
106 self.date_changed = None
107 self.lastparsed = None
108- self.owner = getUtility(ILaunchpadCelebrities).rosetta_experts
109
110- # The default POFile owner is the Rosetta Experts team unless the
111- # given owner has rights to write into that file.
112- if self.canEditTranslations(owner):
113- self.owner = owner
114+ if owner is None:
115+ owner = getUtility(ILaunchpadCelebrities).rosetta_experts
116+ # The "owner" is really just the creator, without any extra
117+ # privileges.
118+ self.owner = owner
119
120 self.path = u'unknown'
121 self.datecreated = datetime.datetime.now(UTC)
122
123=== modified file 'lib/lp/translations/model/potemplate.py'
124--- lib/lp/translations/model/potemplate.py 2010-10-18 16:36:46 +0000
125+++ lib/lp/translations/model/potemplate.py 2010-10-19 12:57:50 +0000
126@@ -103,10 +103,7 @@
127 from lp.translations.interfaces.translationimportqueue import (
128 RosettaImportStatus,
129 )
130-from lp.translations.model.pofile import (
131- DummyPOFile,
132- POFile,
133- )
134+from lp.translations.model.pofile import POFile
135 from lp.translations.model.pomsgid import POMsgID
136 from lp.translations.model.potmsgset import POTMsgSet
137 from lp.translations.model.translationimportqueue import collect_import_info
138@@ -170,7 +167,8 @@
139 for entry, pofile in enumerate(result):
140 assert pofile == result[entry], "This enumerate confuses me."
141 if pofile is None:
142- result[entry] = DummyPOFile(potemplates[entry], language)
143+ result[entry] = potemplates[entry].getDummyPOFile(
144+ language, check_for_existing=False)
145
146 return result
147
148@@ -744,7 +742,7 @@
149 # Update cache to reflect the change.
150 template._cached_pofiles_by_language[language_code] = pofile
151
152- def newPOFile(self, language_code, create_sharing=True):
153+ def newPOFile(self, language_code, create_sharing=True, owner=None):
154 """See `IPOTemplate`."""
155 # Make sure we don't already have a PO file for this language.
156 existingpo = self.getPOFileByLang(language_code)
157@@ -773,7 +771,8 @@
158 data['origin'] = self.sourcepackagename.name
159
160 # The default POFile owner is the Rosetta Experts team.
161- owner = getUtility(ILaunchpadCelebrities).rosetta_experts
162+ if owner is None:
163+ owner = getUtility(ILaunchpadCelebrities).rosetta_experts
164
165 path = self._composePOFilePath(language)
166
167@@ -806,6 +805,9 @@
168 def getDummyPOFile(self, language, requester=None,
169 check_for_existing=True):
170 """See `IPOTemplate`."""
171+ # Avoid circular import.
172+ from lp.translations.model.pofile import DummyPOFile
173+
174 if check_for_existing:
175 # see if a valid one exists.
176 existingpo = self.getPOFileByLang(language.code)
177
178=== modified file 'lib/lp/translations/stories/standalone/xx-pofile-export.txt'
179--- lib/lp/translations/stories/standalone/xx-pofile-export.txt 2009-12-10 12:46:11 +0000
180+++ lib/lp/translations/stories/standalone/xx-pofile-export.txt 2010-10-19 12:57:50 +0000
181@@ -1,4 +1,5 @@
182-= Exporting Single PO Files through the Web =
183+Exporting Single PO Files through the Web
184+=========================================
185
186 Not logged in users can't access the +export page.
187
188@@ -57,24 +58,11 @@
189 ... print tag.renderContents()
190 Your request has been received. Expect to receive an email shortly.
191
192-Since no-privileges person isn't a valid translator for Welsh (cy)
193-language, the ownership of the newly created pofile is set to Rosetta
194-Admins.
195-
196- >>> anon_browser.open(
197- ... 'http://translations.launchpad.dev/evolution'
198- ... '/trunk/+pots/evolution-2.2/cy/+details')
199- >>> translation_portlet = find_portlet(
200- ... anon_browser.contents, 'Translation file details')
201- >>> t = extract_text(
202- ... translation_portlet.firstText('Creator:').findNext('a'))
203- >>> u'Rosetta Administrators' in t
204- True
205-
206-But if we request an export from a valid translator, he gets the
207-ownership. We test using the Swedish (sv) language which doesn't have a
208-pofile for evolution yet; it will be created at the moment the export is
209-requested.
210+If the POFile first has to be created, the requester becomes its owner.
211+This implies no special privileges.
212+
213+We test using the Swedish (sv) language which doesn't have a pofile for
214+evolution yet; it will be created at the moment the export is requested.
215
216 >>> browser = setupBrowser(auth='Basic carlos@canonical.com:test')
217 >>> browser.open(
218@@ -115,4 +103,3 @@
219 >>> for tag in find_tags_by_class(browser.contents, 'informational'):
220 ... tag.renderContents()
221 'Your request has been received. Expect to receive an email shortly.'
222-
223
224=== modified file 'lib/lp/translations/tests/test_pofile.py'
225--- lib/lp/translations/tests/test_pofile.py 2010-10-18 16:36:46 +0000
226+++ lib/lp/translations/tests/test_pofile.py 2010-10-19 12:57:50 +0000
227@@ -33,6 +33,7 @@
228 from lp.translations.interfaces.translationcommonformat import (
229 ITranslationFileData,
230 )
231+from lp.translations.interfaces.translationgroup import TranslationPermission
232 from lp.translations.interfaces.translationmessage import (
233 TranslationValidationStatus,
234 )
235@@ -1888,6 +1889,16 @@
236 self.pofile.markChanged(translator=translator)
237 self.assertEqual(translator, self.pofile.lasttranslator)
238
239+ def test_owner_has_no_privileges(self):
240+ # Being a POFile's owner does not imply edit privileges.
241+ creator = self.factory.makePerson()
242+ removeSecurityProxy(self.pofile).owner = creator
243+ naked_product = removeSecurityProxy(
244+ self.potemplate.productseries.product)
245+ naked_product.translationpermission = TranslationPermission.RESTRICTED
246+
247+ self.assertFalse(self.pofile.canEditTranslations(creator))
248+
249 def test_hasPluralFormInformation_bluffs_if_irrelevant(self):
250 # If the template has no messages that use plural forms, the
251 # POFile has all the relevant plural-form information regardless
252
253=== modified file 'lib/lp/translations/tests/test_potemplate.py'
254--- lib/lp/translations/tests/test_potemplate.py 2010-10-18 16:36:46 +0000
255+++ lib/lp/translations/tests/test_potemplate.py 2010-10-19 12:57:50 +0000
256@@ -12,7 +12,6 @@
257 from lp.services.worlddata.interfaces.language import ILanguageSet
258 from lp.testing import TestCaseWithFactory
259 from lp.translations.interfaces.potemplate import IPOTemplateSet
260-from lp.translations.model.pofile import DummyPOFile
261 from lp.translations.model.potemplate import (
262 get_pofiles_for,
263 POTemplateSet,
264@@ -29,6 +28,13 @@
265 self.potemplate = removeSecurityProxy(self.factory.makePOTemplate(
266 translation_domain = "testdomain"))
267
268+ def assertIsDummy(self, pofile):
269+ """Assert that `pofile` is actually a `DummyPOFile`."""
270+ # Avoid circular imports.
271+ from lp.translations.model.pofile import DummyPOFile
272+
273+ self.assertEquals(DummyPOFile, type(pofile))
274+
275 def test_composePOFilePath(self):
276 esperanto = getUtility(ILanguageSet).getLanguageByCode('eo')
277 self.potemplate.path = "testdir/messages.pot"
278@@ -69,7 +75,7 @@
279 # Test basic behaviour of getDummyPOFile.
280 language = self.factory.makeLanguage('sr@test')
281 dummy = self.potemplate.getDummyPOFile(language)
282- self.assertEquals(DummyPOFile, type(dummy))
283+ self.assertIsDummy(dummy)
284
285 def test_getDummyPOFile_with_existing_pofile(self):
286 # Test that getDummyPOFile fails when trying to get a DummyPOFile
287@@ -88,7 +94,22 @@
288 # This is just "assertNotRaises".
289 dummy = self.potemplate.getDummyPOFile(language,
290 check_for_existing=False)
291- self.assertEquals(DummyPOFile, type(dummy))
292+ self.assertIsDummy(dummy)
293+
294+ def test_newPOFile_owner(self):
295+ # The intended owner of a new POFile can be passed to newPOFile.
296+ language = self.factory.makeLanguage('nl@test')
297+ person = self.factory.makePerson()
298+ pofile = self.potemplate.newPOFile(language.code, owner=person)
299+ self.assertEqual(person, pofile.owner)
300+
301+ def test_getDummyPOFile_owner(self):
302+ # The intended owner of a new DummyPOFile can be passed to
303+ # getDummyPOFile.
304+ language = self.factory.makeLanguage('nl@test')
305+ person = self.factory.makePerson()
306+ pofile = self.potemplate.getDummyPOFile(language, requester=person)
307+ self.assertEqual(person, pofile.owner)
308
309 def test_getTranslationCredits(self):
310 # getTranslationCredits returns only translation credits.
311@@ -478,6 +499,10 @@
312 def test_get_pofiles_for_untranslated_template(self):
313 # If there is no POFile for a template in a language,
314 # get_pofiles_for makes up a DummyPOFile.
315+
316+ # Avoid circular imports.
317+ from lp.translations.model.pofile import DummyPOFile
318+
319 pofiles = get_pofiles_for([self.potemplate], self.greek)
320 pofile = pofiles[0]
321- self.assertTrue(isinstance(pofile, DummyPOFile))
322+ self.assertIsInstance(pofile, DummyPOFile)
323
324=== modified file 'lib/lp/translations/tests/test_translatedlanguage.py'
325--- lib/lp/translations/tests/test_translatedlanguage.py 2010-10-04 19:50:45 +0000
326+++ lib/lp/translations/tests/test_translatedlanguage.py 2010-10-19 12:57:50 +0000
327@@ -1,20 +1,25 @@
328 # Copyright 2010 Canonical Ltd. This software is licensed under the
329 # GNU Affero General Public License version 3 (see the file LICENSE).
330
331+from __future__ import with_statement
332+
333 __metaclass__ = type
334
335 from zope.component import getUtility
336 from zope.interface.verify import verifyObject
337 from zope.security.proxy import removeSecurityProxy
338
339+from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
340 from canonical.testing.layers import ZopelessDatabaseLayer
341 from lp.app.enums import ServiceUsage
342-from lp.testing import TestCaseWithFactory
343+from lp.testing import (
344+ person_logged_in,
345+ TestCaseWithFactory,
346+ )
347 from lp.translations.interfaces.productserieslanguage import (
348 IProductSeriesLanguageSet,
349 )
350 from lp.translations.interfaces.translatedlanguage import ITranslatedLanguage
351-from lp.translations.model.pofile import DummyPOFile
352
353
354 class TestTranslatedLanguageMixin(TestCaseWithFactory):
355@@ -46,6 +51,22 @@
356 potemplate.priority = priority
357 return potemplate
358
359+ def addPOFile(self, potemplate=None):
360+ """Add a `POFile` for the given `POTemplate`, in `self.language`.
361+
362+ If no `potemplate` is given, one will be created.
363+ """
364+ if potemplate is None:
365+ potemplate = self.addPOTemplate()
366+ return self.factory.makePOFile(self.language.code, potemplate)
367+
368+ def assertIsDummy(self, pofile):
369+ """Assert that `pofile` is actually a `DummyPOFile`."""
370+ # Avoid circular imports.
371+ from lp.translations.model.pofile import DummyPOFile
372+
373+ self.assertIsInstance(pofile, DummyPOFile)
374+
375 def test_interface(self):
376 translated_language = self.getTranslatedLanguage(self.language)
377 self.assertTrue(verifyObject(ITranslatedLanguage,
378@@ -76,7 +97,7 @@
379 # instead.
380 dummy_pofile = pofiles[0]
381 naked_dummy = removeSecurityProxy(dummy_pofile)
382- self.assertEqual(DummyPOFile, type(naked_dummy))
383+ self.assertIsDummy(naked_dummy)
384 self.assertEqual(self.language, dummy_pofile.language)
385 self.assertEqual(potemplate, dummy_pofile.potemplate)
386
387@@ -88,7 +109,7 @@
388 def test_pofiles_template_with_pofiles(self):
389 translated_language = self.getTranslatedLanguage(self.language)
390 potemplate = self.addPOTemplate()
391- pofile = self.factory.makePOFile(self.language.code, potemplate)
392+ pofile = self.addPOFile(potemplate)
393 self.assertEqual([pofile], list(translated_language.pofiles))
394
395 # Two queries get executed when listifying
396@@ -101,9 +122,9 @@
397 # Two templates with different priorities so they get sorted
398 # appropriately.
399 potemplate1 = self.addPOTemplate(priority=2)
400- pofile1 = self.factory.makePOFile(self.language.code, potemplate1)
401+ pofile1 = self.addPOFile(potemplate1)
402 potemplate2 = self.addPOTemplate(priority=1)
403- pofile2 = self.factory.makePOFile(self.language.code, potemplate2)
404+ pofile2 = self.addPOFile(potemplate2)
405 self.assertEqual([pofile1, pofile2],
406 list(translated_language.pofiles))
407
408@@ -117,12 +138,12 @@
409 # Two templates with different priorities so they get sorted
410 # appropriately.
411 potemplate1 = self.addPOTemplate(priority=2)
412- pofile1 = self.factory.makePOFile(self.language.code, potemplate1)
413+ pofile1 = self.addPOFile(potemplate1)
414 potemplate2 = self.addPOTemplate(priority=1)
415 pofiles = translated_language.pofiles
416 self.assertEqual(pofile1, pofiles[0])
417 dummy_pofile = removeSecurityProxy(pofiles[1])
418- self.assertEqual(DummyPOFile, type(dummy_pofile))
419+ self.assertIsDummy(dummy_pofile)
420
421 # Two queries get executed when listifying
422 # TranslatedLanguageMixin.pofiles: a len() does a count, and
423@@ -133,37 +154,39 @@
424 # Slicing still works, and always does the same constant number
425 # of queries (1).
426 translated_language = self.getTranslatedLanguage(self.language)
427- # Three templates with different priorities so they get sorted
428- # appropriately.
429- potemplate1 = self.addPOTemplate(priority=2)
430- pofile1 = self.factory.makePOFile(self.language.code, potemplate1)
431- potemplate2 = self.addPOTemplate(priority=1)
432- pofile2 = self.factory.makePOFile(self.language.code, potemplate2)
433- potemplate3 = self.addPOTemplate(priority=0)
434-
435- pofiles = translated_language.pofiles[0:2]
436- self.assertEqual([pofile1, pofile2], list(pofiles))
437-
438- # Slicing executes only a single query.
439- get_slice = lambda of, start, end: list(of[start:end])
440- self.assertStatementCount(1, get_slice,
441- translated_language.pofiles, 1, 3)
442+ pofile1 = self.addPOFile()
443+ pofile2 = self.addPOFile()
444+ self.addPOTemplate(priority=-1)
445+
446+ # This does assume that a few teams with special privileges are
447+ # already cached. For a normal user without those special
448+ # privileges, no further queries are needed to authorize access.
449+ user = self.factory.makePerson()
450+ celebs = getUtility(ILaunchpadCelebrities)
451+
452+ with person_logged_in(user):
453+ self.assertFalse(user.inTeam(celebs.admin))
454+ self.assertFalse(user.inTeam(celebs.rosetta_experts))
455+ pofiles = translated_language.pofiles[0:2]
456+ self.assertContentEqual([pofile1, pofile2], list(pofiles))
457+
458+ get_slice = lambda of, start, end: list(of[start:end])
459+ self.assertStatementCount(
460+ 1, get_slice, translated_language.pofiles, 1, 3)
461
462 def test_pofiles_slicing_dummies(self):
463 # Slicing includes DummyPOFiles.
464 translated_language = self.getTranslatedLanguage(self.language)
465 # Three templates with different priorities so they get sorted
466 # appropriately.
467- potemplate1 = self.addPOTemplate(priority=2)
468- pofile1 = self.factory.makePOFile(self.language.code, potemplate1)
469- potemplate2 = self.addPOTemplate(priority=1)
470- pofile2 = self.factory.makePOFile(self.language.code, potemplate2)
471- potemplate3 = self.addPOTemplate(priority=0)
472+ pofile1 = self.addPOFile(self.addPOTemplate(priority=2))
473+ pofile2 = self.addPOFile(self.addPOTemplate(priority=1))
474+ self.addPOTemplate(priority=0)
475
476 pofiles = translated_language.pofiles[1:3]
477 self.assertEqual(pofile2, pofiles[0])
478 dummy_pofile = removeSecurityProxy(pofiles[1])
479- self.assertEqual(DummyPOFile, type(dummy_pofile))
480+ self.assertIsDummy(dummy_pofile)
481
482 def test_statistics_empty(self):
483 translated_language = self.getTranslatedLanguage(self.language)
484@@ -222,7 +245,7 @@
485 def test_recalculateCounts_total_one_pofile(self):
486 translated_language = self.getTranslatedLanguage(self.language)
487 potemplate = self.addPOTemplate(number_of_potmsgsets=5)
488- pofile = self.factory.makePOFile(self.language.code, potemplate)
489+ pofile = self.addPOFile(potemplate)
490
491 translated_language.recalculateCounts()
492 self.assertEqual(
493@@ -231,9 +254,9 @@
494 def test_recalculateCounts_total_two_pofiles(self):
495 translated_language = self.getTranslatedLanguage(self.language)
496 potemplate1 = self.addPOTemplate(number_of_potmsgsets=5)
497- pofile1 = self.factory.makePOFile(self.language.code, potemplate1)
498+ pofile1 = self.addPOFile(potemplate1)
499 potemplate2 = self.addPOTemplate(number_of_potmsgsets=3)
500- pofile2 = self.factory.makePOFile(self.language.code, potemplate2)
501+ pofile2 = self.addPOFile(potemplate2)
502
503 translated_language.recalculateCounts()
504 self.assertEqual(
505@@ -242,7 +265,7 @@
506 def test_recalculateCounts_translated_one_pofile(self):
507 translated_language = self.getTranslatedLanguage(self.language)
508 potemplate = self.addPOTemplate(number_of_potmsgsets=5)
509- pofile = self.factory.makePOFile(self.language.code, potemplate)
510+ pofile = self.addPOFile(potemplate)
511 naked_pofile = removeSecurityProxy(pofile)
512 # translated count is current + rosetta
513 naked_pofile.currentcount = 3
514@@ -255,14 +278,14 @@
515 def test_recalculateCounts_translated_two_pofiles(self):
516 translated_language = self.getTranslatedLanguage(self.language)
517 potemplate1 = self.addPOTemplate(number_of_potmsgsets=5)
518- pofile1 = self.factory.makePOFile(self.language.code, potemplate1)
519+ pofile1 = self.addPOFile(potemplate1)
520 naked_pofile1 = removeSecurityProxy(pofile1)
521 # translated count is current + rosetta
522 naked_pofile1.currentcount = 3
523 naked_pofile1.rosettacount = 1
524
525 potemplate2 = self.addPOTemplate(number_of_potmsgsets=3)
526- pofile2 = self.factory.makePOFile(self.language.code, potemplate2)
527+ pofile2 = self.addPOFile(potemplate2)
528 naked_pofile2 = removeSecurityProxy(pofile2)
529 # translated count is current + rosetta
530 naked_pofile2.currentcount = 1
531@@ -275,7 +298,7 @@
532 def test_recalculateCounts_changed_one_pofile(self):
533 translated_language = self.getTranslatedLanguage(self.language)
534 potemplate = self.addPOTemplate(number_of_potmsgsets=5)
535- pofile = self.factory.makePOFile(self.language.code, potemplate)
536+ pofile = self.addPOFile(potemplate)
537 naked_pofile = removeSecurityProxy(pofile)
538 # translated count is current + rosetta
539 naked_pofile.updatescount = 3
540@@ -287,12 +310,12 @@
541 def test_recalculateCounts_changed_two_pofiles(self):
542 translated_language = self.getTranslatedLanguage(self.language)
543 potemplate1 = self.addPOTemplate(number_of_potmsgsets=5)
544- pofile1 = self.factory.makePOFile(self.language.code, potemplate1)
545+ pofile1 = self.addPOFile(potemplate1)
546 naked_pofile1 = removeSecurityProxy(pofile1)
547 naked_pofile1.updatescount = 3
548
549 potemplate2 = self.addPOTemplate(number_of_potmsgsets=3)
550- pofile2 = self.factory.makePOFile(self.language.code, potemplate2)
551+ pofile2 = self.addPOFile(potemplate2)
552 naked_pofile2 = removeSecurityProxy(pofile2)
553 naked_pofile2.updatescount = 1
554
555@@ -303,7 +326,7 @@
556 def test_recalculateCounts_new_one_pofile(self):
557 translated_language = self.getTranslatedLanguage(self.language)
558 potemplate = self.addPOTemplate(number_of_potmsgsets=5)
559- pofile = self.factory.makePOFile(self.language.code, potemplate)
560+ pofile = self.addPOFile(potemplate)
561 naked_pofile = removeSecurityProxy(pofile)
562 # new count is rosetta - changed
563 naked_pofile.rosettacount = 3
564@@ -316,14 +339,14 @@
565 def test_recalculateCounts_new_two_pofiles(self):
566 translated_language = self.getTranslatedLanguage(self.language)
567 potemplate1 = self.addPOTemplate(number_of_potmsgsets=5)
568- pofile1 = self.factory.makePOFile(self.language.code, potemplate1)
569+ pofile1 = self.addPOFile(potemplate1)
570 naked_pofile1 = removeSecurityProxy(pofile1)
571 # new count is rosetta - changed
572 naked_pofile1.rosettacount = 3
573 naked_pofile1.updatescount = 1
574
575 potemplate2 = self.addPOTemplate(number_of_potmsgsets=3)
576- pofile2 = self.factory.makePOFile(self.language.code, potemplate2)
577+ pofile2 = self.addPOFile(potemplate2)
578 naked_pofile2 = removeSecurityProxy(pofile2)
579 # new count is rosetta - changed
580 naked_pofile2.rosettacount = 2
581@@ -336,7 +359,7 @@
582 def test_recalculateCounts_unreviewed_one_pofile(self):
583 translated_language = self.getTranslatedLanguage(self.language)
584 potemplate = self.addPOTemplate(number_of_potmsgsets=5)
585- pofile = self.factory.makePOFile(self.language.code, potemplate)
586+ pofile = self.addPOFile(potemplate)
587 naked_pofile = removeSecurityProxy(pofile)
588 # translated count is current + rosetta
589 naked_pofile.unreviewed_count = 3
590@@ -348,12 +371,12 @@
591 def test_recalculateCounts_unreviewed_two_pofiles(self):
592 translated_language = self.getTranslatedLanguage(self.language)
593 potemplate1 = self.addPOTemplate(number_of_potmsgsets=5)
594- pofile1 = self.factory.makePOFile(self.language.code, potemplate1)
595+ pofile1 = self.addPOFile(potemplate1)
596 naked_pofile1 = removeSecurityProxy(pofile1)
597 naked_pofile1.unreviewed_count = 3
598
599 potemplate2 = self.addPOTemplate(number_of_potmsgsets=3)
600- pofile2 = self.factory.makePOFile(self.language.code, potemplate2)
601+ pofile2 = self.addPOFile(potemplate2)
602 naked_pofile2 = removeSecurityProxy(pofile2)
603 naked_pofile2.unreviewed_count = 1
604
605@@ -364,7 +387,7 @@
606 def test_recalculateCounts_one_pofile(self):
607 translated_language = self.getTranslatedLanguage(self.language)
608 potemplate = self.addPOTemplate(number_of_potmsgsets=5)
609- pofile = self.factory.makePOFile(self.language.code, potemplate)
610+ pofile = self.addPOFile(potemplate)
611 naked_pofile = removeSecurityProxy(pofile)
612 # translated count is current + rosetta
613 naked_pofile.currentcount = 3
614@@ -394,7 +417,7 @@
615
616 # Set up one template with a single PO file.
617 potemplate1 = self.addPOTemplate(number_of_potmsgsets=5)
618- pofile1 = self.factory.makePOFile(self.language.code, potemplate1)
619+ pofile1 = self.addPOFile(potemplate1)
620 naked_pofile1 = removeSecurityProxy(pofile1)
621 # translated count is current + rosetta
622 naked_pofile1.currentcount = 2
623@@ -407,7 +430,7 @@
624
625 # Set up second template with a single PO file.
626 potemplate2 = self.addPOTemplate(number_of_potmsgsets=3)
627- pofile2 = self.factory.makePOFile(self.language.code, potemplate2)
628+ pofile2 = self.addPOFile(potemplate2)
629 naked_pofile2 = removeSecurityProxy(pofile2)
630 # translated count is current + rosetta
631 naked_pofile2.currentcount = 1
632@@ -438,7 +461,7 @@
633
634 # Set up one template with a single PO file.
635 potemplate1 = self.addPOTemplate(number_of_potmsgsets=5)
636- pofile1 = self.factory.makePOFile(self.language.code, potemplate1)
637+ pofile1 = self.addPOFile(potemplate1)
638 naked_pofile1 = removeSecurityProxy(pofile1)
639 # translated count is current + rosetta
640 naked_pofile1.currentcount = 2

Subscribers

People subscribed via source and target branches