Merge lp:~henninge/launchpad/bug-516739-needs-information into lp:launchpad

Proposed by Henning Eggers
Status: Merged
Approved by: Jeroen T. Vermeulen
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~henninge/launchpad/bug-516739-needs-information
Merge into: lp:launchpad
Diff against target: 201 lines (+40/-25)
6 files modified
lib/canonical/launchpad/icing/style-3-0.css (+2/-0)
lib/lp/translations/doc/translationimportqueue.txt (+1/-0)
lib/lp/translations/interfaces/translationimportqueue.py (+6/-0)
lib/lp/translations/model/translationimportqueue.py (+4/-0)
lib/lp/translations/stories/importqueue/xx-translation-import-queue-filtering.txt (+1/-0)
lib/lp/translations/tests/test_translationimportqueue.py (+26/-25)
To merge this branch: bzr merge lp:~henninge/launchpad/bug-516739-needs-information
Reviewer Review Type Date Requested Status
Jeroen T. Vermeulen (community) code Approve
Review via email: mp+18693@code.launchpad.net

Commit message

Added Need Information status for translation import queue.

To post a comment you must log in.
Revision history for this message
Henning Eggers (henninge) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

= Summary =

Fixes bug 516739 by introducing a new status for translation import
queue entries called "Needs Information" to request a reply from the
uploader.

== Proposed fix ==

Add the new status to the RosettaImportStatus enum and add permissions
to TranslationImportQueueEntry.canSetStatus.

== Pre-implementation notes ==

Agreed with jtv that "Needs Information" is a better name than
"Incomplete" because it prompts the uploader for action. Also agreed,
that permissions should be the same as for "Approved".

== Implementation details ==

Actually, the permissions are not identical to "Approved" because "Needs
Information" can also be set if no import target has been selected.

== Tests ==

bin/test -vvct canSetSTatus

== Demo and Q/A ==

Go to the import queue as an admin and you'll see the new status in the
status picker.

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
lib/lp/translations/model/translationimportqueue.py
lib/canonical/launchpad/icing/style-3-0.css
lib/lp/translations/tests/test_translationimportqueue.py
lib/lp/translations/interfaces/translationimportqueue.py

== Pylint notices ==

lib/lp/translations/interfaces/translationimportqueue.py
10: [F0401] Unable to import 'lazr.enum' (No module named enum)
20: [F0401] Unable to import 'lazr.restful.interface' (No module named
restful)
21: [F0401] Unable to import 'lazr.restful.fields' (No module named restful)
22: [F0401] Unable to import 'lazr.restful.declarations' (No module
named restful)

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAktr7KIACgkQBT3oW1L17igkkgCfYxNNZGLZSIft6Z3ys8iYLolN
S/UAn0a/mPAJn5oHPnoVHDHHFJFWQu93
=OnOh
-----END PGP SIGNATURE-----

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Reviewed by IRC. Small fixes:
 * Better docstring for the new state.
 * The explicit ordering of states used in the test was no longer alphabetical; being made alphabetical again.
 * Pre-existing typo in comment. :-)

review: Approve
Revision history for this message
Jeroen T. Vermeulen (jtv) :
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/icing/style-3-0.css'
2--- lib/canonical/launchpad/icing/style-3-0.css 2010-01-21 17:55:18 +0000
3+++ lib/canonical/launchpad/icing/style-3-0.css 2010-02-05 15:31:17 +0000
4@@ -655,6 +655,8 @@
5 .translationimportstatusNEEDS_REVIEW a {color: #f60;}
6 .translationimportstatusBLOCKED,
7 .translationimportstatusBLOCKED a {color: blue;}
8+.translationimportstatusNEEDS_INFORMATION,
9+.translationimportstatusNEEDS_INFORMATION a {color: maroon;}
10
11 /* ==== Translations hand-made forms ==== */
12
13
14=== modified file 'lib/lp/translations/doc/translationimportqueue.txt'
15--- lib/lp/translations/doc/translationimportqueue.txt 2010-01-26 15:25:53 +0000
16+++ lib/lp/translations/doc/translationimportqueue.txt 2010-02-05 15:31:17 +0000
17@@ -1461,6 +1461,7 @@
18 debian/woody Woody
19 BLOCKED:
20 ubuntu/grumpy Grumpy
21+ NEEDS_INFORMATION:
22
23 You can also select by status.
24
25
26=== modified file 'lib/lp/translations/interfaces/translationimportqueue.py'
27--- lib/lp/translations/interfaces/translationimportqueue.py 2010-02-03 10:17:08 +0000
28+++ lib/lp/translations/interfaces/translationimportqueue.py 2010-02-05 15:31:17 +0000
29@@ -104,6 +104,12 @@
30 The entry has been blocked to be imported by a Rosetta Expert.
31 """)
32
33+ NEEDS_INFORMATION = DBItem(7, """
34+ Needs Information
35+
36+ The reviewer needs more information before this entry can be approved.
37+ """)
38+
39
40 class SpecialTranslationImportTargetFilter(DBEnumeratedType):
41 """Special "meta-targets" to filter the queue view by."""
42
43=== modified file 'lib/lp/translations/model/translationimportqueue.py'
44--- lib/lp/translations/model/translationimportqueue.py 2010-02-03 12:08:47 +0000
45+++ lib/lp/translations/model/translationimportqueue.py 2010-02-05 15:31:17 +0000
46@@ -320,6 +320,10 @@
47 # that's only possible if we know where to import it
48 # (import_into not None).
49 return self.canAdmin(roles) and self.import_into is not None
50+ if new_status == RosettaImportStatus.NEEDS_INFORMATION:
51+ # Only administrators are able to set the NEEDS_INFORMATION
52+ # status.
53+ return self.canAdmin(roles)
54 if new_status == RosettaImportStatus.IMPORTED:
55 # Only rosetta experts are able to set the IMPORTED status, and
56 # that's only possible if we know where to import it
57
58=== modified file 'lib/lp/translations/stories/importqueue/xx-translation-import-queue-filtering.txt'
59--- lib/lp/translations/stories/importqueue/xx-translation-import-queue-filtering.txt 2009-09-01 21:03:51 +0000
60+++ lib/lp/translations/stories/importqueue/xx-translation-import-queue-filtering.txt 2010-02-05 15:31:17 +0000
61@@ -84,6 +84,7 @@
62 Failed
63 Needs Review
64 Blocked
65+ Needs Information
66
67 >>> print_batch_heading(browser)
68 1 ... 5 of 102 results
69
70=== modified file 'lib/lp/translations/tests/test_translationimportqueue.py'
71--- lib/lp/translations/tests/test_translationimportqueue.py 2010-02-03 12:08:47 +0000
72+++ lib/lp/translations/tests/test_translationimportqueue.py 2010-02-05 15:31:17 +0000
73@@ -45,13 +45,14 @@
74 def _assertCanSetStatus(self, user, entry, expected_list):
75 # Helper to check for all statuses.
76 # Could iterate RosettaImportStatus.items but listing them here
77- # explicitely is better to read. They are sorted alphabetically.
78+ # explicitly is better to read. They are sorted alphabetically.
79 possible_statuses = [
80 RosettaImportStatus.APPROVED,
81 RosettaImportStatus.BLOCKED,
82 RosettaImportStatus.DELETED,
83 RosettaImportStatus.FAILED,
84 RosettaImportStatus.IMPORTED,
85+ RosettaImportStatus.NEEDS_INFORMATION,
86 RosettaImportStatus.NEEDS_REVIEW,
87 ]
88 self._switch_dbuser()
89@@ -64,14 +65,14 @@
90 # A non-privileged users cannot set any status.
91 some_user = self.factory.makePerson()
92 self._assertCanSetStatus(some_user, self.entry,
93- # A B D F I NR
94- [False, False, False, False, False, False])
95+ # A B D F I NI NR
96+ [False, False, False, False, False, False, False])
97
98 def test_canSetStatus_rosetta_expert(self):
99 # Rosetta experts are all-powerful, didn't you know that?
100 self._assertCanSetStatus(self.rosetta_experts, self.entry,
101- # A B D F I NR
102- [True, True, True, True, True, True])
103+ # A B D F I NI NR
104+ [True, True, True, True, True, True, True])
105
106 def test_canSetStatus_rosetta_expert_no_target(self):
107 # If the entry has no import target set, even Rosetta experts
108@@ -79,56 +80,56 @@
109 self.entry.potemplate = None
110 self.entry.pofile = None
111 self._assertCanSetStatus(self.rosetta_experts, self.entry,
112- # A B D F I NR
113- [False, True, True, True, False, True])
114+ # A B D F I NI NR
115+ [False, True, True, True, False, True, True])
116
117 def test_canSetStatus_uploader(self):
118 # The uploader can set some statuses.
119 self._assertCanSetStatus(self.uploaderperson, self.entry,
120- # A B D F I NR
121- [False, False, True, False, False, True])
122+ # A B D F I NI NR
123+ [False, False, True, False, False, False, True])
124
125 def test_canSetStatus_product_owner(self):
126 # The owner (maintainer) of the product gets to set Blocked as well.
127 owner = self.productseries.product.owner
128 self._assertCanSetStatus(owner, self.entry,
129- # A B D F I NR
130- [False, True, True, False, False, True])
131+ # A B D F I NI NR
132+ [False, True, True, False, False, False, True])
133
134 def test_canSetStatus_owner_and_uploader(self):
135 # Corner case: Nothing changes if the maintainer is also the uploader.
136 self.productseries.product.owner = self.uploaderperson
137 self._assertCanSetStatus(self.uploaderperson, self.entry,
138- # A B D F I NR
139- [False, True, True, False, False, True])
140+ # A B D F I NI NR
141+ [False, True, True, False, False, False, True])
142
143 def test_canSetStatus_driver(self):
144 # The driver gets the same permissions as the maintainer.
145 driver = self.productseries.driver
146 self._assertCanSetStatus(driver, self.entry,
147- # A B D F I NR
148- [False, True, True, False, False, True])
149+ # A B D F I NI NR
150+ [False, True, True, False, False, False, True])
151
152 def test_canSetStatus_driver_and_uploader(self):
153 # Corner case: Nothing changes if the driver is also the uploader.
154 self.productseries.driver = self.uploaderperson
155 self._assertCanSetStatus(self.uploaderperson, self.entry,
156- # A B D F I NR
157- [False, True, True, False, False, True])
158+ # A B D F I NI NR
159+ [False, True, True, False, False, False, True])
160
161 def test_canSetStatus_product_driver(self):
162 # The driver of the product, too.
163 driver = self.productseries.product.driver
164 self._assertCanSetStatus(driver, self.entry,
165- # A B D F I NR
166- [False, True, True, False, False, True])
167+ # A B D F I NI NR
168+ [False, True, True, False, False, False, True])
169
170 def test_canSetStatus_product_driver_and_uploader(self):
171 # Corner case: Nothing changes if the driver is also the uploader.
172 self.productseries.product.driver = self.uploaderperson
173 self._assertCanSetStatus(self.uploaderperson, self.entry,
174- # A B D F I NR
175- [False, True, True, False, False, True])
176+ # A B D F I NI NR
177+ [False, True, True, False, False, False, True])
178
179 def _setUpUbuntu(self):
180 self.ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
181@@ -146,16 +147,16 @@
182 sourcepackagename=self.factory.makeSourcePackageName(),
183 potemplate=self.potemplate)
184 self._assertCanSetStatus(self.ubuntu_group_owner, ubuntu_entry,
185- # A B D F I NR
186- [True, True, True, False, False, True])
187+ # A B D F I NI NR
188+ [True, True, True, False, False, True, True])
189
190 def test_canSetStatus_ubuntu_translation_group_not_ubuntu(self):
191 # Outside of Ubuntu, owners of the Ubuntu translation Groups have no
192 # powers.
193 self._setUpUbuntu()
194 self._assertCanSetStatus(self.ubuntu_group_owner, self.entry,
195- # A B D F I NR
196- [False, False, False, False, False, False])
197+ # A B D F I NI NR
198+ [False, False, False, False, False, False, False])
199
200
201 class TestCanSetStatusPOTemplate(TestCanSetStatusBase):