Merge lp:~stevenk/launchpad/db-merge-stable-with-feeling into lp:launchpad/db-devel

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 11866
Proposed branch: lp:~stevenk/launchpad/db-merge-stable-with-feeling
Merge into: lp:launchpad/db-devel
Diff against target: 2267 lines (+358/-723)
42 files modified
lib/lp/app/browser/lazrjs.py (+1/-4)
lib/lp/app/browser/tests/test_inlineeditpickerwidget.py (+1/-11)
lib/lp/app/browser/tests/test_vocabulary.py (+11/-17)
lib/lp/app/javascript/picker/picker_patcher.js (+8/-13)
lib/lp/app/widgets/popup.py (+1/-9)
lib/lp/app/widgets/tests/test_popup.py (+2/-13)
lib/lp/bugs/browser/bug.py (+2/-1)
lib/lp/bugs/browser/tests/test_bug_views.py (+2/-0)
lib/lp/bugs/browser/tests/test_bugtask.py (+4/-2)
lib/lp/bugs/doc/bug.txt (+2/-0)
lib/lp/bugs/doc/bugsubscription.txt (+6/-0)
lib/lp/bugs/javascript/filebug.js (+1/-1)
lib/lp/bugs/javascript/tests/test_filebug.js (+2/-2)
lib/lp/bugs/mail/tests/test_commands.py (+1/-0)
lib/lp/bugs/model/bug.py (+4/-16)
lib/lp/bugs/model/bugtask.py (+5/-8)
lib/lp/bugs/model/tests/test_bug.py (+2/-2)
lib/lp/bugs/model/tests/test_bugsummary.py (+3/-6)
lib/lp/bugs/model/tests/test_bugtask.py (+4/-1)
lib/lp/bugs/model/tests/test_bugtasksearch.py (+0/-3)
lib/lp/bugs/stories/bug-also-affects/xx-bug-also-affects.txt (+1/-0)
lib/lp/code/browser/tests/test_branch.py (+3/-1)
lib/lp/code/model/branch.py (+4/-8)
lib/lp/code/model/tests/test_branchjob.py (+18/-0)
lib/lp/code/model/tests/test_branchnamespace.py (+0/-6)
lib/lp/registry/browser/distribution.py (+1/-7)
lib/lp/registry/browser/pillar.py (+0/-27)
lib/lp/registry/browser/product.py (+1/-7)
lib/lp/registry/browser/tests/test_pillar_sharing.py (+128/-217)
lib/lp/registry/javascript/sharing/pillarsharingview.js (+3/-19)
lib/lp/registry/javascript/sharing/sharingdetailsview.js (+1/-15)
lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js (+0/-19)
lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js (+0/-11)
lib/lp/registry/model/accesspolicy.py (+9/-4)
lib/lp/registry/model/teammembership.py (+5/-8)
lib/lp/registry/services/sharingservice.py (+4/-28)
lib/lp/registry/services/tests/test_sharingservice.py (+97/-200)
lib/lp/registry/tests/test_accesspolicy.py (+17/-0)
lib/lp/registry/tests/test_teammembership.py (+1/-2)
lib/lp/services/features/flags.py (+0/-34)
lib/lp/testing/factory.py (+2/-0)
versions.cfg (+1/-1)
To merge this branch: bzr merge lp:~stevenk/launchpad/db-merge-stable-with-feeling
Reviewer Review Type Date Requested Status
Steve Kowalik (community) code Approve
Review via email: mp+121752@code.launchpad.net

Commit message

Merge stable r15871.

Description of the change

Merge stable r15871.

To post a comment you must log in.
Revision history for this message
Steve Kowalik (stevenk) :
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/app/browser/lazrjs.py'
2--- lib/lp/app/browser/lazrjs.py 2012-08-14 01:57:17 +0000
3+++ lib/lp/app/browser/lazrjs.py 2012-08-29 05:40:35 +0000
4@@ -40,7 +40,6 @@
5 get_person_picker_entry_metadata,
6 vocabulary_filters,
7 )
8-from lp.services.features import getFeatureFlag
9 from lp.services.propertycache import cachedproperty
10 from lp.services.webapp.interfaces import ILaunchBag
11 from lp.services.webapp.publisher import canonical_url
12@@ -423,9 +422,7 @@
13
14 @property
15 def show_create_team(self):
16- return (self._show_create_team
17- and getFeatureFlag(
18- "disclosure.add-team-person-picker.enabled"))
19+ return self._show_create_team
20
21 def getConfig(self):
22 config = super(InlinePersonEditPickerWidget, self).getConfig()
23
24=== modified file 'lib/lp/app/browser/tests/test_inlineeditpickerwidget.py'
25--- lib/lp/app/browser/tests/test_inlineeditpickerwidget.py 2012-06-21 06:50:10 +0000
26+++ lib/lp/app/browser/tests/test_inlineeditpickerwidget.py 2012-08-29 05:40:35 +0000
27@@ -15,7 +15,6 @@
28 InlineEditPickerWidget,
29 InlinePersonEditPickerWidget,
30 )
31-from lp.services.features.testing import FeatureFixture
32 from lp.testing import (
33 login_person,
34 TestCaseWithFactory,
35@@ -118,18 +117,9 @@
36 login_person(self.factory.makePerson())
37 self.assertFalse(widget.config['show_assign_me_button'])
38
39- def test_show_create_team_link_with_feature_flag(self):
40- with FeatureFixture(
41- {'disclosure.add-team-person-picker.enabled': 'true'}):
42- widget = self.getWidget(
43- None, vocabulary='ValidPersonOrTeam', required=True,
44- show_create_team=True)
45- login_person(self.factory.makePerson())
46- self.assertTrue(widget.config['show_create_team'])
47-
48 def test_show_create_team_link(self):
49 widget = self.getWidget(
50 None, vocabulary='ValidPersonOrTeam', required=True,
51 show_create_team=True)
52 login_person(self.factory.makePerson())
53- self.assertFalse(widget.config['show_create_team'])
54+ self.assertTrue(widget.config['show_create_team'])
55
56=== modified file 'lib/lp/app/browser/tests/test_vocabulary.py'
57--- lib/lp/app/browser/tests/test_vocabulary.py 2012-08-13 19:34:10 +0000
58+++ lib/lp/app/browser/tests/test_vocabulary.py 2012-08-29 05:40:35 +0000
59@@ -135,40 +135,35 @@
60 self.assertEqual('sprite person', entry.css)
61 self.assertEqual('sprite new-window', entry.link_css)
62
63- def test_PersonPickerEntrySourceAdapter_enhanced_picker_user(self):
64- # The enhanced person picker provides more information for users.
65+ def test_PersonPickerEntrySourceAdapter_user(self):
66+ # The person picker provides more information for users.
67 person = self.factory.makePerson(email='snarf@eg.dom', name='snarf')
68 creation_date = datetime(
69 2005, 01, 30, 0, 0, 0, 0, pytz.timezone('UTC'))
70 removeSecurityProxy(person).datecreated = creation_date
71 getUtility(IIrcIDSet).new(person, 'eg.dom', 'snarf')
72 getUtility(IIrcIDSet).new(person, 'ex.dom', 'pting')
73- entry = get_picker_entry(
74- person, None, enhanced_picker_enabled=True,
75- picker_expander_enabled=True)
76+ entry = get_picker_entry(person, None, picker_expander_enabled=True)
77 self.assertEqual('http://launchpad.dev/~snarf', entry.alt_title_link)
78 self.assertEqual(
79 ['snarf on eg.dom, pting on ex.dom', 'Member since 2005-01-30'],
80 entry.details)
81
82- def test_PersonPickerEntrySourceAdapter_enhanced_picker_team(self):
83- # The enhanced person picker provides more information for teams.
84+ def test_PersonPickerEntrySourceAdapter_team(self):
85+ # The person picker provides more information for teams.
86 team = self.factory.makeTeam(email='fnord@eg.dom', name='fnord')
87- entry = get_picker_entry(
88- team, None, enhanced_picker_enabled=True,
89- picker_expander_enabled=True)
90+ entry = get_picker_entry(team, None, picker_expander_enabled=True)
91 self.assertEqual('http://launchpad.dev/~fnord', entry.alt_title_link)
92 self.assertEqual(['Team members: 1'], entry.details)
93
94- def test_PersonPickerEntryAdapter_enhanced_picker_enabled_badges(self):
95- # The enhanced person picker provides affiliation information.
96+ def test_PersonPickerEntryAdapter_badges(self):
97+ # The person picker provides affiliation information.
98 person = self.factory.makePerson(email='snarf@eg.dom', name='snarf')
99 project = self.factory.makeProduct(
100 name='fnord', owner=person, bug_supervisor=person)
101 bugtask = self.factory.makeBugTask(target=project)
102 entry = get_picker_entry(
103- person, bugtask, enhanced_picker_enabled=True,
104- picker_expander_enabled=True,
105+ person, bugtask, picker_expander_enabled=True,
106 personpicker_affiliation_enabled=True)
107 self.assertEqual(3, len(entry.badges))
108 self.assertEqual('/@@/product-badge', entry.badges[0]['url'])
109@@ -182,13 +177,12 @@
110 self.assertEqual('bug supervisor', entry.badges[2]['role'])
111
112 def test_PersonPickerEntryAdapter_badges_without_IHasAffiliation(self):
113- # The enhanced person picker handles objects that do not support
114+ # The person picker handles objects that do not support
115 # IHasAffilliation.
116 person = self.factory.makePerson(email='snarf@eg.dom', name='snarf')
117 thing = object()
118 entry = get_picker_entry(
119- person, thing, enhanced_picker_enabled=True,
120- picker_expander_enabled=True,
121+ person, thing, picker_expander_enabled=True,
122 personpicker_affiliation_enabled=True)
123 self.assertIsNot(None, entry)
124
125
126=== modified file 'lib/lp/app/javascript/picker/picker_patcher.js'
127--- lib/lp/app/javascript/picker/picker_patcher.js 2012-07-07 14:00:30 +0000
128+++ lib/lp/app/javascript/picker/picker_patcher.js 2012-08-29 05:40:35 +0000
129@@ -25,19 +25,14 @@
130 return;
131 }
132 var picker_span = show_widget_node.get('parentNode');
133- if (config.enhanced_picker) {
134- var new_node = Y.Node.create('<span>(<a href="#"></a>)</span>');
135- show_widget_node = new_node.one('a');
136- show_widget_node
137- .set('id', show_widget_id)
138- .addClass('js-action')
139- .set('text', 'Choose\u2026');
140- picker_span.empty();
141- picker_span.appendChild(new_node);
142- } else {
143- show_widget_node.set('text', 'Choose\u2026');
144- show_widget_node.addClass('js-action');
145- }
146+ var new_node = Y.Node.create('<span>(<a href="#"></a>)</span>');
147+ show_widget_node = new_node.one('a');
148+ show_widget_node
149+ .set('id', show_widget_id)
150+ .addClass('js-action')
151+ .set('text', 'Choose\u2026');
152+ picker_span.empty();
153+ picker_span.appendChild(new_node);
154 picker_span.removeClass('hidden');
155 show_widget_node.on('click', function (e) {
156 if (picker === null) {
157
158=== modified file 'lib/lp/app/widgets/popup.py'
159--- lib/lp/app/widgets/popup.py 2012-07-07 14:00:30 +0000
160+++ lib/lp/app/widgets/popup.py 2012-08-29 05:40:35 +0000
161@@ -23,7 +23,6 @@
162 get_person_picker_entry_metadata,
163 vocabulary_filters,
164 )
165-from lp.services.features import getFeatureFlag
166 from lp.services.propertycache import cachedproperty
167 from lp.services.webapp import canonical_url
168
169@@ -58,12 +57,6 @@
170 # Defaults to self.vocabulary.displayname.
171 header = None
172
173- @property
174- def enhanced_picker(self):
175- flag = getFeatureFlag(
176- "disclosure.add-team-person-picker.enabled")
177- return flag and self.show_create_team_link
178-
179 @cachedproperty
180 def matches(self):
181 """Return a list of matches (as ITokenizedTerm) to whatever the
182@@ -152,8 +145,7 @@
183 vocabulary_filters=self.vocabulary_filters,
184 input_element=self.input_id,
185 show_widget_id=self.show_widget_id,
186- enhanced_picker=self.enhanced_picker,
187- show_create_team=self.enhanced_picker)
188+ show_create_team=self.show_create_team_link)
189
190 @property
191 def json_config(self):
192
193=== modified file 'lib/lp/app/widgets/tests/test_popup.py'
194--- lib/lp/app/widgets/tests/test_popup.py 2012-06-28 01:27:06 +0000
195+++ lib/lp/app/widgets/tests/test_popup.py 2012-08-29 05:40:35 +0000
196@@ -13,7 +13,6 @@
197 PersonPickerWidget,
198 VocabularyPickerWidget,
199 )
200-from lp.services.features.testing import FeatureFixture
201 from lp.services.webapp.servers import LaunchpadTestRequest
202 from lp.testing import TestCaseWithFactory
203 from lp.testing.layers import DatabaseFunctionalLayer
204@@ -170,24 +169,14 @@
205 self.assertFalse(person_picker_widget.config['show_remove_button'])
206
207 def test_create_team_link(self):
208- # The person picker widget shows a create team link if the feature flag
209- # is on.
210+ # The person picker widget shows a create team link.
211 field = ITest['test_valid.item']
212 bound_field = field.bind(self.context)
213
214- with FeatureFixture(
215- {'disclosure.add-team-person-picker.enabled': 'true'}):
216- picker_widget = PersonPickerWidget(
217- bound_field, self.vocabulary, self.request)
218- picker_widget.show_create_team_link = True
219- self.assertTrue(picker_widget.config['show_create_team'])
220- self.assertTrue(picker_widget.config['enhanced_picker'])
221-
222 picker_widget = PersonPickerWidget(
223 bound_field, self.vocabulary, self.request)
224 picker_widget.show_create_team_link = True
225- self.assertFalse(picker_widget.config['show_create_team'])
226- self.assertFalse(picker_widget.config['enhanced_picker'])
227+ self.assertTrue(picker_widget.config['show_create_team'])
228
229 def test_widget_personvalue_meta(self):
230 # The person picker has the correct meta value for a person value.
231
232=== modified file 'lib/lp/bugs/browser/bug.py'
233--- lib/lp/bugs/browser/bug.py 2012-08-24 12:49:00 +0000
234+++ lib/lp/bugs/browser/bug.py 2012-08-29 05:40:35 +0000
235@@ -2,7 +2,6 @@
236 # GNU Affero General Public License version 3 (see the file LICENSE).
237
238 """IBug related view classes."""
239-from lp.app.interfaces.services import IService
240
241 __metaclass__ = type
242
243@@ -72,6 +71,7 @@
244 LaunchpadFormView,
245 )
246 from lp.app.errors import NotFoundError
247+from lp.app.interfaces.services import IService
248 from lp.app.widgets.itemswidgets import LaunchpadRadioWidgetWithDescription
249 from lp.app.widgets.product import GhostCheckBoxWidget
250 from lp.app.widgets.project import ProjectScopeWidget
251@@ -881,6 +881,7 @@
252 if self.request.is_ajax:
253 validate_change = data.get('validate_change', False)
254 if (validate_change and
255+ information_type in PRIVATE_INFORMATION_TYPES and
256 self._bug_will_be_invisible(information_type)):
257 self.request.response.setStatus(400, "Bug Visibility")
258 return ''
259
260=== modified file 'lib/lp/bugs/browser/tests/test_bug_views.py'
261--- lib/lp/bugs/browser/tests/test_bug_views.py 2012-08-24 12:49:00 +0000
262+++ lib/lp/bugs/browser/tests/test_bug_views.py 2012-08-29 05:40:35 +0000
263@@ -97,6 +97,7 @@
264 # We expect that only the Also Affects Project link is disallowed.
265 distro = self.factory.makeDistribution()
266 owner = self.factory.makePerson()
267+ self.factory.makeAccessPolicy(pillar=distro)
268 bug = self.factory.makeBug(
269 target=distro,
270 information_type=InformationType.PROPRIETARY, owner=owner)
271@@ -402,6 +403,7 @@
272 # bug will become invisible but and no visibility check is performed.
273 product = self.factory.makeProduct(
274 bug_sharing_policy=BugSharingPolicy.PUBLIC_OR_PROPRIETARY)
275+ self.factory.makeAccessPolicy(pillar=product)
276 bug = self.factory.makeBug(target=product)
277 self._assert_secrecy_view_ajax_render(bug, 'PROPRIETARY', False)
278
279
280=== modified file 'lib/lp/bugs/browser/tests/test_bugtask.py'
281--- lib/lp/bugs/browser/tests/test_bugtask.py 2012-08-21 20:41:05 +0000
282+++ lib/lp/bugs/browser/tests/test_bugtask.py 2012-08-29 05:40:35 +0000
283@@ -140,12 +140,12 @@
284 self.getUserBrowser(url, person_no_teams)
285 # This may seem large: it is; there is easily another 30% fat in
286 # there.
287- # If this test is run in isolation, the query count is 89.
288+ # If this test is run in isolation, the query count is 94.
289 # Other tests in this TestCase could cache the
290 # "SELECT id, product, project, distribution FROM PillarName ..."
291 # query by previously browsing the task url, in which case the
292 # query count is decreased by one.
293- self.assertThat(recorder, HasQueryCount(LessThan(94)))
294+ self.assertThat(recorder, HasQueryCount(LessThan(95)))
295 count_with_no_teams = recorder.count
296 # count with many teams
297 self.invalidate_caches(task)
298@@ -1120,6 +1120,7 @@
299 # could affect another package.
300 distro = self.factory.makeDistribution()
301 owner = self.factory.makePerson()
302+ self.factory.makeAccessPolicy(pillar=distro)
303 bug = self.factory.makeBug(
304 target=distro, owner=owner,
305 information_type=InformationType.PROPRIETARY)
306@@ -1140,6 +1141,7 @@
307 sp = self.factory.makeSourcePackage(
308 sourcepackagename=sp_name, distroseries=distroseries)
309 owner = self.factory.makePerson()
310+ self.factory.makeAccessPolicy(pillar=distro)
311 bug = self.factory.makeBug(
312 target=sp.distribution_sourcepackage, owner=owner,
313 information_type=InformationType.PROPRIETARY)
314
315=== modified file 'lib/lp/bugs/doc/bug.txt'
316--- lib/lp/bugs/doc/bug.txt 2012-08-08 11:48:29 +0000
317+++ lib/lp/bugs/doc/bug.txt 2012-08-29 05:40:35 +0000
318@@ -662,6 +662,7 @@
319 ... comment="a description of the bug",
320 ... owner=current_user())
321 >>> private_bug = firefox.createBug(params)
322+ >>> ignored = factory.makeAccessPolicy(pillar=firefox)
323 >>> private_bug.transitionToInformationType(
324 ... InformationType.PROPRIETARY, current_user())
325 True
326@@ -730,6 +731,7 @@
327 We cannot add distro series or source package tasks for different distros.
328
329 >>> private_bug = tubuntu.createBug(params)
330+ >>> ignored = factory.makeAccessPolicy(pillar=tubuntu)
331 >>> private_bug.transitionToInformationType(
332 ... InformationType.PROPRIETARY, current_user())
333 True
334
335=== modified file 'lib/lp/bugs/doc/bugsubscription.txt'
336--- lib/lp/bugs/doc/bugsubscription.txt 2012-08-22 23:02:40 +0000
337+++ lib/lp/bugs/doc/bugsubscription.txt 2012-08-29 05:40:35 +0000
338@@ -364,6 +364,7 @@
339
340 >>> print_displayname(linux_source_bug.getDirectSubscribers())
341 Foo Bar
342+ Mark Shuttleworth
343 Robert Collins
344
345 Direct subscriptions always take precedence over indirect subscriptions.
346@@ -375,6 +376,7 @@
347
348 >>> print_displayname(linux_source_bug.getDirectSubscribers())
349 Foo Bar
350+ Mark Shuttleworth
351 Robert Collins
352
353 >>> print_displayname(linux_source_bug.getIndirectSubscribers())
354@@ -398,6 +400,7 @@
355 >>> addresses = recipients.getEmails()
356 >>> [(address, recipients.getReason(address)[1]) for address in addresses]
357 [('foo.bar@canonical.com', 'Subscriber'),
358+ ('mark@example.com', 'Subscriber'),
359 ('no-priv@canonical.com', u'Subscriber (linux-source-2.6.15 in Ubuntu)'),
360 ('robertc@robertcollins.net', 'Subscriber'),
361 ('test@canonical.com', 'Assignee')]
362@@ -411,6 +414,7 @@
363 >>> addresses = recipients.getEmails()
364 >>> [(address, recipients.getReason(address)[1]) for address in addresses]
365 [('foo.bar@canonical.com', 'Subscriber'),
366+ ('mark@example.com', 'Subscriber'),
367 ('robertc@robertcollins.net', 'Subscriber'),
368 ('test@canonical.com', 'Assignee')]
369
370@@ -424,6 +428,7 @@
371 >>> addresses = recipients.getEmails()
372 >>> [(address, recipients.getReason(address)[1]) for address in addresses]
373 [('foo.bar@canonical.com', 'Subscriber'),
374+ ('mark@example.com', 'Subscriber'),
375 ('robertc@robertcollins.net', 'Subscriber'),
376 ('test@canonical.com', 'Assignee')]
377
378@@ -435,6 +440,7 @@
379 >>> addresses = recipients.getEmails()
380 >>> [(address, recipients.getReason(address)[1]) for address in addresses]
381 [('foo.bar@canonical.com', 'Subscriber'),
382+ ('mark@example.com', 'Subscriber'),
383 ('no-priv@canonical.com', u'Subscriber (linux-source-2.6.15 in Ubuntu)'),
384 ('robertc@robertcollins.net', 'Subscriber'),
385 ('test@canonical.com', 'Assignee')]
386
387=== modified file 'lib/lp/bugs/javascript/filebug.js'
388--- lib/lp/bugs/javascript/filebug.js 2012-08-21 13:27:00 +0000
389+++ lib/lp/bugs/javascript/filebug.js 2012-08-29 05:40:35 +0000
390@@ -69,7 +69,7 @@
391 Y.Array.forEach(LP.cache.information_type_data, function(item) {
392 info_type_descriptions[item.value] = item.name;
393 });
394- var text_template = "This report has {info_type} information." +
395+ var text_template = "This report contains {info_type} information." +
396 " You can change the information type later.";
397 value = info_type_descriptions[value];
398 return Y.Lang.substitute(text_template, {'info_type': value});
399
400=== modified file 'lib/lp/bugs/javascript/tests/test_filebug.js'
401--- lib/lp/bugs/javascript/tests/test_filebug.js 2012-07-19 03:18:37 +0000
402+++ lib/lp/bugs/javascript/tests/test_filebug.js 2012-08-29 05:40:35 +0000
403@@ -91,7 +91,7 @@
404 Y.Assert.isNull(banner_hidden);
405 var banner_text = Y.one('.banner-text').get('text');
406 Y.Assert.areEqual(
407- 'This report has Private Security information. ' +
408+ 'This report contains Private Security information. ' +
409 'You can change the information type later.', banner_text);
410 },
411
412@@ -281,7 +281,7 @@
413 Y.Assert.isNull(banner_hidden);
414 var banner_text = Y.one('.banner-text').get('text');
415 Y.Assert.areEqual(
416- 'This report has Private information. ' +
417+ 'This report contains Private information. ' +
418 'You can change the information type later.', banner_text);
419 },
420
421
422=== modified file 'lib/lp/bugs/mail/tests/test_commands.py'
423--- lib/lp/bugs/mail/tests/test_commands.py 2012-08-21 19:19:32 +0000
424+++ lib/lp/bugs/mail/tests/test_commands.py 2012-08-29 05:40:35 +0000
425@@ -287,6 +287,7 @@
426 # Test that attempts to invalidly add a new bug task results in the
427 # expected error message.
428 product = self.factory.makeProduct()
429+ self.factory.makeAccessPolicy(pillar=product)
430 bug = self.factory.makeBug(
431 target=product, information_type=InformationType.PROPRIETARY)
432 self.factory.makeProduct(name='fnord')
433
434=== modified file 'lib/lp/bugs/model/bug.py'
435--- lib/lp/bugs/model/bug.py 2012-08-23 04:20:48 +0000
436+++ lib/lp/bugs/model/bug.py 2012-08-29 05:40:35 +0000
437@@ -200,7 +200,6 @@
438 sqlvalues,
439 )
440 from lp.services.database.stormbase import StormBase
441-from lp.services.features import getFeatureFlag
442 from lp.services.fields import DuplicateBug
443 from lp.services.helpers import shortlist
444 from lp.services.librarian.interfaces import ILibraryFileAliasSet
445@@ -1766,18 +1765,10 @@
446 if pillar.driver in subscribers and pillar != ubuntu:
447 required_subscribers.add(pillar.driver)
448 service = getUtility(IService, 'sharing')
449- subscribers_to_remove = set(service.getPeopleWithoutAccess(
450- self, subscribers)).difference(required_subscribers)
451 if len(required_subscribers):
452 service.ensureAccessGrants(
453 required_subscribers, who, bugs=[self],
454 ignore_permissions=True)
455- # There is a job to do the unsubscribe, but it's behind a
456- # flag. If that flag is not set, do it manually.
457- if len(subscribers_to_remove) and not bool(
458- getFeatureFlag('disclosure.unsubscribe_jobs.enabled')):
459- for s in subscribers_to_remove:
460- self.unsubscribe(s, who, ignore_permissions=True)
461
462 # Add the required subscribers, but not if they are all already
463 # subscribed via a team.
464@@ -1788,13 +1779,10 @@
465
466 self.updateHeat()
467
468- flag = 'disclosure.unsubscribe_jobs.enabled'
469- if bool(getFeatureFlag(flag)):
470- # As a result of the transition, some subscribers may no longer
471- # have access to the bug. We need to run a job to remove any such
472- # subscriptions.
473- getUtility(IRemoveArtifactSubscriptionsJobSource).create(
474- who, [self])
475+ # As a result of the transition, some subscribers may no longer
476+ # have access to the bug. We need to run a job to remove any such
477+ # subscriptions.
478+ getUtility(IRemoveArtifactSubscriptionsJobSource).create(who, [self])
479
480 return True
481
482
483=== modified file 'lib/lp/bugs/model/bugtask.py'
484--- lib/lp/bugs/model/bugtask.py 2012-08-24 01:17:35 +0000
485+++ lib/lp/bugs/model/bugtask.py 2012-08-29 05:40:35 +0000
486@@ -141,7 +141,6 @@
487 SQLBase,
488 sqlvalues,
489 )
490-from lp.services.features import getFeatureFlag
491 from lp.services.helpers import shortlist
492 from lp.services.propertycache import get_property_cache
493 from lp.services.searchbuilder import any
494@@ -1140,13 +1139,11 @@
495 self.maybeConfirm()
496 # END TEMPORARY BIT FOR BUGTASK AUTOCONFIRM FEATURE FLAG.
497
498- flag = 'disclosure.unsubscribe_jobs.enabled'
499- if bool(getFeatureFlag(flag)):
500- # As a result of the transition, some subscribers may no longer
501- # have access to the parent bug. We need to run a job to remove any
502- # such subscriptions.
503- getUtility(IRemoveArtifactSubscriptionsJobSource).create(
504- user, [self.bug], pillar=target_before_change.pillar)
505+ # As a result of the transition, some subscribers may no longer
506+ # have access to the parent bug. We need to run a job to remove any
507+ # such subscriptions.
508+ getUtility(IRemoveArtifactSubscriptionsJobSource).create(
509+ user, [self.bug], pillar=target_before_change.pillar)
510
511 def updateTargetNameCache(self, newtarget=None):
512 """See `IBugTask`."""
513
514=== modified file 'lib/lp/bugs/model/tests/test_bug.py'
515--- lib/lp/bugs/model/tests/test_bug.py 2012-08-23 04:20:48 +0000
516+++ lib/lp/bugs/model/tests/test_bug.py 2012-08-29 05:40:35 +0000
517@@ -639,7 +639,7 @@
518 who = self.factory.makePerson(name='who')
519 bug.transitionToInformationType(
520 InformationType.PRIVATESECURITY, who=who)
521- subscribers = bug.getDirectSubscribers()
522+ subscribers = bug.getDirectSubscribers(filter_visible=True)
523 expected_subscribers = set((
524 default_bugtask.pillar.driver, bug_owner, who))
525 self.assertContentEqual(expected_subscribers, subscribers)
526@@ -662,7 +662,7 @@
527 bug.subscribe(subscriber, bug_owner)
528 who = self.factory.makePerson(name='who')
529 bug.transitionToInformationType(InformationType.USERDATA, who)
530- subscribers = bug.getDirectSubscribers()
531+ subscribers = bug.getDirectSubscribers(filter_visible=True)
532 expected_subscribers = set((
533 default_bugtask.pillar.bug_supervisor,
534 default_bugtask.pillar.driver,
535
536=== modified file 'lib/lp/bugs/model/tests/test_bugsummary.py'
537--- lib/lp/bugs/model/tests/test_bugsummary.py 2012-08-08 11:48:29 +0000
538+++ lib/lp/bugs/model/tests/test_bugsummary.py 2012-08-29 05:40:35 +0000
539@@ -28,7 +28,6 @@
540 SharingPermission,
541 )
542 from lp.services.database.lpstorm import IMasterStore
543-from lp.services.features.testing import FeatureFixture
544 from lp.testing import TestCaseWithFactory
545 from lp.testing.dbuser import switch_dbuser
546 from lp.testing.layers import LaunchpadZopelessLayer
547@@ -192,11 +191,9 @@
548 person_b = self.factory.makePerson()
549 person_c = self.factory.makePerson()
550 product = self.factory.makeProduct()
551- with FeatureFixture(
552- {'disclosure.enhanced_sharing.writable': 'true'}):
553- getUtility(IService, 'sharing').sharePillarInformation(
554- product, person_c, product.owner,
555- {InformationType.USERDATA: SharingPermission.ALL})
556+ getUtility(IService, 'sharing').sharePillarInformation(
557+ product, person_c, product.owner,
558+ {InformationType.USERDATA: SharingPermission.ALL})
559 bug = self.factory.makeBug(target=product, owner=person_b)
560
561 bug.subscribe(person=person_a, subscribed_by=person_a)
562
563=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
564--- lib/lp/bugs/model/tests/test_bugtask.py 2012-08-21 15:13:25 +0000
565+++ lib/lp/bugs/model/tests/test_bugtask.py 2012-08-29 05:40:35 +0000
566@@ -2678,7 +2678,6 @@
567
568 def setUp(self):
569 self.useFixture(FeatureFixture({
570- 'disclosure.unsubscribe_jobs.enabled': 'true',
571 'jobs.celery.enabled_classes': 'RemoveArtifactSubscriptionsJob',
572 }))
573 super(TestTransitionsRemovesSubscribersJob, self).setUp()
574@@ -2856,6 +2855,7 @@
575 if not self.multi_tenant_test_one_task_only:
576 self.factory.makeBugTask(bug=bug)
577 p = self.factory.makeProduct()
578+ self.factory.makeAccessPolicy(pillar=d)
579 with person_logged_in(bug.owner):
580 bug.transitionToInformationType(
581 InformationType.PROPRIETARY, bug.owner)
582@@ -2877,6 +2877,7 @@
583 bug = self.factory.makeBug(target=p1)
584 if not self.multi_tenant_test_one_task_only:
585 self.factory.makeBugTask(bug=bug)
586+ self.factory.makeAccessPolicy(pillar=p1)
587 with person_logged_in(bug.owner):
588 bug.transitionToInformationType(
589 InformationType.PROPRIETARY, bug.owner)
590@@ -2905,6 +2906,7 @@
591 bug = self.factory.makeBug(target=p1)
592 if not self.multi_tenant_test_one_task_only:
593 self.factory.makeBugTask(bug=bug)
594+ self.factory.makeAccessPolicy(pillar=p1)
595 with person_logged_in(bug.owner):
596 bug.transitionToInformationType(
597 InformationType.PROPRIETARY, bug.owner)
598@@ -2927,6 +2929,7 @@
599 bug = self.factory.makeBug(target=d1)
600 if not self.multi_tenant_test_one_task_only:
601 self.factory.makeBugTask(bug=bug)
602+ self.factory.makeAccessPolicy(pillar=d1)
603 with person_logged_in(bug.owner):
604 bug.transitionToInformationType(
605 InformationType.PROPRIETARY, bug.owner)
606
607=== modified file 'lib/lp/bugs/model/tests/test_bugtasksearch.py'
608--- lib/lp/bugs/model/tests/test_bugtasksearch.py 2012-08-16 05:18:54 +0000
609+++ lib/lp/bugs/model/tests/test_bugtasksearch.py 2012-08-29 05:40:35 +0000
610@@ -67,7 +67,6 @@
611 from lp.registry.model.person import Person
612 from lp.services.database.lpstorm import IStore
613 from lp.services.database.sqlbase import convert_storm_clause_to_string
614-from lp.services.features.testing import FeatureFixture
615 from lp.services.searchbuilder import (
616 all,
617 any,
618@@ -2410,8 +2409,6 @@
619 # People and teams with AccessPolicyGrants can see the bug.
620 self.makePrivacyScenario()
621
622- self.useFixture(FeatureFixture(
623- {'disclosure.enhanced_sharing.writable': 'true'}))
624 with admin_logged_in():
625 for princ in (self.grantee_team, self.grantee_person):
626 getUtility(IService, 'sharing').sharePillarInformation(
627
628=== modified file 'lib/lp/bugs/stories/bug-also-affects/xx-bug-also-affects.txt'
629--- lib/lp/bugs/stories/bug-also-affects/xx-bug-also-affects.txt 2012-07-10 08:12:53 +0000
630+++ lib/lp/bugs/stories/bug-also-affects/xx-bug-also-affects.txt 2012-08-29 05:40:35 +0000
631@@ -215,6 +215,7 @@
632 >>> login("foo.bar@canonical.com")
633 >>> productset = getUtility(IProductSet)
634 >>> firefox = productset.get(4)
635+ >>> ignored = factory.makeAccessPolicy(pillar=firefox)
636 >>> params = CreateBugParams(
637 ... title="a test private bug",
638 ... comment="a description of the bug",
639
640=== modified file 'lib/lp/code/browser/tests/test_branch.py'
641--- lib/lp/code/browser/tests/test_branch.py 2012-08-22 14:23:12 +0000
642+++ lib/lp/code/browser/tests/test_branch.py 2012-08-29 05:40:35 +0000
643@@ -1028,8 +1028,10 @@
644 # We don't force branches with a disallowed type (eg. Proprietary on a
645 # non-commercial project) to change, so the current type is
646 # shown.
647+ product = self.factory.makeProduct()
648+ self.factory.makeAccessPolicy(pillar=product)
649 branch = self.factory.makeBranch(
650- information_type=InformationType.PROPRIETARY)
651+ product=product, information_type=InformationType.PROPRIETARY)
652 self.assertShownTypes(
653 [InformationType.PUBLIC, InformationType.PROPRIETARY], branch)
654
655
656=== modified file 'lib/lp/code/model/branch.py'
657--- lib/lp/code/model/branch.py 2012-08-07 02:31:56 +0000
658+++ lib/lp/code/model/branch.py 2012-08-29 05:40:35 +0000
659@@ -171,7 +171,6 @@
660 ArrayAgg,
661 ArrayIntersects,
662 )
663-from lp.services.features import getFeatureFlag
664 from lp.services.helpers import shortlist
665 from lp.services.job.interfaces.job import JobStatus
666 from lp.services.job.model.job import Job
667@@ -272,13 +271,10 @@
668 service.ensureAccessGrants(
669 blind_subscribers, who, branches=[self],
670 ignore_permissions=True)
671- flag = 'disclosure.unsubscribe_jobs.enabled'
672- if bool(getFeatureFlag(flag)):
673- # As a result of the transition, some subscribers may no longer
674- # have access to the branch. We need to run a job to remove any
675- # such subscriptions.
676- getUtility(IRemoveArtifactSubscriptionsJobSource).create(
677- who, [self])
678+ # As a result of the transition, some subscribers may no longer
679+ # have access to the branch. We need to run a job to remove any
680+ # such subscriptions.
681+ getUtility(IRemoveArtifactSubscriptionsJobSource).create(who, [self])
682
683 registrant = ForeignKey(
684 dbName='registrant', foreignKey='Person',
685
686=== modified file 'lib/lp/code/model/tests/test_branchjob.py'
687--- lib/lp/code/model/tests/test_branchjob.py 2012-06-28 01:14:33 +0000
688+++ lib/lp/code/model/tests/test_branchjob.py 2012-08-29 05:40:35 +0000
689@@ -65,6 +65,7 @@
690 from lp.code.model.revision import RevisionSet
691 from lp.code.model.tests.test_branch import create_knit
692 from lp.codehosting.vfs import branch_id_to_path
693+from lp.registry.enums import InformationType
694 from lp.scripts.helpers import TransactionFreeOperation
695 from lp.services.config import config
696 from lp.services.database.constants import UTC_NOW
697@@ -173,6 +174,23 @@
698
699 self.assertEqual(db_branch.revision_count, 5)
700
701+ def test_run_with_private_linked_bug(self):
702+ """Ensure the job scans a branch with a private bug in the revprops."""
703+ self.useBzrBranches(direct_database=True)
704+ db_branch, bzr_tree = self.create_branch_and_tree()
705+ product = self.factory.makeProduct()
706+ private_bug = self.factory.makeBug(
707+ target=product, information_type=InformationType.USERDATA)
708+ bug_line = 'https://launchpad.net/bugs/%s fixed' % private_bug.id
709+ with override_environ(BZR_EMAIL='me@example.com'):
710+ bzr_tree.commit(
711+ 'First commit', rev_id='rev1', revprops={'bugs': bug_line})
712+ job = BranchScanJob.create(db_branch)
713+ with dbuser(config.branchscanner.dbuser):
714+ job.run()
715+ self.assertEqual(db_branch.revision_count, 1)
716+ self.assertTrue(private_bug.hasBranch(db_branch))
717+
718
719 class TestBranchUpgradeJob(TestCaseWithFactory):
720 """Tests for `BranchUpgradeJob`."""
721
722=== modified file 'lib/lp/code/model/tests/test_branchnamespace.py'
723--- lib/lp/code/model/tests/test_branchnamespace.py 2012-08-22 14:23:12 +0000
724+++ lib/lp/code/model/tests/test_branchnamespace.py 2012-08-29 05:40:35 +0000
725@@ -57,7 +57,6 @@
726 )
727 from lp.registry.interfaces.product import NoSuchProduct
728 from lp.registry.model.sourcepackage import SourcePackage
729-from lp.services.features.testing import FeatureFixture
730 from lp.testing import (
731 person_logged_in,
732 TestCaseWithFactory,
733@@ -458,11 +457,6 @@
734
735 layer = DatabaseFunctionalLayer
736
737- def setUp(self):
738- super(TestProductNamespacePrivacyWithInformationType, self).setUp()
739- self.useFixture(FeatureFixture(
740- {'disclosure.enhanced_sharing.writable': 'true'}))
741-
742 def makeProductNamespace(self, sharing_policy, person=None):
743 if person is None:
744 person = self.factory.makePerson()
745
746=== modified file 'lib/lp/registry/browser/distribution.py'
747--- lib/lp/registry/browser/distribution.py 2012-08-21 00:34:02 +0000
748+++ lib/lp/registry/browser/distribution.py 2012-08-29 05:40:35 +0000
749@@ -108,7 +108,6 @@
750 )
751 from lp.registry.interfaces.series import SeriesStatus
752 from lp.services.database.decoratedresultset import DecoratedResultSet
753-from lp.services.features import getFeatureFlag
754 from lp.services.feeds.browser import FeedsMixin
755 from lp.services.geoip.helpers import (
756 ipaddress_from_request,
757@@ -313,12 +312,7 @@
758
759 @enabled_with_permission('launchpad.Driver')
760 def sharing(self):
761- text = 'Sharing'
762- enabled_readonly_flag = 'disclosure.enhanced_sharing.enabled'
763- enabled_writable_flag = 'disclosure.enhanced_sharing.writable'
764- enabled = (bool(getFeatureFlag(enabled_readonly_flag))
765- or bool(getFeatureFlag(enabled_writable_flag)))
766- return Link('+sharing', text, icon='edit', enabled=enabled)
767+ return Link('+sharing', 'Sharing', icon='edit')
768
769 @cachedproperty
770 def links(self):
771
772=== modified file 'lib/lp/registry/browser/pillar.py'
773--- lib/lp/registry/browser/pillar.py 2012-08-23 04:42:37 +0000
774+++ lib/lp/registry/browser/pillar.py 2012-08-29 05:40:35 +0000
775@@ -31,7 +31,6 @@
776 getVocabularyRegistry,
777 SimpleVocabulary,
778 )
779-from zope.security.interfaces import Unauthorized
780 from zope.traversing.browser.absoluteurl import absoluteURL
781
782 from lp.app.browser.launchpad import iter_view_registrations
783@@ -60,9 +59,7 @@
784 from lp.registry.interfaces.projectgroup import IProjectGroup
785 from lp.registry.model.pillar import PillarPerson
786 from lp.services.config import config
787-from lp.services.features import getFeatureFlag
788 from lp.services.propertycache import cachedproperty
789-from lp.services.webapp.authorization import check_permission
790 from lp.services.webapp.batching import (
791 BatchNavigator,
792 StormRangeFactory,
793@@ -278,11 +275,6 @@
794
795 sharing_vocabulary_name = 'NewPillarGrantee'
796
797- related_features = (
798- 'disclosure.enhanced_sharing.enabled',
799- 'disclosure.enhanced_sharing.writable',
800- )
801-
802 _batch_navigator = None
803
804 def _getSharingService(self):
805@@ -348,16 +340,7 @@
806
807 def initialize(self):
808 super(PillarSharingView, self).initialize()
809- enabled_readonly_flag = 'disclosure.enhanced_sharing.enabled'
810- enabled_writable_flag = (
811- 'disclosure.enhanced_sharing.writable')
812- enabled = bool(getFeatureFlag(enabled_readonly_flag))
813- write_flag_enabled = bool(getFeatureFlag(enabled_writable_flag))
814- if not enabled and not write_flag_enabled:
815- raise Unauthorized("This feature is not yet available.")
816 cache = IJSONRequestCache(self.request)
817- cache.objects['sharing_write_enabled'] = (write_flag_enabled
818- and check_permission('launchpad.Edit', self.context))
819 cache.objects['information_types'] = self.information_types
820 cache.objects['sharing_permissions'] = self.sharing_permissions
821 cache.objects['bug_sharing_policies'] = self.bug_sharing_policies
822@@ -402,11 +385,6 @@
823 label = "Information shared with person or team"
824
825 def initialize(self):
826- enabled_flag = 'disclosure.enhanced_sharing_details.enabled'
827- enabled = bool(getFeatureFlag(enabled_flag))
828- if not enabled:
829- raise Unauthorized("This feature is not yet available.")
830-
831 self.pillar = self.context.pillar
832 self.person = self.context.person
833
834@@ -431,11 +409,6 @@
835 cache.objects['pillar'] = pillar_data
836 cache.objects['bugs'] = bug_data
837 cache.objects['branches'] = branch_data
838- enabled_writable_flag = (
839- 'disclosure.enhanced_sharing.writable')
840- write_flag_enabled = bool(getFeatureFlag(enabled_writable_flag))
841- cache.objects['sharing_write_enabled'] = (write_flag_enabled
842- and check_permission('launchpad.Edit', self.pillar))
843
844 def _loadSharedArtifacts(self):
845 # As a concrete can by linked via more than one policy, we use sets to
846
847=== modified file 'lib/lp/registry/browser/product.py'
848--- lib/lp/registry/browser/product.py 2012-08-23 04:42:37 +0000
849+++ lib/lp/registry/browser/product.py 2012-08-29 05:40:35 +0000
850@@ -171,7 +171,6 @@
851 from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
852 from lp.services.config import config
853 from lp.services.database.decoratedresultset import DecoratedResultSet
854-from lp.services.features import getFeatureFlag
855 from lp.services.feeds.browser import FeedsMixin
856 from lp.services.fields import (
857 PillarAliases,
858@@ -500,12 +499,7 @@
859
860 @enabled_with_permission('launchpad.Driver')
861 def sharing(self):
862- text = 'Sharing'
863- enabled_readonly_flag = 'disclosure.enhanced_sharing.enabled'
864- enabled_writable_flag = 'disclosure.enhanced_sharing.writable'
865- enabled = (bool(getFeatureFlag(enabled_readonly_flag))
866- or bool(getFeatureFlag(enabled_writable_flag)))
867- return Link('+sharing', text, icon='edit', enabled=enabled)
868+ return Link('+sharing', 'Sharing', icon='edit')
869
870
871 class IProductEditMenu(Interface):
872
873=== modified file 'lib/lp/registry/browser/tests/test_pillar_sharing.py'
874--- lib/lp/registry/browser/tests/test_pillar_sharing.py 2012-08-14 04:48:36 +0000
875+++ lib/lp/registry/browser/tests/test_pillar_sharing.py 2012-08-29 05:40:35 +0000
876@@ -17,7 +17,6 @@
877 Raises,
878 )
879 from zope.component import getUtility
880-from zope.security.interfaces import Unauthorized
881 from zope.traversing.browser.absoluteurl import absoluteURL
882
883 from lp.app.interfaces.services import IService
884@@ -30,7 +29,6 @@
885 from lp.registry.model.pillar import PillarPerson
886 from lp.services.config import config
887 from lp.services.database.lpstorm import IStore
888-from lp.services.features.testing import FeatureFixture
889 from lp.services.webapp.interfaces import StormRangeFactoryError
890 from lp.services.webapp.publisher import canonical_url
891 from lp.testing import (
892@@ -49,14 +47,6 @@
893 )
894
895
896-DETAILS_ENABLED_FLAG = {'disclosure.enhanced_sharing_details.enabled': 'true'}
897-DETAILS_WRITE_FLAG = {
898- 'disclosure.enhanced_sharing_details.enabled': 'true',
899- 'disclosure.enhanced_sharing.writable': 'true'}
900-ENABLED_FLAG = {'disclosure.enhanced_sharing.enabled': 'true'}
901-WRITE_FLAG = {'disclosure.enhanced_sharing.writable': 'true'}
902-
903-
904 class SharingBaseTestCase(TestCaseWithFactory):
905
906 layer = DatabaseFunctionalLayer
907@@ -146,124 +136,94 @@
908 # There are bugs in the sharingdetails view that not everyone with
909 # `launchpad.Driver` -- the permission level for the page -- should be
910 # able to see.
911- with FeatureFixture(DETAILS_ENABLED_FLAG):
912- pillarperson = self.getPillarPerson(security=True)
913- logout()
914- login_person(self.driver)
915- view = create_initialized_view(pillarperson, '+index')
916- # The page loads
917- self.assertEqual(pillarperson.person.displayname, view.page_title)
918- # The bug, which is not shared with the driver, is not included.
919- self.assertEqual(0, view.shared_bugs_count)
920+ pillarperson = self.getPillarPerson(security=True)
921+ logout()
922+ login_person(self.driver)
923+ view = create_initialized_view(pillarperson, '+index')
924+ # The page loads
925+ self.assertEqual(pillarperson.person.displayname, view.page_title)
926+ # The bug, which is not shared with the driver, is not included.
927+ self.assertEqual(0, view.shared_bugs_count)
928
929 def test_view_traverses_plus_sharingdetails(self):
930 # The traversed url in the app is pillar/+sharing/person
931- with FeatureFixture(DETAILS_ENABLED_FLAG):
932- # We have to do some fun url hacking to force the traversal a user
933- # encounters.
934- pillarperson = self.getPillarPerson()
935- expected = "Sharing details for %s : Sharing : %s" % (
936- pillarperson.person.displayname,
937- pillarperson.pillar.displayname)
938- url = 'http://launchpad.dev/%s/+sharing/%s' % (
939- pillarperson.pillar.name, pillarperson.person.name)
940- browser = self.getUserBrowser(user=self.owner, url=url)
941- self.assertEqual(expected, browser.title)
942+ # We have to do some fun url hacking to force the traversal a user
943+ # encounters.
944+ pillarperson = self.getPillarPerson()
945+ expected = "Sharing details for %s : Sharing : %s" % (
946+ pillarperson.person.displayname,
947+ pillarperson.pillar.displayname)
948+ url = 'http://launchpad.dev/%s/+sharing/%s' % (
949+ pillarperson.pillar.name, pillarperson.person.name)
950+ browser = self.getUserBrowser(user=self.owner, url=url)
951+ self.assertEqual(expected, browser.title)
952
953 def test_no_sharing_message(self):
954 # If there is no sharing between pillar and person, a suitable message
955 # is displayed.
956- with FeatureFixture(DETAILS_ENABLED_FLAG):
957- # We have to do some fun url hacking to force the traversal a user
958- # encounters.
959- pillarperson = PillarPerson(
960- self.pillar, self.factory.makePerson())
961- url = 'http://launchpad.dev/%s/+sharing/%s' % (
962- pillarperson.pillar.name, pillarperson.person.name)
963- browser = self.getUserBrowser(user=self.owner, url=url)
964- self.assertIn(
965- 'There are no shared bugs or branches.',
966- browser.contents)
967-
968- def test_init_without_feature_flag(self):
969- # We need a feature flag to enable the view.
970- pillarperson = self.getPillarPerson()
971- self.assertRaises(
972- Unauthorized, create_initialized_view, pillarperson, '+index')
973-
974- def test_init_with_feature_flag(self):
975+ # We have to do some fun url hacking to force the traversal a user
976+ # encounters.
977+ pillarperson = PillarPerson(
978+ self.pillar, self.factory.makePerson())
979+ url = 'http://launchpad.dev/%s/+sharing/%s' % (
980+ pillarperson.pillar.name, pillarperson.person.name)
981+ browser = self.getUserBrowser(user=self.owner, url=url)
982+ self.assertIn(
983+ 'There are no shared bugs or branches.', browser.contents)
984+
985+ def test_init_works(self):
986 # The view works with a feature flag.
987- with FeatureFixture(DETAILS_ENABLED_FLAG):
988- pillarperson = self.getPillarPerson()
989- view = create_initialized_view(pillarperson, '+index')
990- self.assertEqual(pillarperson.person.displayname, view.page_title)
991- self.assertEqual(1, view.shared_bugs_count)
992+ pillarperson = self.getPillarPerson()
993+ view = create_initialized_view(pillarperson, '+index')
994+ self.assertEqual(pillarperson.person.displayname, view.page_title)
995+ self.assertEqual(1, view.shared_bugs_count)
996
997 def test_view_data_model(self):
998 # Test that the json request cache contains the view data model.
999- with FeatureFixture(DETAILS_ENABLED_FLAG):
1000- pillarperson = self.getPillarPerson()
1001- view = create_initialized_view(pillarperson, '+index')
1002- bugtask = list(view.bugtasks)[0]
1003- bug = bugtask.bug
1004- cache = IJSONRequestCache(view.request)
1005- request = get_current_web_service_request()
1006- self.assertEqual({
1007- 'self_link': absoluteURL(pillarperson.person, request),
1008- 'displayname': pillarperson.person.displayname
1009- }, cache.objects.get('grantee'))
1010- self.assertEqual({
1011- 'self_link': absoluteURL(pillarperson.pillar, request),
1012- }, cache.objects.get('pillar'))
1013- self.assertEqual({
1014- 'bug_id': bug.id,
1015- 'bug_summary': bug.title,
1016- 'bug_importance': bugtask.importance.title.lower(),
1017- 'information_type': bug.information_type.title,
1018- 'web_link': canonical_url(
1019- bugtask, path_only_if_possible=True),
1020- 'self_link': absoluteURL(bug, request),
1021- }, cache.objects.get('bugs')[0])
1022- if self.pillar_type == 'product':
1023- branch = list(view.branches)[0]
1024- self.assertEqual({
1025- 'branch_id': branch.id,
1026- 'branch_name': branch.unique_name,
1027- 'information_type': InformationType.USERDATA.title,
1028- 'web_link': canonical_url(
1029- branch, path_only_if_possible=True),
1030- 'self_link': absoluteURL(branch, request),
1031- }, cache.objects.get('branches')[0])
1032+ pillarperson = self.getPillarPerson()
1033+ view = create_initialized_view(pillarperson, '+index')
1034+ bugtask = list(view.bugtasks)[0]
1035+ bug = bugtask.bug
1036+ cache = IJSONRequestCache(view.request)
1037+ request = get_current_web_service_request()
1038+ self.assertEqual({
1039+ 'self_link': absoluteURL(pillarperson.person, request),
1040+ 'displayname': pillarperson.person.displayname
1041+ }, cache.objects.get('grantee'))
1042+ self.assertEqual({
1043+ 'self_link': absoluteURL(pillarperson.pillar, request),
1044+ }, cache.objects.get('pillar'))
1045+ self.assertEqual({
1046+ 'bug_id': bug.id,
1047+ 'bug_summary': bug.title,
1048+ 'bug_importance': bugtask.importance.title.lower(),
1049+ 'information_type': bug.information_type.title,
1050+ 'web_link': canonical_url(
1051+ bugtask, path_only_if_possible=True),
1052+ 'self_link': absoluteURL(bug, request),
1053+ }, cache.objects.get('bugs')[0])
1054+ if self.pillar_type == 'product':
1055+ branch = list(view.branches)[0]
1056+ self.assertEqual({
1057+ 'branch_id': branch.id,
1058+ 'branch_name': branch.unique_name,
1059+ 'information_type': InformationType.USERDATA.title,
1060+ 'web_link': canonical_url(branch, path_only_if_possible=True),
1061+ 'self_link': absoluteURL(branch, request),
1062+ }, cache.objects.get('branches')[0])
1063
1064 def test_view_query_count(self):
1065 # Test that the view bulk loads artifacts.
1066- with FeatureFixture(DETAILS_ENABLED_FLAG):
1067- person = self.factory.makePerson()
1068- for x in range(0, 15):
1069- self.makeArtifactGrantee(person, True, True, False)
1070- pillarperson = PillarPerson(self.pillar, person)
1071-
1072- # Invalidate the Storm cache and check the query count.
1073- IStore(self.pillar).invalidate()
1074- with StormStatementRecorder() as recorder:
1075- create_initialized_view(pillarperson, '+index')
1076- self.assertThat(recorder, HasQueryCount(LessThan(12)))
1077-
1078- def test_view_write_enabled_without_feature_flag(self):
1079- # Test that sharing_write_enabled is not set without the feature flag.
1080- with FeatureFixture(DETAILS_ENABLED_FLAG):
1081- pillarperson = self.getPillarPerson()
1082- view = create_initialized_view(pillarperson, '+index')
1083- cache = IJSONRequestCache(view.request)
1084- self.assertFalse(cache.objects.get('sharing_write_enabled'))
1085-
1086- def test_view_write_enabled_with_feature_flag(self):
1087- # Test that sharing_write_enabled is set when required.
1088- with FeatureFixture(DETAILS_WRITE_FLAG):
1089- pillarperson = self.getPillarPerson()
1090- view = create_initialized_view(pillarperson, '+index')
1091- cache = IJSONRequestCache(view.request)
1092- self.assertTrue(cache.objects.get('sharing_write_enabled'))
1093+ person = self.factory.makePerson()
1094+ for x in range(0, 15):
1095+ self.makeArtifactGrantee(person, True, True, False)
1096+ pillarperson = PillarPerson(self.pillar, person)
1097+
1098+ # Invalidate the Storm cache and check the query count.
1099+ IStore(self.pillar).invalidate()
1100+ with StormStatementRecorder() as recorder:
1101+ create_initialized_view(pillarperson, '+index')
1102+ self.assertThat(recorder, HasQueryCount(LessThan(12)))
1103
1104
1105 class TestProductSharingDetailsView(
1106@@ -289,132 +249,83 @@
1107 class PillarSharingViewTestMixin:
1108 """Test the PillarSharingView."""
1109
1110- def test_init_without_feature_flag(self):
1111- # We need a feature flag to enable the view.
1112- self.assertRaises(
1113- Unauthorized, create_initialized_view, self.pillar, '+sharing')
1114-
1115- def test_init_with_feature_flag(self):
1116- # The view works with a feature flag.
1117- with FeatureFixture(ENABLED_FLAG):
1118- view = create_initialized_view(self.pillar, '+sharing')
1119- self.assertEqual('Sharing', view.page_title)
1120-
1121- def test_sharing_menu_without_feature_flag(self):
1122+ def test_sharing_menu(self):
1123 url = canonical_url(self.pillar)
1124 browser = setupBrowserForUser(user=self.driver)
1125 browser.open(url)
1126 soup = BeautifulSoup(browser.contents)
1127- sharing_menu = soup.find('a', {'class': 'menu-link-sharing'})
1128- self.assertIsNone(sharing_menu)
1129-
1130- def test_sharing_menu_with_feature_flag(self):
1131- with FeatureFixture(ENABLED_FLAG):
1132- url = canonical_url(self.pillar)
1133- browser = setupBrowserForUser(user=self.driver)
1134- browser.open(url)
1135- soup = BeautifulSoup(browser.contents)
1136- sharing_url = canonical_url(self.pillar, view_name='+sharing')
1137- sharing_menu = soup.find('a', {'href': sharing_url})
1138- self.assertIsNotNone(sharing_menu)
1139+ sharing_url = canonical_url(self.pillar, view_name='+sharing')
1140+ sharing_menu = soup.find('a', {'href': sharing_url})
1141+ self.assertIsNotNone(sharing_menu)
1142
1143 def test_picker_config(self):
1144 # Test the config passed to the disclosure sharing picker.
1145- with FeatureFixture(ENABLED_FLAG):
1146- view = create_view(self.pillar, name='+sharing')
1147- picker_config = simplejson.loads(view.json_sharing_picker_config)
1148- self.assertTrue('vocabulary_filters' in picker_config)
1149- self.assertEqual(
1150- 'Share project information',
1151- picker_config['header'])
1152- self.assertEqual(
1153- 'Search for user or exclusive team with whom to share',
1154- picker_config['steptitle'])
1155- self.assertEqual(
1156- 'NewPillarGrantee', picker_config['vocabulary'])
1157+ view = create_view(self.pillar, name='+sharing')
1158+ picker_config = simplejson.loads(view.json_sharing_picker_config)
1159+ self.assertTrue('vocabulary_filters' in picker_config)
1160+ self.assertEqual('Share project information', picker_config['header'])
1161+ self.assertEqual(
1162+ 'Search for user or exclusive team with whom to share',
1163+ picker_config['steptitle'])
1164+ self.assertEqual('NewPillarGrantee', picker_config['vocabulary'])
1165
1166 def test_view_data_model(self):
1167 # Test that the json request cache contains the view data model.
1168- with FeatureFixture(ENABLED_FLAG):
1169- view = create_initialized_view(self.pillar, name='+sharing')
1170- cache = IJSONRequestCache(view.request)
1171- self.assertIsNotNone(cache.objects.get('information_types'))
1172- self.assertIsNotNone(
1173- cache.objects.get('branch_sharing_policies'))
1174- self.assertIsNotNone(cache.objects.get('bug_sharing_policies'))
1175- self.assertIsNotNone(cache.objects.get('sharing_permissions'))
1176- batch_size = config.launchpad.default_batch_size
1177- apgfs = getUtility(IAccessPolicyGrantFlatSource)
1178- grantees = apgfs.findGranteePermissionsByPolicy(
1179- [self.access_policy], self.grantees[:batch_size])
1180- sharing_service = getUtility(IService, 'sharing')
1181- grantee_data = sharing_service.jsonGranteeData(grantees)
1182- self.assertContentEqual(
1183- grantee_data, cache.objects.get('grantee_data'))
1184+ view = create_initialized_view(self.pillar, name='+sharing')
1185+ cache = IJSONRequestCache(view.request)
1186+ self.assertIsNotNone(cache.objects.get('information_types'))
1187+ self.assertIsNotNone(cache.objects.get('branch_sharing_policies'))
1188+ self.assertIsNotNone(cache.objects.get('bug_sharing_policies'))
1189+ self.assertIsNotNone(cache.objects.get('sharing_permissions'))
1190+ batch_size = config.launchpad.default_batch_size
1191+ apgfs = getUtility(IAccessPolicyGrantFlatSource)
1192+ grantees = apgfs.findGranteePermissionsByPolicy(
1193+ [self.access_policy], self.grantees[:batch_size])
1194+ sharing_service = getUtility(IService, 'sharing')
1195+ grantee_data = sharing_service.jsonGranteeData(grantees)
1196+ self.assertContentEqual(
1197+ grantee_data, cache.objects.get('grantee_data'))
1198
1199 def test_view_batch_data(self):
1200 # Test the expected batching data is in the json request cache.
1201- with FeatureFixture(ENABLED_FLAG):
1202- view = create_initialized_view(self.pillar, name='+sharing')
1203- cache = IJSONRequestCache(view.request)
1204- # Test one expected data value (there are many).
1205- next_batch = view.grantees().batch.nextBatch()
1206- self.assertContentEqual(
1207- next_batch.range_memo, cache.objects.get('next')['memo'])
1208+ view = create_initialized_view(self.pillar, name='+sharing')
1209+ cache = IJSONRequestCache(view.request)
1210+ # Test one expected data value (there are many).
1211+ next_batch = view.grantees().batch.nextBatch()
1212+ self.assertContentEqual(
1213+ next_batch.range_memo, cache.objects.get('next')['memo'])
1214
1215 def test_view_range_factory(self):
1216 # Test the view range factory is properly configured.
1217- with FeatureFixture(ENABLED_FLAG):
1218- view = create_initialized_view(self.pillar, name='+sharing')
1219- range_factory = view.grantees().batch.range_factory
1220-
1221- def test_range_factory():
1222- row = range_factory.resultset.get_plain_result_set()[0]
1223- range_factory.getOrderValuesFor(row)
1224-
1225- self.assertThat(
1226- test_range_factory,
1227- Not(Raises(MatchesException(StormRangeFactoryError))))
1228+ view = create_initialized_view(self.pillar, name='+sharing')
1229+ range_factory = view.grantees().batch.range_factory
1230+
1231+ def test_range_factory():
1232+ row = range_factory.resultset.get_plain_result_set()[0]
1233+ range_factory.getOrderValuesFor(row)
1234+
1235+ self.assertThat(
1236+ test_range_factory,
1237+ Not(Raises(MatchesException(StormRangeFactoryError))))
1238
1239 def test_view_query_count(self):
1240 # Test the query count is within expected limit.
1241- with FeatureFixture(ENABLED_FLAG):
1242- view = create_view(self.pillar, name='+sharing')
1243- with StormStatementRecorder() as recorder:
1244- view.initialize()
1245- self.assertThat(recorder, HasQueryCount(LessThan(9)))
1246-
1247- def test_view_write_enabled_without_feature_flag(self):
1248- # Test that sharing_write_enabled is not set without the feature flag.
1249- with FeatureFixture(ENABLED_FLAG):
1250- login_person(self.owner)
1251- view = create_initialized_view(self.pillar, name='+sharing')
1252- cache = IJSONRequestCache(view.request)
1253- self.assertFalse(cache.objects.get('sharing_write_enabled'))
1254-
1255- def test_view_write_enabled_with_feature_flag(self):
1256- # Test that sharing_write_enabled is set when required.
1257- with FeatureFixture(WRITE_FLAG):
1258- view = create_initialized_view(self.pillar, name='+sharing')
1259- cache = IJSONRequestCache(view.request)
1260- self.assertFalse(cache.objects.get('sharing_write_enabled'))
1261- login_person(self.owner)
1262- view = create_initialized_view(self.pillar, name='+sharing')
1263- cache = IJSONRequestCache(view.request)
1264- self.assertTrue(cache.objects.get('sharing_write_enabled'))
1265+ view = create_view(self.pillar, name='+sharing')
1266+ with StormStatementRecorder() as recorder:
1267+ view.initialize()
1268+ self.assertThat(recorder, HasQueryCount(LessThan(9)))
1269
1270 def test_view_invisible_information_types(self):
1271 # Test the expected invisible information type data is in the
1272 # json request cache.
1273- with FeatureFixture(WRITE_FLAG):
1274- with person_logged_in(self.pillar.owner):
1275- getUtility(IService, 'sharing').deletePillarGrantee(
1276- self.pillar, self.pillar.owner, self.pillar.owner)
1277- view = create_initialized_view(self.pillar, name='+sharing')
1278- cache = IJSONRequestCache(view.request)
1279- self.assertContentEqual(
1280- ['Private Security', 'Private'],
1281- cache.objects.get('invisible_information_types'))
1282+ with person_logged_in(self.pillar.owner):
1283+ getUtility(IService, 'sharing').deletePillarGrantee(
1284+ self.pillar, self.pillar.owner, self.pillar.owner)
1285+ view = create_initialized_view(self.pillar, name='+sharing')
1286+ cache = IJSONRequestCache(view.request)
1287+ self.assertContentEqual(
1288+ ['Private Security', 'Private'],
1289+ cache.objects.get('invisible_information_types'))
1290
1291
1292 class TestProductSharingView(PillarSharingViewTestMixin,
1293
1294=== modified file 'lib/lp/registry/javascript/sharing/pillarsharingview.js'
1295--- lib/lp/registry/javascript/sharing/pillarsharingview.js 2012-08-23 00:35:25 +0000
1296+++ lib/lp/registry/javascript/sharing/pillarsharingview.js 2012-08-29 05:40:35 +0000
1297@@ -19,10 +19,6 @@
1298 value: new Y.lp.client.Launchpad()
1299 },
1300
1301- write_enabled: {
1302- value: false
1303- },
1304-
1305 grantee_picker: {
1306 value: null
1307 },
1308@@ -61,12 +57,6 @@
1309 this.set(
1310 'sharing_permissions_by_value', sharing_permissions_by_value);
1311
1312- // No need to do anything else if we are read only.
1313- if (LP.cache.sharing_write_enabled !== true) {
1314- return;
1315- }
1316- this.set('write_enabled', true);
1317-
1318 var vocab;
1319 var header;
1320 var steptitle;
1321@@ -125,13 +115,11 @@
1322 sharing_permissions:
1323 this.get('sharing_permissions_by_value'),
1324 information_types: this.get('information_types_by_value'),
1325- write_enabled: this.get('write_enabled')
1326+ write_enabled: true
1327 });
1328 this.set('grantee_table', grantee_table);
1329 grantee_table.render();
1330- if (this.get('write_enabled')) {
1331- Y.one('#add-grantee-link').removeClass('hidden');
1332- }
1333+ Y.one('#add-grantee-link').removeClass('hidden');
1334 this.bug_sharing_policy_widget
1335 = this._render_sharing_policy('bug', 'Bug');
1336 this.branch_sharing_policy_widget
1337@@ -164,8 +152,7 @@
1338 }
1339 choice_items.push.apply(
1340 choice_items, this.getSharingPolicyInformation(artifact_type));
1341- var editable = LP.cache.sharing_write_enabled
1342- && choice_items.length > 1;
1343+ var editable = choice_items.length > 1;
1344 var policy_edit = new Y.ChoiceSource({
1345 flashEnabled: false,
1346 clickable_content: editable,
1347@@ -186,9 +173,6 @@
1348 },
1349
1350 bindUI: function() {
1351- if (!this.get('write_enabled')) {
1352- return;
1353- }
1354 var self = this;
1355 var share_link = Y.one('#add-grantee-link');
1356 share_link.on('click', function(e) {
1357
1358=== modified file 'lib/lp/registry/javascript/sharing/sharingdetailsview.js'
1359--- lib/lp/registry/javascript/sharing/sharingdetailsview.js 2012-07-21 03:04:06 +0000
1360+++ lib/lp/registry/javascript/sharing/sharingdetailsview.js 2012-08-29 05:40:35 +0000
1361@@ -19,10 +19,6 @@
1362 value: new Y.lp.client.Launchpad()
1363 },
1364
1365- write_enabled: {
1366- value: false
1367- },
1368-
1369 sharing_details_table: {
1370 value: null
1371 }
1372@@ -30,29 +26,19 @@
1373
1374 Y.extend(SharingDetailsView, Y.Widget, {
1375
1376- initializer: function(config) {
1377- if (LP.cache.sharing_write_enabled !== true) {
1378- return;
1379- }
1380- this.set('write_enabled', true);
1381- },
1382-
1383 renderUI: function() {
1384 var ns = Y.lp.registry.sharing.sharingdetails;
1385 var details_table = new ns.SharingDetailsTable({
1386 bugs: LP.cache.bugs,
1387 branches: LP.cache.branches,
1388 person_name: LP.cache.grantee.displayname,
1389- write_enabled: this.get('write_enabled')
1390+ write_enabled: true
1391 });
1392 this.set('sharing_details_table', details_table);
1393 details_table.render();
1394 },
1395
1396 bindUI: function() {
1397- if (!this.get('write_enabled')) {
1398- return;
1399- }
1400 var self = this;
1401 var sharing_details_table = this.get('sharing_details_table');
1402 var ns = Y.lp.registry.sharing.sharingdetails;
1403
1404=== modified file 'lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js'
1405--- lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js 2012-08-16 00:19:42 +0000
1406+++ lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js 2012-08-29 05:40:35 +0000
1407@@ -56,7 +56,6 @@
1408 title: 'Branch Policy 1',
1409 description: 'Branch Policy 1 description'}
1410 ],
1411- sharing_write_enabled: true
1412 }
1413 };
1414 this.mockio = new Y.lp.testing.mockio.MockIo();
1415@@ -119,16 +118,6 @@
1416 Y.Assert.isNotNull(Y.one('.yui3-grantee_picker'));
1417 },
1418
1419- // Read only mode disables the correct things.
1420- test_readonly: function() {
1421- window.LP.cache.sharing_write_enabled = false;
1422- this.view = this._create_Widget();
1423- this.view.render();
1424- Y.Assert.isTrue(Y.one('#add-grantee-link').hasClass('hidden'));
1425- Y.Assert.isFalse(
1426- this.view.get('grantee_table').get('write_enabled'));
1427- },
1428-
1429 // Clicking a update grantee grantee link calls
1430 // the update_grantee_interaction method with the correct parameters.
1431 test_update_grantee_click: function() {
1432@@ -547,14 +536,6 @@
1433 'Bug Policy 1', value_node.get('text').trim());
1434 },
1435
1436- // If the view is readonly, no edit links are available.
1437- test_sharing_policy_render_read_only: function() {
1438- window.LP.cache.sharing_write_enabled = false;
1439- this.view = this._create_Widget();
1440- this.view.render();
1441- this._assert_sharing_policies_editable(false);
1442- },
1443-
1444 // If there is only one policy choice, no edit links are available.
1445 test_sharing_policy_render_only_one_choice: function() {
1446 // Add a model value so the legacy choice is not used.
1447
1448=== modified file 'lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js'
1449--- lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js 2012-07-20 03:15:04 +0000
1450+++ lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js 2012-08-29 05:40:35 +0000
1451@@ -37,7 +37,6 @@
1452 pillar: {
1453 self_link: '/pillar'
1454 },
1455- sharing_write_enabled: true
1456 }
1457 };
1458 this.fixture = Y.one('#fixture');
1459@@ -79,16 +78,6 @@
1460 Y.one('#sharing-table-body tr[id=shared-bug-2]'));
1461 },
1462
1463- // Read only mode disables the correct things.
1464- test_readonly: function() {
1465- window.LP.cache.sharing_write_enabled = false;
1466- this.view = this._create_Widget();
1467- this.view.render();
1468- Y.Assert.isFalse(
1469- this.view.get('sharing_details_table')
1470- .get('write_enabled'));
1471- },
1472-
1473 // Clicking a bug remove link calls the confirm_grant_removal
1474 // method with the correct parameters.
1475 test_remove_bug_grant_click: function() {
1476
1477=== modified file 'lib/lp/registry/model/accesspolicy.py'
1478--- lib/lp/registry/model/accesspolicy.py 2012-08-22 04:58:49 +0000
1479+++ lib/lp/registry/model/accesspolicy.py 2012-08-29 05:40:35 +0000
1480@@ -65,14 +65,19 @@
1481 getUtility(IAccessArtifactSource).delete([artifact])
1482 return
1483 [abstract_artifact] = getUtility(IAccessArtifactSource).ensure([artifact])
1484+ aps = getUtility(IAccessPolicySource).find(
1485+ (pillar, information_type) for pillar in pillars)
1486+ missing_pillars = set(pillars) - set([ap.pillar for ap in aps])
1487+ if len(missing_pillars):
1488+ pillar_str = ', '.join([p.name for p in missing_pillars])
1489+ raise AssertionError(
1490+ "Pillar(s) %s require an access policy for information type "
1491+ "%s." % (pillar_str, information_type.title))
1492
1493 # Now determine the existing and desired links, and make them
1494 # match.
1495 apasource = getUtility(IAccessPolicyArtifactSource)
1496- wanted_links = set(
1497- (abstract_artifact, policy) for policy in
1498- getUtility(IAccessPolicySource).find(
1499- (pillar, information_type) for pillar in pillars))
1500+ wanted_links = set((abstract_artifact, policy) for policy in aps)
1501 existing_links = set([
1502 (apa.abstract_artifact, apa.policy)
1503 for apa in apasource.findByArtifact([abstract_artifact])])
1504
1505=== modified file 'lib/lp/registry/model/teammembership.py'
1506--- lib/lp/registry/model/teammembership.py 2012-08-14 23:27:07 +0000
1507+++ lib/lp/registry/model/teammembership.py 2012-08-29 05:40:35 +0000
1508@@ -65,7 +65,6 @@
1509 SQLBase,
1510 sqlvalues,
1511 )
1512-from lp.services.features import getFeatureFlag
1513 from lp.services.mail.helpers import (
1514 get_contact_email_addresses,
1515 get_email_template,
1516@@ -343,13 +342,11 @@
1517 _fillTeamParticipation(self.person, self.team)
1518 elif old_status in ACTIVE_STATES:
1519 _cleanTeamParticipation(self.person, self.team)
1520- flag = 'disclosure.unsubscribe_jobs.enabled'
1521- if bool(getFeatureFlag(flag)):
1522- # A person has left the team so they may no longer have access
1523- # to some artifacts shared with the team. We need to run a job
1524- # to remove any subscriptions to such artifacts.
1525- getUtility(IRemoveArtifactSubscriptionsJobSource).create(
1526- user, grantee=self.person)
1527+ # A person has left the team so they may no longer have access
1528+ # to some artifacts shared with the team. We need to run a job
1529+ # to remove any subscriptions to such artifacts.
1530+ getUtility(IRemoveArtifactSubscriptionsJobSource).create(
1531+ user, grantee=self.person)
1532 else:
1533 # Changed from an inactive state to another inactive one, so no
1534 # need to fill/clean the TeamParticipation table.
1535
1536=== modified file 'lib/lp/registry/services/sharingservice.py'
1537--- lib/lp/registry/services/sharingservice.py 2012-08-16 06:06:36 +0000
1538+++ lib/lp/registry/services/sharingservice.py 2012-08-29 05:40:35 +0000
1539@@ -59,7 +59,6 @@
1540 from lp.registry.model.teammembership import TeamParticipation
1541 from lp.services.database.lpstorm import IStore
1542 from lp.services.database.stormexpr import ColumnSelect
1543-from lp.services.features import getFeatureFlag
1544 from lp.services.searchbuilder import any
1545 from lp.services.webapp.authorization import (
1546 available_with_permission,
1547@@ -81,12 +80,6 @@
1548 """See `IService`."""
1549 return 'sharing'
1550
1551- @property
1552- def write_enabled(self):
1553- return (
1554- bool(getFeatureFlag(
1555- 'disclosure.enhanced_sharing.writable')))
1556-
1557 def checkPillarAccess(self, pillar, information_type, person):
1558 """See `ISharingService`."""
1559 policy = getUtility(IAccessPolicySource).find(
1560@@ -350,15 +343,12 @@
1561 result = []
1562 request = get_current_web_service_request()
1563 browser_request = IWebBrowserOriginatingRequest(request)
1564- details_enabled = bool((getFeatureFlag(
1565- 'disclosure.enhanced_sharing_details.enabled')))
1566 # We need to precache icon and validity information for the batch.
1567 grantee_ids = [grantee[0].id for grantee in grant_permissions]
1568 list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(
1569 grantee_ids, need_icon=True, need_validity=True))
1570 for (grantee, permissions, shared_artifact_types) in grant_permissions:
1571- some_things_shared = (
1572- details_enabled and len(shared_artifact_types) > 0)
1573+ some_things_shared = len(shared_artifact_types) > 0
1574 grantee_permissions = {}
1575 for (policy, permission) in permissions.iteritems():
1576 grantee_permissions[policy.type.name] = permission.name
1577@@ -386,9 +376,6 @@
1578 # We do not support adding grantees to project groups.
1579 assert not IProjectGroup.providedBy(pillar)
1580
1581- if not self.write_enabled:
1582- raise Unauthorized("This feature is not yet enabled.")
1583-
1584 # Separate out the info types according to permission.
1585 information_types = permissions.keys()
1586 info_types_for_all = [
1587@@ -463,9 +450,6 @@
1588 information_types=None):
1589 """See `ISharingService`."""
1590
1591- if not self.write_enabled:
1592- raise Unauthorized("This feature is not yet enabled.")
1593-
1594 policy_source = getUtility(IAccessPolicySource)
1595 if information_types is None:
1596 # We delete all policy grants for the pillar.
1597@@ -491,9 +475,8 @@
1598 to_delete = list(ap_grant_flat.findArtifactsByGrantee(
1599 grantee, pillar_policies))
1600 if len(to_delete) > 0:
1601- accessartifact_grant_source = getUtility(
1602- IAccessArtifactGrantSource)
1603- accessartifact_grant_source.revokeByArtifact(to_delete, [grantee])
1604+ getUtility(IAccessArtifactGrantSource).revokeByArtifact(
1605+ to_delete, [grantee])
1606
1607 # Create a job to remove subscriptions for artifacts the grantee can no
1608 # longer see.
1609@@ -512,9 +495,6 @@
1610 bugs=None):
1611 """See `ISharingService`."""
1612
1613- if not self.write_enabled:
1614- raise Unauthorized("This feature is not yet enabled.")
1615-
1616 artifacts = []
1617 if branches:
1618 artifacts.extend(branches)
1619@@ -524,8 +504,7 @@
1620 accessartifact_source = getUtility(IAccessArtifactSource)
1621 artifacts_to_delete = accessartifact_source.find(artifacts)
1622 # Revoke access to bugs/branches for the specified grantee.
1623- accessartifact_grant_source = getUtility(IAccessArtifactGrantSource)
1624- accessartifact_grant_source.revokeByArtifact(
1625+ getUtility(IAccessArtifactGrantSource).revokeByArtifact(
1626 artifacts_to_delete, [grantee])
1627
1628 # Create a job to remove subscriptions for artifacts the grantee can no
1629@@ -537,9 +516,6 @@
1630 ignore_permissions=False):
1631 """See `ISharingService`."""
1632
1633- if not ignore_permissions and not self.write_enabled:
1634- raise Unauthorized("This feature is not yet enabled.")
1635-
1636 artifacts = []
1637 if branches:
1638 artifacts.extend(branches)
1639
1640=== modified file 'lib/lp/registry/services/tests/test_sharingservice.py'
1641--- lib/lp/registry/services/tests/test_sharingservice.py 2012-08-16 06:06:36 +0000
1642+++ lib/lp/registry/services/tests/test_sharingservice.py 2012-08-29 05:40:35 +0000
1643@@ -56,13 +56,6 @@
1644 from lp.testing.pages import LaunchpadWebServiceCaller
1645
1646
1647-WRITE_FLAG = {
1648- 'disclosure.enhanced_sharing.writable': 'true',
1649- 'disclosure.enhanced_sharing_details.enabled': 'true',
1650- 'jobs.celery.enabled_classes': 'RemoveArtifactSubscriptionsJob'}
1651-DETAILS_FLAG = {'disclosure.enhanced_sharing_details.enabled': 'true'}
1652-
1653-
1654 class TestSharingService(TestCaseWithFactory):
1655 """Tests for the SharingService."""
1656
1657@@ -71,6 +64,9 @@
1658 def setUp(self):
1659 super(TestSharingService, self).setUp()
1660 self.service = getUtility(IService, 'sharing')
1661+ self.useFixture(FeatureFixture({
1662+ 'jobs.celery.enabled_classes': 'RemoveArtifactSubscriptionsJob',
1663+ }))
1664
1665 def _makeGranteeData(self, grantee, policy_permissions,
1666 shared_artifact_types):
1667@@ -234,12 +230,11 @@
1668 [policy1, policy2] = getUtility(IAccessPolicySource).findByPillar(
1669 [product])
1670 grantee = self.factory.makePerson()
1671- with FeatureFixture(DETAILS_FLAG):
1672- grantees = self.service.jsonGranteeData(
1673- [(grantee, {
1674- policy1: SharingPermission.ALL,
1675- policy2: SharingPermission.SOME},
1676- [policy1.type, policy2.type])])
1677+ grantees = self.service.jsonGranteeData(
1678+ [(grantee, {
1679+ policy1: SharingPermission.ALL,
1680+ policy2: SharingPermission.SOME},
1681+ [policy1.type, policy2.type])])
1682 expected_data = self._makeGranteeData(
1683 grantee,
1684 [(policy1.type, SharingPermission.ALL),
1685@@ -247,24 +242,6 @@
1686 [policy1.type, policy2.type])
1687 self.assertContentEqual([expected_data], grantees)
1688
1689- def test_jsonGranteeData_with_Some_without_flag(self):
1690- # jsonGranteeData returns the expected data for a grantee with
1691- # permissions which include SOME and the feature flag not set.
1692- product = self.factory.makeProduct()
1693- [policy1, policy2] = getUtility(IAccessPolicySource).findByPillar(
1694- [product])
1695- grantee = self.factory.makePerson()
1696- grantees = self.service.jsonGranteeData(
1697- [(grantee, {
1698- policy1: SharingPermission.ALL,
1699- policy2: SharingPermission.SOME}, [policy2.type])])
1700- expected_data = self._makeGranteeData(
1701- grantee,
1702- [(policy1.type, SharingPermission.ALL),
1703- (policy2.type, SharingPermission.SOME)], [policy2.type])
1704- expected_data['shared_items_exist'] = False
1705- self.assertContentEqual([expected_data], grantees)
1706-
1707 def test_jsonGranteeData_without_Some(self):
1708 # jsonGranteeData returns the expected data for a grantee with only ALL
1709 # permissions.
1710@@ -272,10 +249,8 @@
1711 [policy1, policy2] = getUtility(IAccessPolicySource).findByPillar(
1712 [product])
1713 grantee = self.factory.makePerson()
1714- with FeatureFixture(DETAILS_FLAG):
1715- grantees = self.service.jsonGranteeData(
1716- [(grantee, {
1717- policy1: SharingPermission.ALL}, [])])
1718+ grantees = self.service.jsonGranteeData(
1719+ [(grantee, {policy1: SharingPermission.ALL}, [])])
1720 expected_data = self._makeGranteeData(
1721 grantee,
1722 [(policy1.type, SharingPermission.ALL)], [])
1723@@ -290,10 +265,8 @@
1724 icon = self.factory.makeLibraryFileAlias(
1725 filename='smurf.png', content_type='image/png')
1726 grantee = self.factory.makeTeam(icon=icon)
1727- with FeatureFixture(DETAILS_FLAG):
1728- grantees = self.service.jsonGranteeData(
1729- [(grantee, {
1730- policy1: SharingPermission.ALL}, [])])
1731+ grantees = self.service.jsonGranteeData(
1732+ [(grantee, {policy1: SharingPermission.ALL}, [])])
1733 expected_data = self._makeGranteeData(
1734 grantee,
1735 [(policy1.type, SharingPermission.ALL)], [])
1736@@ -312,8 +285,7 @@
1737 self.factory.makeAccessPolicyArtifact(
1738 artifact=artifact_grant.abstract_artifact, policy=access_policy)
1739
1740- with FeatureFixture(DETAILS_FLAG):
1741- grantees = self.service.getPillarGranteeData(pillar)
1742+ grantees = self.service.getPillarGranteeData(pillar)
1743 expected_grantees = [
1744 self._makeGranteeData(
1745 grantee,
1746@@ -540,9 +512,8 @@
1747 InformationType.PRIVATESECURITY: SharingPermission.ALL,
1748 InformationType.USERDATA: SharingPermission.SOME,
1749 InformationType.PROPRIETARY: SharingPermission.NOTHING}
1750- with FeatureFixture(WRITE_FLAG):
1751- grantee_data = self.service.sharePillarInformation(
1752- pillar, grantee, grantor, permissions)
1753+ grantee_data = self.service.sharePillarInformation(
1754+ pillar, grantee, grantor, permissions)
1755 policies = getUtility(IAccessPolicySource).findByPillar([pillar])
1756 policy_grant_source = getUtility(IAccessPolicyGrantSource)
1757 grants = policy_grant_source.findByPolicy(policies)
1758@@ -619,9 +590,8 @@
1759
1760 permissions = {
1761 grant.policy.type: SharingPermission.SOME}
1762- with FeatureFixture(WRITE_FLAG):
1763- grantee_data = self.service.sharePillarInformation(
1764- pillar, grantee, self.factory.makePerson(), permissions)
1765+ grantee_data = self.service.sharePillarInformation(
1766+ pillar, grantee, self.factory.makePerson(), permissions)
1767 self.assertIsNone(grantee_data['grantee_entry'])
1768
1769 def test_granteePillarInformationInvisibleInformationTypes(self):
1770@@ -629,13 +599,12 @@
1771 # information types.
1772 product = self.factory.makeProduct()
1773 grantee = self.factory.makePerson()
1774- with FeatureFixture(WRITE_FLAG):
1775- with admin_logged_in():
1776- self.service.deletePillarGrantee(
1777- product, product.owner, product.owner)
1778- result_data = self.service.sharePillarInformation(
1779- product, grantee, product.owner,
1780- {InformationType.USERDATA: SharingPermission.ALL})
1781+ with admin_logged_in():
1782+ self.service.deletePillarGrantee(
1783+ product, product.owner, product.owner)
1784+ result_data = self.service.sharePillarInformation(
1785+ product, grantee, product.owner,
1786+ {InformationType.USERDATA: SharingPermission.ALL})
1787 # The owner is granted access on product creation. So we need to allow
1788 # for that in the check below.
1789 self.assertContentEqual(
1790@@ -645,42 +614,27 @@
1791 def _assert_sharePillarInformationUnauthorized(self, pillar):
1792 # sharePillarInformation raises an Unauthorized exception if the user
1793 # is not permitted to do so.
1794- with FeatureFixture(WRITE_FLAG):
1795- grantee = self.factory.makePerson()
1796- user = self.factory.makePerson()
1797- self.assertRaises(
1798- Unauthorized, self.service.sharePillarInformation,
1799- pillar, grantee, user,
1800- {InformationType.USERDATA: SharingPermission.ALL})
1801+ grantee = self.factory.makePerson()
1802+ user = self.factory.makePerson()
1803+ self.assertRaises(
1804+ Unauthorized, self.service.sharePillarInformation,
1805+ pillar, grantee, user,
1806+ {InformationType.USERDATA: SharingPermission.ALL})
1807
1808 def test_sharePillarInformationAnonymous(self):
1809 # Anonymous users are not allowed.
1810- with FeatureFixture(WRITE_FLAG):
1811- product = self.factory.makeProduct()
1812- login(ANONYMOUS)
1813- self._assert_sharePillarInformationUnauthorized(product)
1814+ product = self.factory.makeProduct()
1815+ login(ANONYMOUS)
1816+ self._assert_sharePillarInformationUnauthorized(product)
1817
1818 def test_sharePillarInformationAnyone(self):
1819 # Unauthorized users are not allowed.
1820- with FeatureFixture(WRITE_FLAG):
1821- product = self.factory.makeProduct()
1822- login_person(self.factory.makePerson())
1823- self._assert_sharePillarInformationUnauthorized(product)
1824-
1825- def test_sharePillarInformation_without_flag(self):
1826- # The feature flag needs to be enabled.
1827- owner = self.factory.makePerson()
1828- product = self.factory.makeProduct(owner=owner)
1829- login_person(owner)
1830- grantee = self.factory.makePerson()
1831- user = self.factory.makePerson()
1832- self.assertRaises(
1833- Unauthorized, self.service.sharePillarInformation,
1834- product, grantee, user,
1835- {InformationType.USERDATA: SharingPermission.ALL})
1836-
1837- def _assert_deletePillarGrantee(
1838- self, pillar, types_to_delete=None, pillar_type=None):
1839+ product = self.factory.makeProduct()
1840+ login_person(self.factory.makePerson())
1841+ self._assert_sharePillarInformationUnauthorized(product)
1842+
1843+ def _assert_deletePillarGrantee(self, pillar, types_to_delete=None,
1844+ pillar_type=None):
1845 access_policies = getUtility(IAccessPolicySource).findByPillar(
1846 (pillar,))
1847 information_types = [ap.type for ap in access_policies]
1848@@ -701,9 +655,8 @@
1849 self.factory.makeAccessPolicyArtifact(
1850 artifact=artifact, policy=access_policy)
1851 # Delete data for a specific information type.
1852- with FeatureFixture(WRITE_FLAG):
1853- self.service.deletePillarGrantee(
1854- pillar, grantee, pillar.owner, types_to_delete)
1855+ self.service.deletePillarGrantee(
1856+ pillar, grantee, pillar.owner, types_to_delete)
1857 # Assemble the expected data for the remaining access grants for
1858 # grantee.
1859 expected_data = []
1860@@ -768,43 +721,30 @@
1861 def test_deletePillarGranteeInvisibleInformationTypes(self):
1862 # Deleting a pillar grantee returns the resulting invisible info types.
1863 product = self.factory.makeProduct()
1864- with FeatureFixture(WRITE_FLAG):
1865- with admin_logged_in():
1866- invisible_information_types = self.service.deletePillarGrantee(
1867- product, product.owner, product.owner)
1868+ with admin_logged_in():
1869+ invisible_information_types = self.service.deletePillarGrantee(
1870+ product, product.owner, product.owner)
1871 self.assertContentEqual(
1872 ['Private', 'Private Security'], invisible_information_types)
1873
1874 def _assert_deletePillarGranteeUnauthorized(self, pillar):
1875 # deletePillarGrantee raises an Unauthorized exception if the user
1876 # is not permitted to do so.
1877- with FeatureFixture(WRITE_FLAG):
1878- self.assertRaises(
1879- Unauthorized, self.service.deletePillarGrantee,
1880- pillar, pillar.owner, pillar.owner, [InformationType.USERDATA])
1881+ self.assertRaises(
1882+ Unauthorized, self.service.deletePillarGrantee,
1883+ pillar, pillar.owner, pillar.owner, [InformationType.USERDATA])
1884
1885 def test_deletePillarGranteeAnonymous(self):
1886 # Anonymous users are not allowed.
1887- with FeatureFixture(WRITE_FLAG):
1888- product = self.factory.makeProduct()
1889- login(ANONYMOUS)
1890- self._assert_deletePillarGranteeUnauthorized(product)
1891+ product = self.factory.makeProduct()
1892+ login(ANONYMOUS)
1893+ self._assert_deletePillarGranteeUnauthorized(product)
1894
1895 def test_deletePillarGranteeAnyone(self):
1896 # Unauthorized users are not allowed.
1897- with FeatureFixture(WRITE_FLAG):
1898- product = self.factory.makeProduct()
1899- login_person(self.factory.makePerson())
1900- self._assert_deletePillarGranteeUnauthorized(product)
1901-
1902- def test_deletePillarGrantee_without_flag(self):
1903- # The feature flag needs to be enabled.
1904- owner = self.factory.makePerson()
1905- product = self.factory.makeProduct(owner=owner)
1906- login_person(owner)
1907- self.assertRaises(
1908- Unauthorized, self.service.deletePillarGrantee,
1909- product, product.owner, product.owner, [InformationType.USERDATA])
1910+ product = self.factory.makeProduct()
1911+ login_person(self.factory.makePerson())
1912+ self._assert_deletePillarGranteeUnauthorized(product)
1913
1914 def _assert_deleteGranteeRemoveSubscriptions(self,
1915 types_to_delete=None):
1916@@ -839,9 +779,8 @@
1917 bug.subscribe(person, product.owner)
1918
1919 # Delete data for specified information types or all.
1920- with FeatureFixture(WRITE_FLAG):
1921- self.service.deletePillarGrantee(
1922- product, grantee, product.owner, types_to_delete)
1923+ self.service.deletePillarGrantee(
1924+ product, grantee, product.owner, types_to_delete)
1925 with block_on_job(self):
1926 transaction.commit()
1927
1928@@ -907,9 +846,8 @@
1929 apgfs = getUtility(IAccessPolicyGrantFlatSource)
1930 self.assertEqual(1, grants.count())
1931
1932- with FeatureFixture(WRITE_FLAG):
1933- self.service.revokeAccessGrants(
1934- pillar, grantee, pillar.owner, bugs=bugs, branches=branches)
1935+ self.service.revokeAccessGrants(
1936+ pillar, grantee, pillar.owner, bugs=bugs, branches=branches)
1937 with block_on_job(self):
1938 transaction.commit()
1939
1940@@ -993,10 +931,8 @@
1941 for bug in bugs or []:
1942 self.assertIn(person, bug.getDirectSubscribers())
1943
1944- with FeatureFixture(WRITE_FLAG):
1945- self.service.revokeAccessGrants(
1946- pillar, team_grantee, pillar.owner,
1947- bugs=bugs, branches=branches)
1948+ self.service.revokeAccessGrants(
1949+ pillar, team_grantee, pillar.owner, bugs=bugs, branches=branches)
1950 with block_on_job(self):
1951 transaction.commit()
1952
1953@@ -1042,43 +978,27 @@
1954 bug = self.factory.makeBug(
1955 target=product, information_type=InformationType.USERDATA)
1956 grantee = self.factory.makePerson()
1957- with FeatureFixture(WRITE_FLAG):
1958- self.assertRaises(
1959- Unauthorized, self.service.revokeAccessGrants,
1960- product, grantee, product.owner, bugs=[bug])
1961+ self.assertRaises(
1962+ Unauthorized, self.service.revokeAccessGrants,
1963+ product, grantee, product.owner, bugs=[bug])
1964
1965 def test_revokeAccessGrantsAnonymous(self):
1966 # Anonymous users are not allowed.
1967- with FeatureFixture(WRITE_FLAG):
1968- login(ANONYMOUS)
1969- self._assert_revokeAccessGrantsUnauthorized()
1970+ login(ANONYMOUS)
1971+ self._assert_revokeAccessGrantsUnauthorized()
1972
1973 def test_revokeAccessGrantsAnyone(self):
1974 # Unauthorized users are not allowed.
1975- with FeatureFixture(WRITE_FLAG):
1976- login_person(self.factory.makePerson())
1977- self._assert_revokeAccessGrantsUnauthorized()
1978-
1979- def test_revokeAccessGrants_without_flag(self):
1980- # The feature flag needs to be enabled.
1981- owner = self.factory.makePerson()
1982- product = self.factory.makeProduct(owner=owner)
1983- bug = self.factory.makeBug(
1984- target=product, information_type=InformationType.USERDATA)
1985- grantee = self.factory.makePerson()
1986- login_person(owner)
1987- self.assertRaises(
1988- Unauthorized, self.service.revokeAccessGrants,
1989- product, grantee, product.owner, bugs=[bug])
1990+ login_person(self.factory.makePerson())
1991+ self._assert_revokeAccessGrantsUnauthorized()
1992
1993 def _assert_ensureAccessGrants(self, user, bugs, branches,
1994 grantee=None):
1995 # Creating access grants works as expected.
1996 if not grantee:
1997 grantee = self.factory.makePerson()
1998- with FeatureFixture(WRITE_FLAG):
1999- self.service.ensureAccessGrants(
2000- [grantee], user, bugs=bugs, branches=branches)
2001+ self.service.ensureAccessGrants(
2002+ [grantee], user, bugs=bugs, branches=branches)
2003
2004 # Check that grantee has expected access grants.
2005 shared_bugs = []
2006@@ -1133,8 +1053,7 @@
2007 information_type=InformationType.USERDATA)
2008 # Create an existing access grant.
2009 grantee = self.factory.makePerson()
2010- with FeatureFixture(WRITE_FLAG):
2011- self.service.ensureAccessGrants([grantee], owner, bugs=[bug])
2012+ self.service.ensureAccessGrants([grantee], owner, bugs=[bug])
2013 # Test with a new bug as well as the one for which access is already
2014 # granted.
2015 self._assert_ensureAccessGrants(owner, [bug, bug2], None, grantee)
2016@@ -1146,35 +1065,20 @@
2017 bug = self.factory.makeBug(
2018 target=product, information_type=InformationType.USERDATA)
2019 grantee = self.factory.makePerson()
2020- with FeatureFixture(WRITE_FLAG):
2021- self.assertRaises(
2022- Unauthorized, self.service.ensureAccessGrants,
2023- [grantee], user, bugs=[bug])
2024+ self.assertRaises(
2025+ Unauthorized, self.service.ensureAccessGrants, [grantee], user,
2026+ bugs=[bug])
2027
2028 def test_ensureAccessGrantsAnonymous(self):
2029 # Anonymous users are not allowed.
2030- with FeatureFixture(WRITE_FLAG):
2031- login(ANONYMOUS)
2032- self._assert_ensureAccessGrantsUnauthorized(ANONYMOUS)
2033+ login(ANONYMOUS)
2034+ self._assert_ensureAccessGrantsUnauthorized(ANONYMOUS)
2035
2036 def test_ensureAccessGrantsAnyone(self):
2037 # Unauthorized users are not allowed.
2038- with FeatureFixture(WRITE_FLAG):
2039- anyone = self.factory.makePerson()
2040- login_person(anyone)
2041- self._assert_ensureAccessGrantsUnauthorized(anyone)
2042-
2043- def test_ensureAccessGrants_without_flag(self):
2044- # The feature flag needs to be enabled.
2045- owner = self.factory.makePerson()
2046- product = self.factory.makeProduct(owner=owner)
2047- bug = self.factory.makeBug(
2048- target=product, information_type=InformationType.USERDATA)
2049- grantee = self.factory.makePerson()
2050- login_person(owner)
2051- self.assertRaises(
2052- Unauthorized, self.service.ensureAccessGrants,
2053- [grantee], product.owner, bugs=[bug])
2054+ anyone = self.factory.makePerson()
2055+ login_person(anyone)
2056+ self._assert_ensureAccessGrantsUnauthorized(anyone)
2057
2058 def test_getSharedArtifacts(self):
2059 # Test the getSharedArtifacts method.
2060@@ -1385,14 +1289,13 @@
2061 right_person = self.factory.makePerson()
2062 right_team = self.factory.makeTeam(members=[right_person])
2063 wrong_person = self.factory.makePerson()
2064- with FeatureFixture(WRITE_FLAG):
2065- with admin_logged_in():
2066- self.service.sharePillarInformation(
2067- product, right_team, product.owner,
2068- {InformationType.USERDATA: SharingPermission.ALL})
2069- self.service.sharePillarInformation(
2070- product, wrong_person, product.owner,
2071- {InformationType.PRIVATESECURITY: SharingPermission.ALL})
2072+ with admin_logged_in():
2073+ self.service.sharePillarInformation(
2074+ product, right_team, product.owner,
2075+ {InformationType.USERDATA: SharingPermission.ALL})
2076+ self.service.sharePillarInformation(
2077+ product, wrong_person, product.owner,
2078+ {InformationType.PRIVATESECURITY: SharingPermission.ALL})
2079 self.assertEqual(
2080 False,
2081 self.service.checkPillarAccess(
2082@@ -1415,11 +1318,10 @@
2083 # an information type.
2084 product = self.factory.makeProduct()
2085 grantee = self.factory.makePerson()
2086- with FeatureFixture(WRITE_FLAG):
2087- with admin_logged_in():
2088- self.service.sharePillarInformation(
2089- product, grantee, product.owner,
2090- {InformationType.USERDATA: SharingPermission.ALL})
2091+ with admin_logged_in():
2092+ self.service.sharePillarInformation(
2093+ product, grantee, product.owner,
2094+ {InformationType.USERDATA: SharingPermission.ALL})
2095 # The owner is granted access on product creation. So we need to allow
2096 # for that in the check below.
2097 self.assertContentEqual(
2098@@ -1431,10 +1333,9 @@
2099 # checkPillarAccess checks whether the user has full access to
2100 # an information type.
2101 product = self.factory.makeProduct()
2102- with FeatureFixture(WRITE_FLAG):
2103- with admin_logged_in():
2104- self.service.deletePillarGrantee(
2105- product, product.owner, product.owner)
2106+ with admin_logged_in():
2107+ self.service.deletePillarGrantee(
2108+ product, product.owner, product.owner)
2109 self.assertContentEqual(
2110 [(InformationType.PRIVATESECURITY, 0),
2111 (InformationType.USERDATA, 0)],
2112@@ -1499,14 +1400,13 @@
2113
2114 def _sharePillarInformation(self):
2115 pillar_uri = canonical_url(self.pillar, force_local_path=True)
2116- with FeatureFixture(WRITE_FLAG):
2117- return self._named_post(
2118- 'sharePillarInformation', pillar=pillar_uri,
2119- grantee=self.grantee_uri,
2120- user=self.grantor_uri,
2121- permissions={
2122- InformationType.USERDATA.title:
2123- SharingPermission.ALL.title})
2124+ return self._named_post(
2125+ 'sharePillarInformation', pillar=pillar_uri,
2126+ grantee=self.grantee_uri,
2127+ user=self.grantor_uri,
2128+ permissions={
2129+ InformationType.USERDATA.title:
2130+ SharingPermission.ALL.title})
2131
2132
2133 class TestLaunchpadlib(ApiTestMixin, TestCaseWithFactory):
2134@@ -1518,9 +1418,6 @@
2135 super(TestLaunchpadlib, self).setUp()
2136 self.launchpad = self.factory.makeLaunchpadService(person=self.owner)
2137 self.service = self.launchpad.load('+services/sharing')
2138- flag = FeatureFixture(WRITE_FLAG)
2139- flag.setUp()
2140- self.addCleanup(flag.cleanUp)
2141 transaction.commit()
2142 self._sharePillarInformation()
2143
2144
2145=== modified file 'lib/lp/registry/tests/test_accesspolicy.py'
2146--- lib/lp/registry/tests/test_accesspolicy.py 2012-08-08 07:22:51 +0000
2147+++ lib/lp/registry/tests/test_accesspolicy.py 2012-08-29 05:40:35 +0000
2148@@ -725,3 +725,20 @@
2149 reconcile_access_for_artifact(
2150 bug, InformationType.USERDATA, [product])
2151 self.assertPoliciesForBug([(product, InformationType.USERDATA)], bug)
2152+
2153+ def test_raises_exception_on_missing_policies(self):
2154+ # reconcile_access_for_artifact raises an exception if a pillar is
2155+ # missing an AccessPolicy.
2156+ product = self.factory.makeProduct()
2157+ # Creating a product will have created two APs, delete them.
2158+ aps = getUtility(IAccessPolicySource).findByPillar([product])
2159+ getUtility(IAccessPolicyGrantSource).revokeByPolicy(aps)
2160+ for ap in aps:
2161+ IStore(ap).remove(ap)
2162+ bug = self.factory.makeBug(target=product)
2163+ expected = (
2164+ "Pillar(s) %s require an access policy for information type "
2165+ "Private.") % product.name
2166+ self.assertRaisesWithContent(
2167+ AssertionError, expected, reconcile_access_for_artifact, bug,
2168+ InformationType.USERDATA, [product])
2169
2170=== modified file 'lib/lp/registry/tests/test_teammembership.py'
2171--- lib/lp/registry/tests/test_teammembership.py 2012-08-14 23:27:07 +0000
2172+++ lib/lp/registry/tests/test_teammembership.py 2012-08-29 05:40:35 +0000
2173@@ -504,7 +504,7 @@
2174 The number of db queries should be constant not O(depth).
2175 """
2176 self.assertStatementCount(
2177- 7,
2178+ 9,
2179 self.team5.setMembershipData, self.no_priv,
2180 TeamMembershipStatus.DEACTIVATED, self.team5.teamowner)
2181
2182@@ -998,7 +998,6 @@
2183
2184 def setUp(self):
2185 self.useFixture(FeatureFixture({
2186- 'disclosure.unsubscribe_jobs.enabled': 'true',
2187 'jobs.celery.enabled_classes': 'RemoveArtifactSubscriptionsJob',
2188 }))
2189 super(TestTeamMembershipJobs, self).setUp()
2190
2191=== modified file 'lib/lp/services/features/flags.py'
2192--- lib/lp/services/features/flags.py 2012-08-14 18:51:43 +0000
2193+++ lib/lp/services/features/flags.py 2012-08-29 05:40:35 +0000
2194@@ -197,12 +197,6 @@
2195 '',
2196 '',
2197 ''),
2198- ('disclosure.add-team-person-picker.enabled',
2199- 'boolean',
2200- 'Allows users to add a new team directly from the person picker.',
2201- '',
2202- '',
2203- ''),
2204 ('bugs.autoconfirm.enabled_distribution_names',
2205 'space delimited',
2206 ('Enables auto-confirming bugtasks for distributions (and their '
2207@@ -233,34 +227,6 @@
2208 '',
2209 '',
2210 ''),
2211- ('disclosure.enhanced_sharing.enabled',
2212- 'boolean',
2213- ('If true, will allow the use of the new sharing view and apis used '
2214- 'for the new disclosure data model to view but not write data.'),
2215- '',
2216- 'Sharing overview',
2217- ''),
2218- ('disclosure.enhanced_sharing_details.enabled',
2219- 'boolean',
2220- ('If true, enables the details page for viewing the `Some` things that'
2221- 'shared with a user or team.'),
2222- '',
2223- '',
2224- ''),
2225- ('disclosure.enhanced_sharing.writable',
2226- 'boolean',
2227- ('If true, will allow the use of the new sharing view and apis used '
2228- 'to edit the new disclosure data model.'),
2229- '',
2230- 'Sharing management',
2231- ''),
2232- ('disclosure.unsubscribe_jobs.enabled',
2233- 'boolean',
2234- ('If true, the jobs to unsubscribe users who lose access to bugs'
2235- 'and branches are run.'),
2236- '',
2237- '',
2238- ''),
2239 ('registry.upcoming_work_view.enabled',
2240 'boolean',
2241 ('If true, the new upcoming work view of teams is available.'),
2242
2243=== modified file 'lib/lp/testing/factory.py'
2244--- lib/lp/testing/factory.py 2012-08-21 04:28:11 +0000
2245+++ lib/lp/testing/factory.py 2012-08-29 05:40:35 +0000
2246@@ -1688,6 +1688,8 @@
2247 target = series.pillar
2248 else:
2249 target = self.makeProduct()
2250+ if information_type == InformationType.PROPRIETARY:
2251+ self.makeAccessPolicy(pillar=target)
2252 if IDistributionSourcePackage.providedBy(target):
2253 self.makeSourcePackagePublishingHistory(
2254 distroseries=target.distribution.currentseries,
2255
2256=== modified file 'versions.cfg'
2257--- versions.cfg 2012-08-23 02:40:39 +0000
2258+++ versions.cfg 2012-08-29 05:40:35 +0000
2259@@ -10,7 +10,7 @@
2260 argparse = 1.2.1
2261 auditor = 0.0.3
2262 auditorclient = 0.0.2
2263-auditorfixture = 0.0.4
2264+auditorfixture = 0.0.5
2265 BeautifulSoup = 3.1.0.1
2266 bson = 0.3.2
2267 # The source for this version of bzr is at lp:~benji/bzr/bug-998040

Subscribers

People subscribed via source and target branches

to status/vote changes: