Merge lp:~cjwatson/launchpad/translation-import-queue-entry-dsp-vocab into lp:launchpad

Proposed by Colin Watson on 2016-09-12
Status: Merged
Merged at revision: 18200
Proposed branch: lp:~cjwatson/launchpad/translation-import-queue-entry-dsp-vocab
Merge into: lp:launchpad
Prerequisite: lp:~cjwatson/launchpad/potemplate-dsp-vocab
Diff against target: 315 lines (+192/-5)
4 files modified
lib/lp/translations/browser/tests/test_translationimportqueueentry.py (+46/-2)
lib/lp/translations/browser/translationimportqueue.py (+34/-3)
lib/lp/translations/browser/widgets/tests/test_translationimportqueue.py (+78/-0)
lib/lp/translations/browser/widgets/translationimportqueue.py (+34/-0)
To merge this branch: bzr merge lp:~cjwatson/launchpad/translation-import-queue-entry-dsp-vocab
Reviewer Review Type Date Requested Status
William Grant code 2016-09-12 Approve on 2016-09-19
Review via email: mp+305509@code.launchpad.net

Commit Message

Convert TranslationImportQueueEntry:+index to use the DistributionSourcePackage picker if the appropriate feature flag is set.

Description of the Change

Convert TranslationImportQueueEntry:+index to use the DistributionSourcePackage picker if the appropriate feature flag is set.

I believe this is the last of the view conversions.

To post a comment you must log in.
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/translations/browser/tests/test_translationimportqueueentry.py'
2--- lib/lp/translations/browser/tests/test_translationimportqueueentry.py 2014-02-19 04:01:46 +0000
3+++ lib/lp/translations/browser/tests/test_translationimportqueueentry.py 2016-09-12 17:58:08 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2010 Canonical Ltd. This software is licensed under the
6+# Copyright 2010-2016 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8
9 """Unit tests for translation import queue views."""
10@@ -6,12 +6,18 @@
11 from datetime import datetime
12
13 from pytz import timezone
14+from testscenarios import (
15+ load_tests_apply_scenarios,
16+ WithScenarios,
17+ )
18 from zope.component import getUtility
19 from zope.security.proxy import removeSecurityProxy
20
21 from lp.app.enums import ServiceUsage
22+from lp.services.features.testing import FeatureFixture
23 from lp.services.webapp import canonical_url
24 from lp.testing import (
25+ celebrity_logged_in,
26 TestCase,
27 TestCaseWithFactory,
28 )
29@@ -23,14 +29,23 @@
30 )
31
32
33-class TestTranslationImportQueueEntryView(TestCaseWithFactory):
34+class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
35 """Tests for the queue entry review form."""
36
37 layer = LaunchpadFunctionalLayer
38
39+ scenarios = [
40+ ("spn_picker", {"features": {}}),
41+ ("dsp_picker", {
42+ "features": {u"disclosure.dsp_picker.enabled": u"on"},
43+ }),
44+ ]
45+
46 def setUp(self):
47 super(TestTranslationImportQueueEntryView, self).setUp(
48 'foo.bar@canonical.com')
49+ if self.features:
50+ self.useFixture(FeatureFixture(self.features))
51 self.queue = getUtility(ITranslationImportQueue)
52 self.uploader = self.factory.makePerson()
53
54@@ -201,6 +216,32 @@
55
56 self.assertEqual(name, view.initial_values['name'])
57
58+ def test_change_sourcepackage(self):
59+ # Changing the source package is honoured.
60+ series = self.factory.makeDistroSeries()
61+ packagename = self.factory.makeSourcePackageName()
62+ potemplate = self.factory.makePOTemplate(
63+ distroseries=series, sourcepackagename=packagename)
64+ entry = self._makeEntry(
65+ distroseries=series, sourcepackagename=packagename,
66+ potemplate=potemplate)
67+ dsp = self.factory.makeDSPCache(distroseries=series)
68+ form = {
69+ 'field.file_type': 'POT',
70+ 'field.path': entry.path,
71+ 'field.sourcepackagename': dsp.sourcepackagename.name,
72+ 'field.name': potemplate.name,
73+ 'field.translation_domain': potemplate.translation_domain,
74+ 'field.languagepack': '',
75+ 'field.actions.approve': 'Approve',
76+ }
77+ with celebrity_logged_in('rosetta_experts'):
78+ view = create_initialized_view(entry, '+index', form=form)
79+ self.assertEqual([], view.errors)
80+ self.assertEqual(
81+ dsp.sourcepackagename.name,
82+ entry.potemplate.sourcepackagename.name)
83+
84
85 class TestEscapeJSString(TestCase):
86 """Test `escape_js_string`."""
87@@ -222,3 +263,6 @@
88
89 def test_escape_js_string_ampersand(self):
90 self.assertEqual('&', escape_js_string('&'))
91+
92+
93+load_tests = load_tests_apply_scenarios
94
95=== modified file 'lib/lp/translations/browser/translationimportqueue.py'
96--- lib/lp/translations/browser/translationimportqueue.py 2015-07-08 16:05:11 +0000
97+++ lib/lp/translations/browser/translationimportqueue.py 2016-09-12 17:58:08 +0000
98@@ -1,4 +1,4 @@
99-# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
100+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
101 # GNU Affero General Public License version 3 (see the file LICENSE).
102
103 """Browser views for `ITranslationImportQueue`."""
104@@ -15,6 +15,7 @@
105
106 import os
107
108+from lazr.restful.interface import copy_field
109 from zope.component import getUtility
110 from zope.formlib.interfaces import ConversionError
111 from zope.interface import implementer
112@@ -26,6 +27,7 @@
113
114 from lp.app.browser.launchpadform import (
115 action,
116+ custom_widget,
117 LaunchpadFormView,
118 )
119 from lp.app.browser.tales import DateTimeFormatterAPI
120@@ -34,9 +36,13 @@
121 UnexpectedFormData,
122 )
123 from lp.app.validators.name import valid_name
124+from lp.registry.interfaces.distributionsourcepackage import (
125+ IDistributionSourcePackage,
126+ )
127 from lp.registry.interfaces.distroseries import IDistroSeries
128 from lp.registry.interfaces.sourcepackage import ISourcePackageFactory
129 from lp.services.database.constants import UTC_NOW
130+from lp.services.features import getFeatureFlag
131 from lp.services.webapp import (
132 canonical_url,
133 GetitemNavigation,
134@@ -45,6 +51,9 @@
135 from lp.translations.browser.hastranslationimports import (
136 HasTranslationImportsView,
137 )
138+from lp.translations.browser.widgets.translationimportqueue import (
139+ TranslationImportQueueEntrySourcePackageNameWidget,
140+ )
141 from lp.translations.enums import RosettaImportStatus
142 from lp.translations.interfaces.pofile import IPOFileSet
143 from lp.translations.interfaces.potemplate import IPOTemplateSet
144@@ -85,10 +94,28 @@
145 usedfor = ITranslationImportQueueEntry
146
147
148+class IEditTranslationImportQueueEntryDSP(IEditTranslationImportQueueEntry):
149+
150+ sourcepackagename = copy_field(
151+ IEditTranslationImportQueueEntry['sourcepackagename'],
152+ vocabularyName='DistributionSourcePackage')
153+
154+
155 class TranslationImportQueueEntryView(LaunchpadFormView):
156 """The view part of admin interface for the translation import queue."""
157 label = "Review import queue entry"
158- schema = IEditTranslationImportQueueEntry
159+
160+ @property
161+ def schema(self):
162+ """See `LaunchpadFormView`."""
163+ if bool(getFeatureFlag('disclosure.dsp_picker.enabled')):
164+ return IEditTranslationImportQueueEntryDSP
165+ else:
166+ return IEditTranslationImportQueueEntry
167+
168+ custom_widget(
169+ 'sourcepackagename',
170+ TranslationImportQueueEntrySourcePackageNameWidget)
171
172 max_series_to_display = 3
173
174@@ -101,7 +128,7 @@
175 if self.request.method == 'POST':
176 # We got a form post, we don't need to do any initialization.
177 return field_values
178- # Fill the know values.
179+ # Fill in the known values.
180 field_values['path'] = self.context.path
181
182 importer = getUtility(ITranslationImporter)
183@@ -418,6 +445,10 @@
184 self.setFieldError('file_type', 'Please specify the file type')
185 return
186
187+ sourcepackagename = data.get('sourcepackagename')
188+ if IDistributionSourcePackage.providedBy(sourcepackagename):
189+ data['sourcepackagename'] = sourcepackagename.sourcepackagename
190+
191 self.path_changed = self._validatePath(file_type, data.get('path'))
192
193 self.man_potemplate = None
194
195=== added file 'lib/lp/translations/browser/widgets/tests/test_translationimportqueue.py'
196--- lib/lp/translations/browser/widgets/tests/test_translationimportqueue.py 1970-01-01 00:00:00 +0000
197+++ lib/lp/translations/browser/widgets/tests/test_translationimportqueue.py 2016-09-12 17:58:08 +0000
198@@ -0,0 +1,78 @@
199+# Copyright 2016 Canonical Ltd. This software is licensed under the
200+# GNU Affero General Public License version 3 (see the file LICENSE).
201+
202+"""Test the TranslationImportQueueEntry widget."""
203+
204+from __future__ import absolute_import, print_function, unicode_literals
205+
206+__metaclass__ = type
207+
208+from testscenarios import (
209+ load_tests_apply_scenarios,
210+ WithScenarios,
211+ )
212+
213+from lp.services.features.testing import FeatureFixture
214+from lp.services.webapp.servers import LaunchpadTestRequest
215+from lp.testing import TestCaseWithFactory
216+from lp.testing.layers import LaunchpadFunctionalLayer
217+from lp.translations.browser.translationimportqueue import (
218+ IEditTranslationImportQueueEntryDSP,
219+ )
220+from lp.translations.browser.widgets.translationimportqueue import (
221+ TranslationImportQueueEntrySourcePackageNameWidget,
222+ )
223+from lp.translations.interfaces.translationimportqueue import (
224+ IEditTranslationImportQueueEntry,
225+ )
226+
227+
228+class TestTranslationImportQueueEntrySourcePackageNameWidget(
229+ WithScenarios, TestCaseWithFactory):
230+
231+ layer = LaunchpadFunctionalLayer
232+
233+ scenarios = [
234+ ("spn_picker", {
235+ "features": {},
236+ "interface": IEditTranslationImportQueueEntry,
237+ }),
238+ ("dsp_picker", {
239+ "features": {u"disclosure.dsp_picker.enabled": u"on"},
240+ "interface": IEditTranslationImportQueueEntryDSP,
241+ }),
242+ ]
243+
244+ def setUp(self):
245+ super(
246+ TestTranslationImportQueueEntrySourcePackageNameWidget,
247+ self).setUp()
248+ if self.features:
249+ self.useFixture(FeatureFixture(self.features))
250+
251+ def makeWidget(self, entry, form=None):
252+ field = self.interface["sourcepackagename"]
253+ bound_field = field.bind(entry)
254+ request = LaunchpadTestRequest(form=form)
255+ return TranslationImportQueueEntrySourcePackageNameWidget(
256+ bound_field, bound_field.vocabulary, request)
257+
258+ def test_productseries(self):
259+ productseries = self.factory.makeProductSeries()
260+ entry = self.factory.makeTranslationImportQueueEntry(
261+ productseries=productseries)
262+ widget = self.makeWidget(entry)
263+ self.assertIsNone(widget.getDistribution())
264+ self.assertEqual("", widget.distribution_name)
265+
266+ def test_distroseries(self):
267+ distroseries = self.factory.makeDistroSeries()
268+ entry = self.factory.makeTranslationImportQueueEntry(
269+ distroseries=distroseries)
270+ widget = self.makeWidget(entry)
271+ self.assertEqual(distroseries.distribution, widget.getDistribution())
272+ self.assertEqual(
273+ distroseries.distribution.name, widget.distribution_name)
274+
275+
276+load_tests = load_tests_apply_scenarios
277
278=== added file 'lib/lp/translations/browser/widgets/translationimportqueue.py'
279--- lib/lp/translations/browser/widgets/translationimportqueue.py 1970-01-01 00:00:00 +0000
280+++ lib/lp/translations/browser/widgets/translationimportqueue.py 2016-09-12 17:58:08 +0000
281@@ -0,0 +1,34 @@
282+# Copyright 2016 Canonical Ltd. This software is licensed under the
283+# GNU Affero General Public License version 3 (see the file LICENSE).
284+
285+"""Widgets related to `TranslationImportQueueEntry`."""
286+
287+from __future__ import absolute_import, print_function, unicode_literals
288+
289+__metaclass__ = type
290+__all__ = [
291+ "TranslationImportQueueEntrySourcePackageNameWidget",
292+ ]
293+
294+from lp.app.widgets.popup import SourcePackageNameWidgetBase
295+
296+
297+class TranslationImportQueueEntrySourcePackageNameWidget(
298+ SourcePackageNameWidgetBase):
299+ """A widget for associating a TranslationImportQueueEntry with an SPN."""
300+
301+ @property
302+ def distribution_name(self):
303+ distribution = self.getDistribution()
304+ if distribution is not None:
305+ return distribution.name
306+ else:
307+ return ''
308+
309+ def getDistribution(self):
310+ """See `SourcePackageNameWidgetBase`."""
311+ distroseries = self.context.context.distroseries
312+ if distroseries is not None:
313+ return distroseries.distribution
314+ else:
315+ return None