Merge lp:~stevenk/launchpad/drop-disclosure-feature-flags into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 15869
Proposed branch: lp:~stevenk/launchpad/drop-disclosure-feature-flags
Merge into: lp:launchpad
Diff against target: 1942 lines (+289/-711)
28 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/doc/bugsubscription.txt (+6/-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 (+0/-1)
lib/lp/bugs/model/tests/test_bugtasksearch.py (+0/-3)
lib/lp/code/model/branch.py (+4/-8)
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/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_teammembership.py (+1/-2)
lib/lp/services/features/flags.py (+0/-34)
To merge this branch: bzr merge lp:~stevenk/launchpad/drop-disclosure-feature-flags
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+121523@code.launchpad.net

Commit message

Destroy five disclosure feature flags.

Description of the change

Destroy all disclosure feature flags I can, namely:

* disclosure.add-team-person-picker.enabled
* disclosure.enhanced_sharing.enabled
* disclosure.enhanced_sharing_details.enabled
* disclosure.enhanced_sharing.writable
* disclosure.unsubscribe_jobs.enabled

There were a bunch of tests that tested that things didn't work or raised Unauthorized which I just removed. It seems like to me that the test changes in lib/lp/bugs/model/tests/test_bug.py were dependent on the unsubscription happening with the feature flag off, and I've changed the check calls to filter the results by who has access.

The bugsubscription.txt case seems to be more contrived. We subscribe Mark, and then switch the bug to private and check he isn't subscribed, and then flip the bug to public, and he still isn't subscribed.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) wrote :

69 @property
70 def enhanced_picker(self):
71 - flag = getFeatureFlag(
72 - "disclosure.add-team-person-picker.enabled")
73 - return flag and self.show_create_team_link
74 + return self.show_create_team_link

Can you get rid of enhanced_picker entirely?

I'd also like to see a deeper investigation/explanation of the bugsubscription.txt changes.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/app/browser/lazrjs.py'
--- lib/lp/app/browser/lazrjs.py 2012-08-14 01:57:17 +0000
+++ lib/lp/app/browser/lazrjs.py 2012-08-28 04:39:25 +0000
@@ -40,7 +40,6 @@
40 get_person_picker_entry_metadata,40 get_person_picker_entry_metadata,
41 vocabulary_filters,41 vocabulary_filters,
42 )42 )
43from lp.services.features import getFeatureFlag
44from lp.services.propertycache import cachedproperty43from lp.services.propertycache import cachedproperty
45from lp.services.webapp.interfaces import ILaunchBag44from lp.services.webapp.interfaces import ILaunchBag
46from lp.services.webapp.publisher import canonical_url45from lp.services.webapp.publisher import canonical_url
@@ -423,9 +422,7 @@
423422
424 @property423 @property
425 def show_create_team(self):424 def show_create_team(self):
426 return (self._show_create_team425 return self._show_create_team
427 and getFeatureFlag(
428 "disclosure.add-team-person-picker.enabled"))
429426
430 def getConfig(self):427 def getConfig(self):
431 config = super(InlinePersonEditPickerWidget, self).getConfig()428 config = super(InlinePersonEditPickerWidget, self).getConfig()
432429
=== modified file 'lib/lp/app/browser/tests/test_inlineeditpickerwidget.py'
--- lib/lp/app/browser/tests/test_inlineeditpickerwidget.py 2012-06-21 06:50:10 +0000
+++ lib/lp/app/browser/tests/test_inlineeditpickerwidget.py 2012-08-28 04:39:25 +0000
@@ -15,7 +15,6 @@
15 InlineEditPickerWidget,15 InlineEditPickerWidget,
16 InlinePersonEditPickerWidget,16 InlinePersonEditPickerWidget,
17 )17 )
18from lp.services.features.testing import FeatureFixture
19from lp.testing import (18from lp.testing import (
20 login_person,19 login_person,
21 TestCaseWithFactory,20 TestCaseWithFactory,
@@ -118,18 +117,9 @@
118 login_person(self.factory.makePerson())117 login_person(self.factory.makePerson())
119 self.assertFalse(widget.config['show_assign_me_button'])118 self.assertFalse(widget.config['show_assign_me_button'])
120119
121 def test_show_create_team_link_with_feature_flag(self):
122 with FeatureFixture(
123 {'disclosure.add-team-person-picker.enabled': 'true'}):
124 widget = self.getWidget(
125 None, vocabulary='ValidPersonOrTeam', required=True,
126 show_create_team=True)
127 login_person(self.factory.makePerson())
128 self.assertTrue(widget.config['show_create_team'])
129
130 def test_show_create_team_link(self):120 def test_show_create_team_link(self):
131 widget = self.getWidget(121 widget = self.getWidget(
132 None, vocabulary='ValidPersonOrTeam', required=True,122 None, vocabulary='ValidPersonOrTeam', required=True,
133 show_create_team=True)123 show_create_team=True)
134 login_person(self.factory.makePerson())124 login_person(self.factory.makePerson())
135 self.assertFalse(widget.config['show_create_team'])125 self.assertTrue(widget.config['show_create_team'])
136126
=== modified file 'lib/lp/app/browser/tests/test_vocabulary.py'
--- lib/lp/app/browser/tests/test_vocabulary.py 2012-08-13 19:34:10 +0000
+++ lib/lp/app/browser/tests/test_vocabulary.py 2012-08-28 04:39:25 +0000
@@ -135,40 +135,35 @@
135 self.assertEqual('sprite person', entry.css)135 self.assertEqual('sprite person', entry.css)
136 self.assertEqual('sprite new-window', entry.link_css)136 self.assertEqual('sprite new-window', entry.link_css)
137137
138 def test_PersonPickerEntrySourceAdapter_enhanced_picker_user(self):138 def test_PersonPickerEntrySourceAdapter_user(self):
139 # The enhanced person picker provides more information for users.139 # The person picker provides more information for users.
140 person = self.factory.makePerson(email='snarf@eg.dom', name='snarf')140 person = self.factory.makePerson(email='snarf@eg.dom', name='snarf')
141 creation_date = datetime(141 creation_date = datetime(
142 2005, 01, 30, 0, 0, 0, 0, pytz.timezone('UTC'))142 2005, 01, 30, 0, 0, 0, 0, pytz.timezone('UTC'))
143 removeSecurityProxy(person).datecreated = creation_date143 removeSecurityProxy(person).datecreated = creation_date
144 getUtility(IIrcIDSet).new(person, 'eg.dom', 'snarf')144 getUtility(IIrcIDSet).new(person, 'eg.dom', 'snarf')
145 getUtility(IIrcIDSet).new(person, 'ex.dom', 'pting')145 getUtility(IIrcIDSet).new(person, 'ex.dom', 'pting')
146 entry = get_picker_entry(146 entry = get_picker_entry(person, None, picker_expander_enabled=True)
147 person, None, enhanced_picker_enabled=True,
148 picker_expander_enabled=True)
149 self.assertEqual('http://launchpad.dev/~snarf', entry.alt_title_link)147 self.assertEqual('http://launchpad.dev/~snarf', entry.alt_title_link)
150 self.assertEqual(148 self.assertEqual(
151 ['snarf on eg.dom, pting on ex.dom', 'Member since 2005-01-30'],149 ['snarf on eg.dom, pting on ex.dom', 'Member since 2005-01-30'],
152 entry.details)150 entry.details)
153151
154 def test_PersonPickerEntrySourceAdapter_enhanced_picker_team(self):152 def test_PersonPickerEntrySourceAdapter_team(self):
155 # The enhanced person picker provides more information for teams.153 # The person picker provides more information for teams.
156 team = self.factory.makeTeam(email='fnord@eg.dom', name='fnord')154 team = self.factory.makeTeam(email='fnord@eg.dom', name='fnord')
157 entry = get_picker_entry(155 entry = get_picker_entry(team, None, picker_expander_enabled=True)
158 team, None, enhanced_picker_enabled=True,
159 picker_expander_enabled=True)
160 self.assertEqual('http://launchpad.dev/~fnord', entry.alt_title_link)156 self.assertEqual('http://launchpad.dev/~fnord', entry.alt_title_link)
161 self.assertEqual(['Team members: 1'], entry.details)157 self.assertEqual(['Team members: 1'], entry.details)
162158
163 def test_PersonPickerEntryAdapter_enhanced_picker_enabled_badges(self):159 def test_PersonPickerEntryAdapter_badges(self):
164 # The enhanced person picker provides affiliation information.160 # The person picker provides affiliation information.
165 person = self.factory.makePerson(email='snarf@eg.dom', name='snarf')161 person = self.factory.makePerson(email='snarf@eg.dom', name='snarf')
166 project = self.factory.makeProduct(162 project = self.factory.makeProduct(
167 name='fnord', owner=person, bug_supervisor=person)163 name='fnord', owner=person, bug_supervisor=person)
168 bugtask = self.factory.makeBugTask(target=project)164 bugtask = self.factory.makeBugTask(target=project)
169 entry = get_picker_entry(165 entry = get_picker_entry(
170 person, bugtask, enhanced_picker_enabled=True,166 person, bugtask, picker_expander_enabled=True,
171 picker_expander_enabled=True,
172 personpicker_affiliation_enabled=True)167 personpicker_affiliation_enabled=True)
173 self.assertEqual(3, len(entry.badges))168 self.assertEqual(3, len(entry.badges))
174 self.assertEqual('/@@/product-badge', entry.badges[0]['url'])169 self.assertEqual('/@@/product-badge', entry.badges[0]['url'])
@@ -182,13 +177,12 @@
182 self.assertEqual('bug supervisor', entry.badges[2]['role'])177 self.assertEqual('bug supervisor', entry.badges[2]['role'])
183178
184 def test_PersonPickerEntryAdapter_badges_without_IHasAffiliation(self):179 def test_PersonPickerEntryAdapter_badges_without_IHasAffiliation(self):
185 # The enhanced person picker handles objects that do not support180 # The person picker handles objects that do not support
186 # IHasAffilliation.181 # IHasAffilliation.
187 person = self.factory.makePerson(email='snarf@eg.dom', name='snarf')182 person = self.factory.makePerson(email='snarf@eg.dom', name='snarf')
188 thing = object()183 thing = object()
189 entry = get_picker_entry(184 entry = get_picker_entry(
190 person, thing, enhanced_picker_enabled=True,185 person, thing, picker_expander_enabled=True,
191 picker_expander_enabled=True,
192 personpicker_affiliation_enabled=True)186 personpicker_affiliation_enabled=True)
193 self.assertIsNot(None, entry)187 self.assertIsNot(None, entry)
194188
195189
=== modified file 'lib/lp/app/javascript/picker/picker_patcher.js'
--- lib/lp/app/javascript/picker/picker_patcher.js 2012-07-07 14:00:30 +0000
+++ lib/lp/app/javascript/picker/picker_patcher.js 2012-08-28 04:39:25 +0000
@@ -25,19 +25,14 @@
25 return;25 return;
26 }26 }
27 var picker_span = show_widget_node.get('parentNode');27 var picker_span = show_widget_node.get('parentNode');
28 if (config.enhanced_picker) {28 var new_node = Y.Node.create('<span>(<a href="#"></a>)</span>');
29 var new_node = Y.Node.create('<span>(<a href="#"></a>)</span>');29 show_widget_node = new_node.one('a');
30 show_widget_node = new_node.one('a');30 show_widget_node
31 show_widget_node31 .set('id', show_widget_id)
32 .set('id', show_widget_id)32 .addClass('js-action')
33 .addClass('js-action')33 .set('text', 'Choose\u2026');
34 .set('text', 'Choose\u2026');34 picker_span.empty();
35 picker_span.empty();35 picker_span.appendChild(new_node);
36 picker_span.appendChild(new_node);
37 } else {
38 show_widget_node.set('text', 'Choose\u2026');
39 show_widget_node.addClass('js-action');
40 }
41 picker_span.removeClass('hidden');36 picker_span.removeClass('hidden');
42 show_widget_node.on('click', function (e) {37 show_widget_node.on('click', function (e) {
43 if (picker === null) {38 if (picker === null) {
4439
=== modified file 'lib/lp/app/widgets/popup.py'
--- lib/lp/app/widgets/popup.py 2012-07-07 14:00:30 +0000
+++ lib/lp/app/widgets/popup.py 2012-08-28 04:39:25 +0000
@@ -23,7 +23,6 @@
23 get_person_picker_entry_metadata,23 get_person_picker_entry_metadata,
24 vocabulary_filters,24 vocabulary_filters,
25 )25 )
26from lp.services.features import getFeatureFlag
27from lp.services.propertycache import cachedproperty26from lp.services.propertycache import cachedproperty
28from lp.services.webapp import canonical_url27from lp.services.webapp import canonical_url
2928
@@ -58,12 +57,6 @@
58 # Defaults to self.vocabulary.displayname.57 # Defaults to self.vocabulary.displayname.
59 header = None58 header = None
6059
61 @property
62 def enhanced_picker(self):
63 flag = getFeatureFlag(
64 "disclosure.add-team-person-picker.enabled")
65 return flag and self.show_create_team_link
66
67 @cachedproperty60 @cachedproperty
68 def matches(self):61 def matches(self):
69 """Return a list of matches (as ITokenizedTerm) to whatever the62 """Return a list of matches (as ITokenizedTerm) to whatever the
@@ -152,8 +145,7 @@
152 vocabulary_filters=self.vocabulary_filters,145 vocabulary_filters=self.vocabulary_filters,
153 input_element=self.input_id,146 input_element=self.input_id,
154 show_widget_id=self.show_widget_id,147 show_widget_id=self.show_widget_id,
155 enhanced_picker=self.enhanced_picker,148 show_create_team=self.show_create_team_link)
156 show_create_team=self.enhanced_picker)
157149
158 @property150 @property
159 def json_config(self):151 def json_config(self):
160152
=== modified file 'lib/lp/app/widgets/tests/test_popup.py'
--- lib/lp/app/widgets/tests/test_popup.py 2012-06-28 01:27:06 +0000
+++ lib/lp/app/widgets/tests/test_popup.py 2012-08-28 04:39:25 +0000
@@ -13,7 +13,6 @@
13 PersonPickerWidget,13 PersonPickerWidget,
14 VocabularyPickerWidget,14 VocabularyPickerWidget,
15 )15 )
16from lp.services.features.testing import FeatureFixture
17from lp.services.webapp.servers import LaunchpadTestRequest16from lp.services.webapp.servers import LaunchpadTestRequest
18from lp.testing import TestCaseWithFactory17from lp.testing import TestCaseWithFactory
19from lp.testing.layers import DatabaseFunctionalLayer18from lp.testing.layers import DatabaseFunctionalLayer
@@ -170,24 +169,14 @@
170 self.assertFalse(person_picker_widget.config['show_remove_button'])169 self.assertFalse(person_picker_widget.config['show_remove_button'])
171170
172 def test_create_team_link(self):171 def test_create_team_link(self):
173 # The person picker widget shows a create team link if the feature flag172 # The person picker widget shows a create team link.
174 # is on.
175 field = ITest['test_valid.item']173 field = ITest['test_valid.item']
176 bound_field = field.bind(self.context)174 bound_field = field.bind(self.context)
177175
178 with FeatureFixture(
179 {'disclosure.add-team-person-picker.enabled': 'true'}):
180 picker_widget = PersonPickerWidget(
181 bound_field, self.vocabulary, self.request)
182 picker_widget.show_create_team_link = True
183 self.assertTrue(picker_widget.config['show_create_team'])
184 self.assertTrue(picker_widget.config['enhanced_picker'])
185
186 picker_widget = PersonPickerWidget(176 picker_widget = PersonPickerWidget(
187 bound_field, self.vocabulary, self.request)177 bound_field, self.vocabulary, self.request)
188 picker_widget.show_create_team_link = True178 picker_widget.show_create_team_link = True
189 self.assertFalse(picker_widget.config['show_create_team'])179 self.assertTrue(picker_widget.config['show_create_team'])
190 self.assertFalse(picker_widget.config['enhanced_picker'])
191180
192 def test_widget_personvalue_meta(self):181 def test_widget_personvalue_meta(self):
193 # The person picker has the correct meta value for a person value.182 # The person picker has the correct meta value for a person value.
194183
=== modified file 'lib/lp/bugs/doc/bugsubscription.txt'
--- lib/lp/bugs/doc/bugsubscription.txt 2012-08-22 23:02:40 +0000
+++ lib/lp/bugs/doc/bugsubscription.txt 2012-08-28 04:39:25 +0000
@@ -364,6 +364,7 @@
364364
365 >>> print_displayname(linux_source_bug.getDirectSubscribers())365 >>> print_displayname(linux_source_bug.getDirectSubscribers())
366 Foo Bar366 Foo Bar
367 Mark Shuttleworth
367 Robert Collins368 Robert Collins
368369
369Direct subscriptions always take precedence over indirect subscriptions.370Direct subscriptions always take precedence over indirect subscriptions.
@@ -375,6 +376,7 @@
375376
376 >>> print_displayname(linux_source_bug.getDirectSubscribers())377 >>> print_displayname(linux_source_bug.getDirectSubscribers())
377 Foo Bar378 Foo Bar
379 Mark Shuttleworth
378 Robert Collins380 Robert Collins
379381
380 >>> print_displayname(linux_source_bug.getIndirectSubscribers())382 >>> print_displayname(linux_source_bug.getIndirectSubscribers())
@@ -398,6 +400,7 @@
398 >>> addresses = recipients.getEmails()400 >>> addresses = recipients.getEmails()
399 >>> [(address, recipients.getReason(address)[1]) for address in addresses]401 >>> [(address, recipients.getReason(address)[1]) for address in addresses]
400 [('foo.bar@canonical.com', 'Subscriber'),402 [('foo.bar@canonical.com', 'Subscriber'),
403 ('mark@example.com', 'Subscriber'),
401 ('no-priv@canonical.com', u'Subscriber (linux-source-2.6.15 in Ubuntu)'),404 ('no-priv@canonical.com', u'Subscriber (linux-source-2.6.15 in Ubuntu)'),
402 ('robertc@robertcollins.net', 'Subscriber'),405 ('robertc@robertcollins.net', 'Subscriber'),
403 ('test@canonical.com', 'Assignee')]406 ('test@canonical.com', 'Assignee')]
@@ -411,6 +414,7 @@
411 >>> addresses = recipients.getEmails()414 >>> addresses = recipients.getEmails()
412 >>> [(address, recipients.getReason(address)[1]) for address in addresses]415 >>> [(address, recipients.getReason(address)[1]) for address in addresses]
413 [('foo.bar@canonical.com', 'Subscriber'),416 [('foo.bar@canonical.com', 'Subscriber'),
417 ('mark@example.com', 'Subscriber'),
414 ('robertc@robertcollins.net', 'Subscriber'),418 ('robertc@robertcollins.net', 'Subscriber'),
415 ('test@canonical.com', 'Assignee')]419 ('test@canonical.com', 'Assignee')]
416420
@@ -424,6 +428,7 @@
424 >>> addresses = recipients.getEmails()428 >>> addresses = recipients.getEmails()
425 >>> [(address, recipients.getReason(address)[1]) for address in addresses]429 >>> [(address, recipients.getReason(address)[1]) for address in addresses]
426 [('foo.bar@canonical.com', 'Subscriber'),430 [('foo.bar@canonical.com', 'Subscriber'),
431 ('mark@example.com', 'Subscriber'),
427 ('robertc@robertcollins.net', 'Subscriber'),432 ('robertc@robertcollins.net', 'Subscriber'),
428 ('test@canonical.com', 'Assignee')]433 ('test@canonical.com', 'Assignee')]
429434
@@ -435,6 +440,7 @@
435 >>> addresses = recipients.getEmails()440 >>> addresses = recipients.getEmails()
436 >>> [(address, recipients.getReason(address)[1]) for address in addresses]441 >>> [(address, recipients.getReason(address)[1]) for address in addresses]
437 [('foo.bar@canonical.com', 'Subscriber'),442 [('foo.bar@canonical.com', 'Subscriber'),
443 ('mark@example.com', 'Subscriber'),
438 ('no-priv@canonical.com', u'Subscriber (linux-source-2.6.15 in Ubuntu)'),444 ('no-priv@canonical.com', u'Subscriber (linux-source-2.6.15 in Ubuntu)'),
439 ('robertc@robertcollins.net', 'Subscriber'),445 ('robertc@robertcollins.net', 'Subscriber'),
440 ('test@canonical.com', 'Assignee')]446 ('test@canonical.com', 'Assignee')]
441447
=== modified file 'lib/lp/bugs/model/bug.py'
--- lib/lp/bugs/model/bug.py 2012-08-23 04:20:48 +0000
+++ lib/lp/bugs/model/bug.py 2012-08-28 04:39:25 +0000
@@ -200,7 +200,6 @@
200 sqlvalues,200 sqlvalues,
201 )201 )
202from lp.services.database.stormbase import StormBase202from lp.services.database.stormbase import StormBase
203from lp.services.features import getFeatureFlag
204from lp.services.fields import DuplicateBug203from lp.services.fields import DuplicateBug
205from lp.services.helpers import shortlist204from lp.services.helpers import shortlist
206from lp.services.librarian.interfaces import ILibraryFileAliasSet205from lp.services.librarian.interfaces import ILibraryFileAliasSet
@@ -1766,18 +1765,10 @@
1766 if pillar.driver in subscribers and pillar != ubuntu:1765 if pillar.driver in subscribers and pillar != ubuntu:
1767 required_subscribers.add(pillar.driver)1766 required_subscribers.add(pillar.driver)
1768 service = getUtility(IService, 'sharing')1767 service = getUtility(IService, 'sharing')
1769 subscribers_to_remove = set(service.getPeopleWithoutAccess(
1770 self, subscribers)).difference(required_subscribers)
1771 if len(required_subscribers):1768 if len(required_subscribers):
1772 service.ensureAccessGrants(1769 service.ensureAccessGrants(
1773 required_subscribers, who, bugs=[self],1770 required_subscribers, who, bugs=[self],
1774 ignore_permissions=True)1771 ignore_permissions=True)
1775 # There is a job to do the unsubscribe, but it's behind a
1776 # flag. If that flag is not set, do it manually.
1777 if len(subscribers_to_remove) and not bool(
1778 getFeatureFlag('disclosure.unsubscribe_jobs.enabled')):
1779 for s in subscribers_to_remove:
1780 self.unsubscribe(s, who, ignore_permissions=True)
17811772
1782 # Add the required subscribers, but not if they are all already1773 # Add the required subscribers, but not if they are all already
1783 # subscribed via a team.1774 # subscribed via a team.
@@ -1788,13 +1779,10 @@
17881779
1789 self.updateHeat()1780 self.updateHeat()
17901781
1791 flag = 'disclosure.unsubscribe_jobs.enabled'1782 # As a result of the transition, some subscribers may no longer
1792 if bool(getFeatureFlag(flag)):1783 # have access to the bug. We need to run a job to remove any such
1793 # As a result of the transition, some subscribers may no longer1784 # subscriptions.
1794 # have access to the bug. We need to run a job to remove any such1785 getUtility(IRemoveArtifactSubscriptionsJobSource).create(who, [self])
1795 # subscriptions.
1796 getUtility(IRemoveArtifactSubscriptionsJobSource).create(
1797 who, [self])
17981786
1799 return True1787 return True
18001788
18011789
=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py 2012-08-24 01:17:35 +0000
+++ lib/lp/bugs/model/bugtask.py 2012-08-28 04:39:25 +0000
@@ -141,7 +141,6 @@
141 SQLBase,141 SQLBase,
142 sqlvalues,142 sqlvalues,
143 )143 )
144from lp.services.features import getFeatureFlag
145from lp.services.helpers import shortlist144from lp.services.helpers import shortlist
146from lp.services.propertycache import get_property_cache145from lp.services.propertycache import get_property_cache
147from lp.services.searchbuilder import any146from lp.services.searchbuilder import any
@@ -1140,13 +1139,11 @@
1140 self.maybeConfirm()1139 self.maybeConfirm()
1141 # END TEMPORARY BIT FOR BUGTASK AUTOCONFIRM FEATURE FLAG.1140 # END TEMPORARY BIT FOR BUGTASK AUTOCONFIRM FEATURE FLAG.
11421141
1143 flag = 'disclosure.unsubscribe_jobs.enabled'1142 # As a result of the transition, some subscribers may no longer
1144 if bool(getFeatureFlag(flag)):1143 # have access to the parent bug. We need to run a job to remove any
1145 # As a result of the transition, some subscribers may no longer1144 # such subscriptions.
1146 # have access to the parent bug. We need to run a job to remove any1145 getUtility(IRemoveArtifactSubscriptionsJobSource).create(
1147 # such subscriptions.1146 user, [self.bug], pillar=target_before_change.pillar)
1148 getUtility(IRemoveArtifactSubscriptionsJobSource).create(
1149 user, [self.bug], pillar=target_before_change.pillar)
11501147
1151 def updateTargetNameCache(self, newtarget=None):1148 def updateTargetNameCache(self, newtarget=None):
1152 """See `IBugTask`."""1149 """See `IBugTask`."""
11531150
=== modified file 'lib/lp/bugs/model/tests/test_bug.py'
--- lib/lp/bugs/model/tests/test_bug.py 2012-08-23 04:20:48 +0000
+++ lib/lp/bugs/model/tests/test_bug.py 2012-08-28 04:39:25 +0000
@@ -639,7 +639,7 @@
639 who = self.factory.makePerson(name='who')639 who = self.factory.makePerson(name='who')
640 bug.transitionToInformationType(640 bug.transitionToInformationType(
641 InformationType.PRIVATESECURITY, who=who)641 InformationType.PRIVATESECURITY, who=who)
642 subscribers = bug.getDirectSubscribers()642 subscribers = bug.getDirectSubscribers(filter_visible=True)
643 expected_subscribers = set((643 expected_subscribers = set((
644 default_bugtask.pillar.driver, bug_owner, who))644 default_bugtask.pillar.driver, bug_owner, who))
645 self.assertContentEqual(expected_subscribers, subscribers)645 self.assertContentEqual(expected_subscribers, subscribers)
@@ -662,7 +662,7 @@
662 bug.subscribe(subscriber, bug_owner)662 bug.subscribe(subscriber, bug_owner)
663 who = self.factory.makePerson(name='who')663 who = self.factory.makePerson(name='who')
664 bug.transitionToInformationType(InformationType.USERDATA, who)664 bug.transitionToInformationType(InformationType.USERDATA, who)
665 subscribers = bug.getDirectSubscribers()665 subscribers = bug.getDirectSubscribers(filter_visible=True)
666 expected_subscribers = set((666 expected_subscribers = set((
667 default_bugtask.pillar.bug_supervisor,667 default_bugtask.pillar.bug_supervisor,
668 default_bugtask.pillar.driver,668 default_bugtask.pillar.driver,
669669
=== modified file 'lib/lp/bugs/model/tests/test_bugsummary.py'
--- lib/lp/bugs/model/tests/test_bugsummary.py 2012-08-08 11:48:29 +0000
+++ lib/lp/bugs/model/tests/test_bugsummary.py 2012-08-28 04:39:25 +0000
@@ -28,7 +28,6 @@
28 SharingPermission,28 SharingPermission,
29 )29 )
30from lp.services.database.lpstorm import IMasterStore30from lp.services.database.lpstorm import IMasterStore
31from lp.services.features.testing import FeatureFixture
32from lp.testing import TestCaseWithFactory31from lp.testing import TestCaseWithFactory
33from lp.testing.dbuser import switch_dbuser32from lp.testing.dbuser import switch_dbuser
34from lp.testing.layers import LaunchpadZopelessLayer33from lp.testing.layers import LaunchpadZopelessLayer
@@ -192,11 +191,9 @@
192 person_b = self.factory.makePerson()191 person_b = self.factory.makePerson()
193 person_c = self.factory.makePerson()192 person_c = self.factory.makePerson()
194 product = self.factory.makeProduct()193 product = self.factory.makeProduct()
195 with FeatureFixture(194 getUtility(IService, 'sharing').sharePillarInformation(
196 {'disclosure.enhanced_sharing.writable': 'true'}):195 product, person_c, product.owner,
197 getUtility(IService, 'sharing').sharePillarInformation(196 {InformationType.USERDATA: SharingPermission.ALL})
198 product, person_c, product.owner,
199 {InformationType.USERDATA: SharingPermission.ALL})
200 bug = self.factory.makeBug(target=product, owner=person_b)197 bug = self.factory.makeBug(target=product, owner=person_b)
201198
202 bug.subscribe(person=person_a, subscribed_by=person_a)199 bug.subscribe(person=person_a, subscribed_by=person_a)
203200
=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
--- lib/lp/bugs/model/tests/test_bugtask.py 2012-08-27 23:58:18 +0000
+++ lib/lp/bugs/model/tests/test_bugtask.py 2012-08-28 04:39:25 +0000
@@ -2678,7 +2678,6 @@
26782678
2679 def setUp(self):2679 def setUp(self):
2680 self.useFixture(FeatureFixture({2680 self.useFixture(FeatureFixture({
2681 'disclosure.unsubscribe_jobs.enabled': 'true',
2682 'jobs.celery.enabled_classes': 'RemoveArtifactSubscriptionsJob',2681 'jobs.celery.enabled_classes': 'RemoveArtifactSubscriptionsJob',
2683 }))2682 }))
2684 super(TestTransitionsRemovesSubscribersJob, self).setUp()2683 super(TestTransitionsRemovesSubscribersJob, self).setUp()
26852684
=== modified file 'lib/lp/bugs/model/tests/test_bugtasksearch.py'
--- lib/lp/bugs/model/tests/test_bugtasksearch.py 2012-08-16 05:18:54 +0000
+++ lib/lp/bugs/model/tests/test_bugtasksearch.py 2012-08-28 04:39:25 +0000
@@ -67,7 +67,6 @@
67from lp.registry.model.person import Person67from lp.registry.model.person import Person
68from lp.services.database.lpstorm import IStore68from lp.services.database.lpstorm import IStore
69from lp.services.database.sqlbase import convert_storm_clause_to_string69from lp.services.database.sqlbase import convert_storm_clause_to_string
70from lp.services.features.testing import FeatureFixture
71from lp.services.searchbuilder import (70from lp.services.searchbuilder import (
72 all,71 all,
73 any,72 any,
@@ -2410,8 +2409,6 @@
2410 # People and teams with AccessPolicyGrants can see the bug.2409 # People and teams with AccessPolicyGrants can see the bug.
2411 self.makePrivacyScenario()2410 self.makePrivacyScenario()
24122411
2413 self.useFixture(FeatureFixture(
2414 {'disclosure.enhanced_sharing.writable': 'true'}))
2415 with admin_logged_in():2412 with admin_logged_in():
2416 for princ in (self.grantee_team, self.grantee_person):2413 for princ in (self.grantee_team, self.grantee_person):
2417 getUtility(IService, 'sharing').sharePillarInformation(2414 getUtility(IService, 'sharing').sharePillarInformation(
24182415
=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py 2012-08-07 02:31:56 +0000
+++ lib/lp/code/model/branch.py 2012-08-28 04:39:25 +0000
@@ -171,7 +171,6 @@
171 ArrayAgg,171 ArrayAgg,
172 ArrayIntersects,172 ArrayIntersects,
173 )173 )
174from lp.services.features import getFeatureFlag
175from lp.services.helpers import shortlist174from lp.services.helpers import shortlist
176from lp.services.job.interfaces.job import JobStatus175from lp.services.job.interfaces.job import JobStatus
177from lp.services.job.model.job import Job176from lp.services.job.model.job import Job
@@ -272,13 +271,10 @@
272 service.ensureAccessGrants(271 service.ensureAccessGrants(
273 blind_subscribers, who, branches=[self],272 blind_subscribers, who, branches=[self],
274 ignore_permissions=True)273 ignore_permissions=True)
275 flag = 'disclosure.unsubscribe_jobs.enabled'274 # As a result of the transition, some subscribers may no longer
276 if bool(getFeatureFlag(flag)):275 # have access to the branch. We need to run a job to remove any
277 # As a result of the transition, some subscribers may no longer276 # such subscriptions.
278 # have access to the branch. We need to run a job to remove any277 getUtility(IRemoveArtifactSubscriptionsJobSource).create(who, [self])
279 # such subscriptions.
280 getUtility(IRemoveArtifactSubscriptionsJobSource).create(
281 who, [self])
282278
283 registrant = ForeignKey(279 registrant = ForeignKey(
284 dbName='registrant', foreignKey='Person',280 dbName='registrant', foreignKey='Person',
285281
=== modified file 'lib/lp/code/model/tests/test_branchnamespace.py'
--- lib/lp/code/model/tests/test_branchnamespace.py 2012-08-22 14:23:12 +0000
+++ lib/lp/code/model/tests/test_branchnamespace.py 2012-08-28 04:39:25 +0000
@@ -57,7 +57,6 @@
57 )57 )
58from lp.registry.interfaces.product import NoSuchProduct58from lp.registry.interfaces.product import NoSuchProduct
59from lp.registry.model.sourcepackage import SourcePackage59from lp.registry.model.sourcepackage import SourcePackage
60from lp.services.features.testing import FeatureFixture
61from lp.testing import (60from lp.testing import (
62 person_logged_in,61 person_logged_in,
63 TestCaseWithFactory,62 TestCaseWithFactory,
@@ -458,11 +457,6 @@
458457
459 layer = DatabaseFunctionalLayer458 layer = DatabaseFunctionalLayer
460459
461 def setUp(self):
462 super(TestProductNamespacePrivacyWithInformationType, self).setUp()
463 self.useFixture(FeatureFixture(
464 {'disclosure.enhanced_sharing.writable': 'true'}))
465
466 def makeProductNamespace(self, sharing_policy, person=None):460 def makeProductNamespace(self, sharing_policy, person=None):
467 if person is None:461 if person is None:
468 person = self.factory.makePerson()462 person = self.factory.makePerson()
469463
=== modified file 'lib/lp/registry/browser/distribution.py'
--- lib/lp/registry/browser/distribution.py 2012-08-21 00:34:02 +0000
+++ lib/lp/registry/browser/distribution.py 2012-08-28 04:39:25 +0000
@@ -108,7 +108,6 @@
108 )108 )
109from lp.registry.interfaces.series import SeriesStatus109from lp.registry.interfaces.series import SeriesStatus
110from lp.services.database.decoratedresultset import DecoratedResultSet110from lp.services.database.decoratedresultset import DecoratedResultSet
111from lp.services.features import getFeatureFlag
112from lp.services.feeds.browser import FeedsMixin111from lp.services.feeds.browser import FeedsMixin
113from lp.services.geoip.helpers import (112from lp.services.geoip.helpers import (
114 ipaddress_from_request,113 ipaddress_from_request,
@@ -313,12 +312,7 @@
313312
314 @enabled_with_permission('launchpad.Driver')313 @enabled_with_permission('launchpad.Driver')
315 def sharing(self):314 def sharing(self):
316 text = 'Sharing'315 return Link('+sharing', 'Sharing', icon='edit')
317 enabled_readonly_flag = 'disclosure.enhanced_sharing.enabled'
318 enabled_writable_flag = 'disclosure.enhanced_sharing.writable'
319 enabled = (bool(getFeatureFlag(enabled_readonly_flag))
320 or bool(getFeatureFlag(enabled_writable_flag)))
321 return Link('+sharing', text, icon='edit', enabled=enabled)
322316
323 @cachedproperty317 @cachedproperty
324 def links(self):318 def links(self):
325319
=== modified file 'lib/lp/registry/browser/pillar.py'
--- lib/lp/registry/browser/pillar.py 2012-08-23 04:42:37 +0000
+++ lib/lp/registry/browser/pillar.py 2012-08-28 04:39:25 +0000
@@ -31,7 +31,6 @@
31 getVocabularyRegistry,31 getVocabularyRegistry,
32 SimpleVocabulary,32 SimpleVocabulary,
33 )33 )
34from zope.security.interfaces import Unauthorized
35from zope.traversing.browser.absoluteurl import absoluteURL34from zope.traversing.browser.absoluteurl import absoluteURL
3635
37from lp.app.browser.launchpad import iter_view_registrations36from lp.app.browser.launchpad import iter_view_registrations
@@ -60,9 +59,7 @@
60from lp.registry.interfaces.projectgroup import IProjectGroup59from lp.registry.interfaces.projectgroup import IProjectGroup
61from lp.registry.model.pillar import PillarPerson60from lp.registry.model.pillar import PillarPerson
62from lp.services.config import config61from lp.services.config import config
63from lp.services.features import getFeatureFlag
64from lp.services.propertycache import cachedproperty62from lp.services.propertycache import cachedproperty
65from lp.services.webapp.authorization import check_permission
66from lp.services.webapp.batching import (63from lp.services.webapp.batching import (
67 BatchNavigator,64 BatchNavigator,
68 StormRangeFactory,65 StormRangeFactory,
@@ -278,11 +275,6 @@
278275
279 sharing_vocabulary_name = 'NewPillarGrantee'276 sharing_vocabulary_name = 'NewPillarGrantee'
280277
281 related_features = (
282 'disclosure.enhanced_sharing.enabled',
283 'disclosure.enhanced_sharing.writable',
284 )
285
286 _batch_navigator = None278 _batch_navigator = None
287279
288 def _getSharingService(self):280 def _getSharingService(self):
@@ -348,16 +340,7 @@
348340
349 def initialize(self):341 def initialize(self):
350 super(PillarSharingView, self).initialize()342 super(PillarSharingView, self).initialize()
351 enabled_readonly_flag = 'disclosure.enhanced_sharing.enabled'
352 enabled_writable_flag = (
353 'disclosure.enhanced_sharing.writable')
354 enabled = bool(getFeatureFlag(enabled_readonly_flag))
355 write_flag_enabled = bool(getFeatureFlag(enabled_writable_flag))
356 if not enabled and not write_flag_enabled:
357 raise Unauthorized("This feature is not yet available.")
358 cache = IJSONRequestCache(self.request)343 cache = IJSONRequestCache(self.request)
359 cache.objects['sharing_write_enabled'] = (write_flag_enabled
360 and check_permission('launchpad.Edit', self.context))
361 cache.objects['information_types'] = self.information_types344 cache.objects['information_types'] = self.information_types
362 cache.objects['sharing_permissions'] = self.sharing_permissions345 cache.objects['sharing_permissions'] = self.sharing_permissions
363 cache.objects['bug_sharing_policies'] = self.bug_sharing_policies346 cache.objects['bug_sharing_policies'] = self.bug_sharing_policies
@@ -402,11 +385,6 @@
402 label = "Information shared with person or team"385 label = "Information shared with person or team"
403386
404 def initialize(self):387 def initialize(self):
405 enabled_flag = 'disclosure.enhanced_sharing_details.enabled'
406 enabled = bool(getFeatureFlag(enabled_flag))
407 if not enabled:
408 raise Unauthorized("This feature is not yet available.")
409
410 self.pillar = self.context.pillar388 self.pillar = self.context.pillar
411 self.person = self.context.person389 self.person = self.context.person
412390
@@ -431,11 +409,6 @@
431 cache.objects['pillar'] = pillar_data409 cache.objects['pillar'] = pillar_data
432 cache.objects['bugs'] = bug_data410 cache.objects['bugs'] = bug_data
433 cache.objects['branches'] = branch_data411 cache.objects['branches'] = branch_data
434 enabled_writable_flag = (
435 'disclosure.enhanced_sharing.writable')
436 write_flag_enabled = bool(getFeatureFlag(enabled_writable_flag))
437 cache.objects['sharing_write_enabled'] = (write_flag_enabled
438 and check_permission('launchpad.Edit', self.pillar))
439412
440 def _loadSharedArtifacts(self):413 def _loadSharedArtifacts(self):
441 # As a concrete can by linked via more than one policy, we use sets to414 # As a concrete can by linked via more than one policy, we use sets to
442415
=== modified file 'lib/lp/registry/browser/product.py'
--- lib/lp/registry/browser/product.py 2012-08-23 04:42:37 +0000
+++ lib/lp/registry/browser/product.py 2012-08-28 04:39:25 +0000
@@ -171,7 +171,6 @@
171from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet171from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
172from lp.services.config import config172from lp.services.config import config
173from lp.services.database.decoratedresultset import DecoratedResultSet173from lp.services.database.decoratedresultset import DecoratedResultSet
174from lp.services.features import getFeatureFlag
175from lp.services.feeds.browser import FeedsMixin174from lp.services.feeds.browser import FeedsMixin
176from lp.services.fields import (175from lp.services.fields import (
177 PillarAliases,176 PillarAliases,
@@ -500,12 +499,7 @@
500499
501 @enabled_with_permission('launchpad.Driver')500 @enabled_with_permission('launchpad.Driver')
502 def sharing(self):501 def sharing(self):
503 text = 'Sharing'502 return Link('+sharing', 'Sharing', icon='edit')
504 enabled_readonly_flag = 'disclosure.enhanced_sharing.enabled'
505 enabled_writable_flag = 'disclosure.enhanced_sharing.writable'
506 enabled = (bool(getFeatureFlag(enabled_readonly_flag))
507 or bool(getFeatureFlag(enabled_writable_flag)))
508 return Link('+sharing', text, icon='edit', enabled=enabled)
509503
510504
511class IProductEditMenu(Interface):505class IProductEditMenu(Interface):
512506
=== modified file 'lib/lp/registry/browser/tests/test_pillar_sharing.py'
--- lib/lp/registry/browser/tests/test_pillar_sharing.py 2012-08-14 04:48:36 +0000
+++ lib/lp/registry/browser/tests/test_pillar_sharing.py 2012-08-28 04:39:25 +0000
@@ -17,7 +17,6 @@
17 Raises,17 Raises,
18 )18 )
19from zope.component import getUtility19from zope.component import getUtility
20from zope.security.interfaces import Unauthorized
21from zope.traversing.browser.absoluteurl import absoluteURL20from zope.traversing.browser.absoluteurl import absoluteURL
2221
23from lp.app.interfaces.services import IService22from lp.app.interfaces.services import IService
@@ -30,7 +29,6 @@
30from lp.registry.model.pillar import PillarPerson29from lp.registry.model.pillar import PillarPerson
31from lp.services.config import config30from lp.services.config import config
32from lp.services.database.lpstorm import IStore31from lp.services.database.lpstorm import IStore
33from lp.services.features.testing import FeatureFixture
34from lp.services.webapp.interfaces import StormRangeFactoryError32from lp.services.webapp.interfaces import StormRangeFactoryError
35from lp.services.webapp.publisher import canonical_url33from lp.services.webapp.publisher import canonical_url
36from lp.testing import (34from lp.testing import (
@@ -49,14 +47,6 @@
49 )47 )
5048
5149
52DETAILS_ENABLED_FLAG = {'disclosure.enhanced_sharing_details.enabled': 'true'}
53DETAILS_WRITE_FLAG = {
54 'disclosure.enhanced_sharing_details.enabled': 'true',
55 'disclosure.enhanced_sharing.writable': 'true'}
56ENABLED_FLAG = {'disclosure.enhanced_sharing.enabled': 'true'}
57WRITE_FLAG = {'disclosure.enhanced_sharing.writable': 'true'}
58
59
60class SharingBaseTestCase(TestCaseWithFactory):50class SharingBaseTestCase(TestCaseWithFactory):
6151
62 layer = DatabaseFunctionalLayer52 layer = DatabaseFunctionalLayer
@@ -146,124 +136,94 @@
146 # There are bugs in the sharingdetails view that not everyone with136 # There are bugs in the sharingdetails view that not everyone with
147 # `launchpad.Driver` -- the permission level for the page -- should be137 # `launchpad.Driver` -- the permission level for the page -- should be
148 # able to see.138 # able to see.
149 with FeatureFixture(DETAILS_ENABLED_FLAG):139 pillarperson = self.getPillarPerson(security=True)
150 pillarperson = self.getPillarPerson(security=True)140 logout()
151 logout()141 login_person(self.driver)
152 login_person(self.driver)142 view = create_initialized_view(pillarperson, '+index')
153 view = create_initialized_view(pillarperson, '+index')143 # The page loads
154 # The page loads144 self.assertEqual(pillarperson.person.displayname, view.page_title)
155 self.assertEqual(pillarperson.person.displayname, view.page_title)145 # The bug, which is not shared with the driver, is not included.
156 # The bug, which is not shared with the driver, is not included.146 self.assertEqual(0, view.shared_bugs_count)
157 self.assertEqual(0, view.shared_bugs_count)
158147
159 def test_view_traverses_plus_sharingdetails(self):148 def test_view_traverses_plus_sharingdetails(self):
160 # The traversed url in the app is pillar/+sharing/person149 # The traversed url in the app is pillar/+sharing/person
161 with FeatureFixture(DETAILS_ENABLED_FLAG):150 # We have to do some fun url hacking to force the traversal a user
162 # We have to do some fun url hacking to force the traversal a user151 # encounters.
163 # encounters.152 pillarperson = self.getPillarPerson()
164 pillarperson = self.getPillarPerson()153 expected = "Sharing details for %s : Sharing : %s" % (
165 expected = "Sharing details for %s : Sharing : %s" % (154 pillarperson.person.displayname,
166 pillarperson.person.displayname,155 pillarperson.pillar.displayname)
167 pillarperson.pillar.displayname)156 url = 'http://launchpad.dev/%s/+sharing/%s' % (
168 url = 'http://launchpad.dev/%s/+sharing/%s' % (157 pillarperson.pillar.name, pillarperson.person.name)
169 pillarperson.pillar.name, pillarperson.person.name)158 browser = self.getUserBrowser(user=self.owner, url=url)
170 browser = self.getUserBrowser(user=self.owner, url=url)159 self.assertEqual(expected, browser.title)
171 self.assertEqual(expected, browser.title)
172160
173 def test_no_sharing_message(self):161 def test_no_sharing_message(self):
174 # If there is no sharing between pillar and person, a suitable message162 # If there is no sharing between pillar and person, a suitable message
175 # is displayed.163 # is displayed.
176 with FeatureFixture(DETAILS_ENABLED_FLAG):164 # We have to do some fun url hacking to force the traversal a user
177 # We have to do some fun url hacking to force the traversal a user165 # encounters.
178 # encounters.166 pillarperson = PillarPerson(
179 pillarperson = PillarPerson(167 self.pillar, self.factory.makePerson())
180 self.pillar, self.factory.makePerson())168 url = 'http://launchpad.dev/%s/+sharing/%s' % (
181 url = 'http://launchpad.dev/%s/+sharing/%s' % (169 pillarperson.pillar.name, pillarperson.person.name)
182 pillarperson.pillar.name, pillarperson.person.name)170 browser = self.getUserBrowser(user=self.owner, url=url)
183 browser = self.getUserBrowser(user=self.owner, url=url)171 self.assertIn(
184 self.assertIn(172 'There are no shared bugs or branches.', browser.contents)
185 'There are no shared bugs or branches.',173
186 browser.contents)174 def test_init_works(self):
187
188 def test_init_without_feature_flag(self):
189 # We need a feature flag to enable the view.
190 pillarperson = self.getPillarPerson()
191 self.assertRaises(
192 Unauthorized, create_initialized_view, pillarperson, '+index')
193
194 def test_init_with_feature_flag(self):
195 # The view works with a feature flag.175 # The view works with a feature flag.
196 with FeatureFixture(DETAILS_ENABLED_FLAG):176 pillarperson = self.getPillarPerson()
197 pillarperson = self.getPillarPerson()177 view = create_initialized_view(pillarperson, '+index')
198 view = create_initialized_view(pillarperson, '+index')178 self.assertEqual(pillarperson.person.displayname, view.page_title)
199 self.assertEqual(pillarperson.person.displayname, view.page_title)179 self.assertEqual(1, view.shared_bugs_count)
200 self.assertEqual(1, view.shared_bugs_count)
201180
202 def test_view_data_model(self):181 def test_view_data_model(self):
203 # Test that the json request cache contains the view data model.182 # Test that the json request cache contains the view data model.
204 with FeatureFixture(DETAILS_ENABLED_FLAG):183 pillarperson = self.getPillarPerson()
205 pillarperson = self.getPillarPerson()184 view = create_initialized_view(pillarperson, '+index')
206 view = create_initialized_view(pillarperson, '+index')185 bugtask = list(view.bugtasks)[0]
207 bugtask = list(view.bugtasks)[0]186 bug = bugtask.bug
208 bug = bugtask.bug187 cache = IJSONRequestCache(view.request)
209 cache = IJSONRequestCache(view.request)188 request = get_current_web_service_request()
210 request = get_current_web_service_request()189 self.assertEqual({
211 self.assertEqual({190 'self_link': absoluteURL(pillarperson.person, request),
212 'self_link': absoluteURL(pillarperson.person, request),191 'displayname': pillarperson.person.displayname
213 'displayname': pillarperson.person.displayname192 }, cache.objects.get('grantee'))
214 }, cache.objects.get('grantee'))193 self.assertEqual({
215 self.assertEqual({194 'self_link': absoluteURL(pillarperson.pillar, request),
216 'self_link': absoluteURL(pillarperson.pillar, request),195 }, cache.objects.get('pillar'))
217 }, cache.objects.get('pillar'))196 self.assertEqual({
218 self.assertEqual({197 'bug_id': bug.id,
219 'bug_id': bug.id,198 'bug_summary': bug.title,
220 'bug_summary': bug.title,199 'bug_importance': bugtask.importance.title.lower(),
221 'bug_importance': bugtask.importance.title.lower(),200 'information_type': bug.information_type.title,
222 'information_type': bug.information_type.title,201 'web_link': canonical_url(
223 'web_link': canonical_url(202 bugtask, path_only_if_possible=True),
224 bugtask, path_only_if_possible=True),203 'self_link': absoluteURL(bug, request),
225 'self_link': absoluteURL(bug, request),204 }, cache.objects.get('bugs')[0])
226 }, cache.objects.get('bugs')[0])205 if self.pillar_type == 'product':
227 if self.pillar_type == 'product':206 branch = list(view.branches)[0]
228 branch = list(view.branches)[0]207 self.assertEqual({
229 self.assertEqual({208 'branch_id': branch.id,
230 'branch_id': branch.id,209 'branch_name': branch.unique_name,
231 'branch_name': branch.unique_name,210 'information_type': InformationType.USERDATA.title,
232 'information_type': InformationType.USERDATA.title,211 'web_link': canonical_url(branch, path_only_if_possible=True),
233 'web_link': canonical_url(212 'self_link': absoluteURL(branch, request),
234 branch, path_only_if_possible=True),213 }, cache.objects.get('branches')[0])
235 'self_link': absoluteURL(branch, request),
236 }, cache.objects.get('branches')[0])
237214
238 def test_view_query_count(self):215 def test_view_query_count(self):
239 # Test that the view bulk loads artifacts.216 # Test that the view bulk loads artifacts.
240 with FeatureFixture(DETAILS_ENABLED_FLAG):217 person = self.factory.makePerson()
241 person = self.factory.makePerson()218 for x in range(0, 15):
242 for x in range(0, 15):219 self.makeArtifactGrantee(person, True, True, False)
243 self.makeArtifactGrantee(person, True, True, False)220 pillarperson = PillarPerson(self.pillar, person)
244 pillarperson = PillarPerson(self.pillar, person)221
245222 # Invalidate the Storm cache and check the query count.
246 # Invalidate the Storm cache and check the query count.223 IStore(self.pillar).invalidate()
247 IStore(self.pillar).invalidate()224 with StormStatementRecorder() as recorder:
248 with StormStatementRecorder() as recorder:225 create_initialized_view(pillarperson, '+index')
249 create_initialized_view(pillarperson, '+index')226 self.assertThat(recorder, HasQueryCount(LessThan(12)))
250 self.assertThat(recorder, HasQueryCount(LessThan(12)))
251
252 def test_view_write_enabled_without_feature_flag(self):
253 # Test that sharing_write_enabled is not set without the feature flag.
254 with FeatureFixture(DETAILS_ENABLED_FLAG):
255 pillarperson = self.getPillarPerson()
256 view = create_initialized_view(pillarperson, '+index')
257 cache = IJSONRequestCache(view.request)
258 self.assertFalse(cache.objects.get('sharing_write_enabled'))
259
260 def test_view_write_enabled_with_feature_flag(self):
261 # Test that sharing_write_enabled is set when required.
262 with FeatureFixture(DETAILS_WRITE_FLAG):
263 pillarperson = self.getPillarPerson()
264 view = create_initialized_view(pillarperson, '+index')
265 cache = IJSONRequestCache(view.request)
266 self.assertTrue(cache.objects.get('sharing_write_enabled'))
267227
268228
269class TestProductSharingDetailsView(229class TestProductSharingDetailsView(
@@ -289,132 +249,83 @@
289class PillarSharingViewTestMixin:249class PillarSharingViewTestMixin:
290 """Test the PillarSharingView."""250 """Test the PillarSharingView."""
291251
292 def test_init_without_feature_flag(self):252 def test_sharing_menu(self):
293 # We need a feature flag to enable the view.
294 self.assertRaises(
295 Unauthorized, create_initialized_view, self.pillar, '+sharing')
296
297 def test_init_with_feature_flag(self):
298 # The view works with a feature flag.
299 with FeatureFixture(ENABLED_FLAG):
300 view = create_initialized_view(self.pillar, '+sharing')
301 self.assertEqual('Sharing', view.page_title)
302
303 def test_sharing_menu_without_feature_flag(self):
304 url = canonical_url(self.pillar)253 url = canonical_url(self.pillar)
305 browser = setupBrowserForUser(user=self.driver)254 browser = setupBrowserForUser(user=self.driver)
306 browser.open(url)255 browser.open(url)
307 soup = BeautifulSoup(browser.contents)256 soup = BeautifulSoup(browser.contents)
308 sharing_menu = soup.find('a', {'class': 'menu-link-sharing'})257 sharing_url = canonical_url(self.pillar, view_name='+sharing')
309 self.assertIsNone(sharing_menu)258 sharing_menu = soup.find('a', {'href': sharing_url})
310259 self.assertIsNotNone(sharing_menu)
311 def test_sharing_menu_with_feature_flag(self):
312 with FeatureFixture(ENABLED_FLAG):
313 url = canonical_url(self.pillar)
314 browser = setupBrowserForUser(user=self.driver)
315 browser.open(url)
316 soup = BeautifulSoup(browser.contents)
317 sharing_url = canonical_url(self.pillar, view_name='+sharing')
318 sharing_menu = soup.find('a', {'href': sharing_url})
319 self.assertIsNotNone(sharing_menu)
320260
321 def test_picker_config(self):261 def test_picker_config(self):
322 # Test the config passed to the disclosure sharing picker.262 # Test the config passed to the disclosure sharing picker.
323 with FeatureFixture(ENABLED_FLAG):263 view = create_view(self.pillar, name='+sharing')
324 view = create_view(self.pillar, name='+sharing')264 picker_config = simplejson.loads(view.json_sharing_picker_config)
325 picker_config = simplejson.loads(view.json_sharing_picker_config)265 self.assertTrue('vocabulary_filters' in picker_config)
326 self.assertTrue('vocabulary_filters' in picker_config)266 self.assertEqual('Share project information', picker_config['header'])
327 self.assertEqual(267 self.assertEqual(
328 'Share project information',268 'Search for user or exclusive team with whom to share',
329 picker_config['header'])269 picker_config['steptitle'])
330 self.assertEqual(270 self.assertEqual('NewPillarGrantee', picker_config['vocabulary'])
331 'Search for user or exclusive team with whom to share',
332 picker_config['steptitle'])
333 self.assertEqual(
334 'NewPillarGrantee', picker_config['vocabulary'])
335271
336 def test_view_data_model(self):272 def test_view_data_model(self):
337 # Test that the json request cache contains the view data model.273 # Test that the json request cache contains the view data model.
338 with FeatureFixture(ENABLED_FLAG):274 view = create_initialized_view(self.pillar, name='+sharing')
339 view = create_initialized_view(self.pillar, name='+sharing')275 cache = IJSONRequestCache(view.request)
340 cache = IJSONRequestCache(view.request)276 self.assertIsNotNone(cache.objects.get('information_types'))
341 self.assertIsNotNone(cache.objects.get('information_types'))277 self.assertIsNotNone(cache.objects.get('branch_sharing_policies'))
342 self.assertIsNotNone(278 self.assertIsNotNone(cache.objects.get('bug_sharing_policies'))
343 cache.objects.get('branch_sharing_policies'))279 self.assertIsNotNone(cache.objects.get('sharing_permissions'))
344 self.assertIsNotNone(cache.objects.get('bug_sharing_policies'))280 batch_size = config.launchpad.default_batch_size
345 self.assertIsNotNone(cache.objects.get('sharing_permissions'))281 apgfs = getUtility(IAccessPolicyGrantFlatSource)
346 batch_size = config.launchpad.default_batch_size282 grantees = apgfs.findGranteePermissionsByPolicy(
347 apgfs = getUtility(IAccessPolicyGrantFlatSource)283 [self.access_policy], self.grantees[:batch_size])
348 grantees = apgfs.findGranteePermissionsByPolicy(284 sharing_service = getUtility(IService, 'sharing')
349 [self.access_policy], self.grantees[:batch_size])285 grantee_data = sharing_service.jsonGranteeData(grantees)
350 sharing_service = getUtility(IService, 'sharing')286 self.assertContentEqual(
351 grantee_data = sharing_service.jsonGranteeData(grantees)287 grantee_data, cache.objects.get('grantee_data'))
352 self.assertContentEqual(
353 grantee_data, cache.objects.get('grantee_data'))
354288
355 def test_view_batch_data(self):289 def test_view_batch_data(self):
356 # Test the expected batching data is in the json request cache.290 # Test the expected batching data is in the json request cache.
357 with FeatureFixture(ENABLED_FLAG):291 view = create_initialized_view(self.pillar, name='+sharing')
358 view = create_initialized_view(self.pillar, name='+sharing')292 cache = IJSONRequestCache(view.request)
359 cache = IJSONRequestCache(view.request)293 # Test one expected data value (there are many).
360 # Test one expected data value (there are many).294 next_batch = view.grantees().batch.nextBatch()
361 next_batch = view.grantees().batch.nextBatch()295 self.assertContentEqual(
362 self.assertContentEqual(296 next_batch.range_memo, cache.objects.get('next')['memo'])
363 next_batch.range_memo, cache.objects.get('next')['memo'])
364297
365 def test_view_range_factory(self):298 def test_view_range_factory(self):
366 # Test the view range factory is properly configured.299 # Test the view range factory is properly configured.
367 with FeatureFixture(ENABLED_FLAG):300 view = create_initialized_view(self.pillar, name='+sharing')
368 view = create_initialized_view(self.pillar, name='+sharing')301 range_factory = view.grantees().batch.range_factory
369 range_factory = view.grantees().batch.range_factory302
370303 def test_range_factory():
371 def test_range_factory():304 row = range_factory.resultset.get_plain_result_set()[0]
372 row = range_factory.resultset.get_plain_result_set()[0]305 range_factory.getOrderValuesFor(row)
373 range_factory.getOrderValuesFor(row)306
374307 self.assertThat(
375 self.assertThat(308 test_range_factory,
376 test_range_factory,309 Not(Raises(MatchesException(StormRangeFactoryError))))
377 Not(Raises(MatchesException(StormRangeFactoryError))))
378310
379 def test_view_query_count(self):311 def test_view_query_count(self):
380 # Test the query count is within expected limit.312 # Test the query count is within expected limit.
381 with FeatureFixture(ENABLED_FLAG):313 view = create_view(self.pillar, name='+sharing')
382 view = create_view(self.pillar, name='+sharing')314 with StormStatementRecorder() as recorder:
383 with StormStatementRecorder() as recorder:315 view.initialize()
384 view.initialize()316 self.assertThat(recorder, HasQueryCount(LessThan(9)))
385 self.assertThat(recorder, HasQueryCount(LessThan(9)))
386
387 def test_view_write_enabled_without_feature_flag(self):
388 # Test that sharing_write_enabled is not set without the feature flag.
389 with FeatureFixture(ENABLED_FLAG):
390 login_person(self.owner)
391 view = create_initialized_view(self.pillar, name='+sharing')
392 cache = IJSONRequestCache(view.request)
393 self.assertFalse(cache.objects.get('sharing_write_enabled'))
394
395 def test_view_write_enabled_with_feature_flag(self):
396 # Test that sharing_write_enabled is set when required.
397 with FeatureFixture(WRITE_FLAG):
398 view = create_initialized_view(self.pillar, name='+sharing')
399 cache = IJSONRequestCache(view.request)
400 self.assertFalse(cache.objects.get('sharing_write_enabled'))
401 login_person(self.owner)
402 view = create_initialized_view(self.pillar, name='+sharing')
403 cache = IJSONRequestCache(view.request)
404 self.assertTrue(cache.objects.get('sharing_write_enabled'))
405317
406 def test_view_invisible_information_types(self):318 def test_view_invisible_information_types(self):
407 # Test the expected invisible information type data is in the319 # Test the expected invisible information type data is in the
408 # json request cache.320 # json request cache.
409 with FeatureFixture(WRITE_FLAG):321 with person_logged_in(self.pillar.owner):
410 with person_logged_in(self.pillar.owner):322 getUtility(IService, 'sharing').deletePillarGrantee(
411 getUtility(IService, 'sharing').deletePillarGrantee(323 self.pillar, self.pillar.owner, self.pillar.owner)
412 self.pillar, self.pillar.owner, self.pillar.owner)324 view = create_initialized_view(self.pillar, name='+sharing')
413 view = create_initialized_view(self.pillar, name='+sharing')325 cache = IJSONRequestCache(view.request)
414 cache = IJSONRequestCache(view.request)326 self.assertContentEqual(
415 self.assertContentEqual(327 ['Private Security', 'Private'],
416 ['Private Security', 'Private'],328 cache.objects.get('invisible_information_types'))
417 cache.objects.get('invisible_information_types'))
418329
419330
420class TestProductSharingView(PillarSharingViewTestMixin,331class TestProductSharingView(PillarSharingViewTestMixin,
421332
=== modified file 'lib/lp/registry/javascript/sharing/pillarsharingview.js'
--- lib/lp/registry/javascript/sharing/pillarsharingview.js 2012-08-23 00:35:25 +0000
+++ lib/lp/registry/javascript/sharing/pillarsharingview.js 2012-08-28 04:39:25 +0000
@@ -19,10 +19,6 @@
19 value: new Y.lp.client.Launchpad()19 value: new Y.lp.client.Launchpad()
20 },20 },
2121
22 write_enabled: {
23 value: false
24 },
25
26 grantee_picker: {22 grantee_picker: {
27 value: null23 value: null
28 },24 },
@@ -61,12 +57,6 @@
61 this.set(57 this.set(
62 'sharing_permissions_by_value', sharing_permissions_by_value);58 'sharing_permissions_by_value', sharing_permissions_by_value);
6359
64 // No need to do anything else if we are read only.
65 if (LP.cache.sharing_write_enabled !== true) {
66 return;
67 }
68 this.set('write_enabled', true);
69
70 var vocab;60 var vocab;
71 var header;61 var header;
72 var steptitle;62 var steptitle;
@@ -125,13 +115,11 @@
125 sharing_permissions:115 sharing_permissions:
126 this.get('sharing_permissions_by_value'),116 this.get('sharing_permissions_by_value'),
127 information_types: this.get('information_types_by_value'),117 information_types: this.get('information_types_by_value'),
128 write_enabled: this.get('write_enabled')118 write_enabled: true
129 });119 });
130 this.set('grantee_table', grantee_table);120 this.set('grantee_table', grantee_table);
131 grantee_table.render();121 grantee_table.render();
132 if (this.get('write_enabled')) {122 Y.one('#add-grantee-link').removeClass('hidden');
133 Y.one('#add-grantee-link').removeClass('hidden');
134 }
135 this.bug_sharing_policy_widget123 this.bug_sharing_policy_widget
136 = this._render_sharing_policy('bug', 'Bug');124 = this._render_sharing_policy('bug', 'Bug');
137 this.branch_sharing_policy_widget125 this.branch_sharing_policy_widget
@@ -164,8 +152,7 @@
164 }152 }
165 choice_items.push.apply(153 choice_items.push.apply(
166 choice_items, this.getSharingPolicyInformation(artifact_type));154 choice_items, this.getSharingPolicyInformation(artifact_type));
167 var editable = LP.cache.sharing_write_enabled155 var editable = choice_items.length > 1;
168 && choice_items.length > 1;
169 var policy_edit = new Y.ChoiceSource({156 var policy_edit = new Y.ChoiceSource({
170 flashEnabled: false,157 flashEnabled: false,
171 clickable_content: editable,158 clickable_content: editable,
@@ -186,9 +173,6 @@
186 },173 },
187174
188 bindUI: function() {175 bindUI: function() {
189 if (!this.get('write_enabled')) {
190 return;
191 }
192 var self = this;176 var self = this;
193 var share_link = Y.one('#add-grantee-link');177 var share_link = Y.one('#add-grantee-link');
194 share_link.on('click', function(e) {178 share_link.on('click', function(e) {
195179
=== modified file 'lib/lp/registry/javascript/sharing/sharingdetailsview.js'
--- lib/lp/registry/javascript/sharing/sharingdetailsview.js 2012-07-21 03:04:06 +0000
+++ lib/lp/registry/javascript/sharing/sharingdetailsview.js 2012-08-28 04:39:25 +0000
@@ -19,10 +19,6 @@
19 value: new Y.lp.client.Launchpad()19 value: new Y.lp.client.Launchpad()
20 },20 },
2121
22 write_enabled: {
23 value: false
24 },
25
26 sharing_details_table: {22 sharing_details_table: {
27 value: null23 value: null
28 }24 }
@@ -30,29 +26,19 @@
3026
31Y.extend(SharingDetailsView, Y.Widget, {27Y.extend(SharingDetailsView, Y.Widget, {
3228
33 initializer: function(config) {
34 if (LP.cache.sharing_write_enabled !== true) {
35 return;
36 }
37 this.set('write_enabled', true);
38 },
39
40 renderUI: function() {29 renderUI: function() {
41 var ns = Y.lp.registry.sharing.sharingdetails;30 var ns = Y.lp.registry.sharing.sharingdetails;
42 var details_table = new ns.SharingDetailsTable({31 var details_table = new ns.SharingDetailsTable({
43 bugs: LP.cache.bugs,32 bugs: LP.cache.bugs,
44 branches: LP.cache.branches,33 branches: LP.cache.branches,
45 person_name: LP.cache.grantee.displayname,34 person_name: LP.cache.grantee.displayname,
46 write_enabled: this.get('write_enabled')35 write_enabled: true
47 });36 });
48 this.set('sharing_details_table', details_table);37 this.set('sharing_details_table', details_table);
49 details_table.render();38 details_table.render();
50 },39 },
5140
52 bindUI: function() {41 bindUI: function() {
53 if (!this.get('write_enabled')) {
54 return;
55 }
56 var self = this;42 var self = this;
57 var sharing_details_table = this.get('sharing_details_table');43 var sharing_details_table = this.get('sharing_details_table');
58 var ns = Y.lp.registry.sharing.sharingdetails;44 var ns = Y.lp.registry.sharing.sharingdetails;
5945
=== modified file 'lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js'
--- lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js 2012-08-16 00:19:42 +0000
+++ lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js 2012-08-28 04:39:25 +0000
@@ -56,7 +56,6 @@
56 title: 'Branch Policy 1',56 title: 'Branch Policy 1',
57 description: 'Branch Policy 1 description'}57 description: 'Branch Policy 1 description'}
58 ],58 ],
59 sharing_write_enabled: true
60 }59 }
61 };60 };
62 this.mockio = new Y.lp.testing.mockio.MockIo();61 this.mockio = new Y.lp.testing.mockio.MockIo();
@@ -119,16 +118,6 @@
119 Y.Assert.isNotNull(Y.one('.yui3-grantee_picker'));118 Y.Assert.isNotNull(Y.one('.yui3-grantee_picker'));
120 },119 },
121120
122 // Read only mode disables the correct things.
123 test_readonly: function() {
124 window.LP.cache.sharing_write_enabled = false;
125 this.view = this._create_Widget();
126 this.view.render();
127 Y.Assert.isTrue(Y.one('#add-grantee-link').hasClass('hidden'));
128 Y.Assert.isFalse(
129 this.view.get('grantee_table').get('write_enabled'));
130 },
131
132 // Clicking a update grantee grantee link calls121 // Clicking a update grantee grantee link calls
133 // the update_grantee_interaction method with the correct parameters.122 // the update_grantee_interaction method with the correct parameters.
134 test_update_grantee_click: function() {123 test_update_grantee_click: function() {
@@ -547,14 +536,6 @@
547 'Bug Policy 1', value_node.get('text').trim());536 'Bug Policy 1', value_node.get('text').trim());
548 },537 },
549538
550 // If the view is readonly, no edit links are available.
551 test_sharing_policy_render_read_only: function() {
552 window.LP.cache.sharing_write_enabled = false;
553 this.view = this._create_Widget();
554 this.view.render();
555 this._assert_sharing_policies_editable(false);
556 },
557
558 // If there is only one policy choice, no edit links are available.539 // If there is only one policy choice, no edit links are available.
559 test_sharing_policy_render_only_one_choice: function() {540 test_sharing_policy_render_only_one_choice: function() {
560 // Add a model value so the legacy choice is not used.541 // Add a model value so the legacy choice is not used.
561542
=== modified file 'lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js'
--- lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js 2012-07-20 03:15:04 +0000
+++ lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js 2012-08-28 04:39:25 +0000
@@ -37,7 +37,6 @@
37 pillar: {37 pillar: {
38 self_link: '/pillar'38 self_link: '/pillar'
39 },39 },
40 sharing_write_enabled: true
41 }40 }
42 };41 };
43 this.fixture = Y.one('#fixture');42 this.fixture = Y.one('#fixture');
@@ -79,16 +78,6 @@
79 Y.one('#sharing-table-body tr[id=shared-bug-2]'));78 Y.one('#sharing-table-body tr[id=shared-bug-2]'));
80 },79 },
8180
82 // Read only mode disables the correct things.
83 test_readonly: function() {
84 window.LP.cache.sharing_write_enabled = false;
85 this.view = this._create_Widget();
86 this.view.render();
87 Y.Assert.isFalse(
88 this.view.get('sharing_details_table')
89 .get('write_enabled'));
90 },
91
92 // Clicking a bug remove link calls the confirm_grant_removal81 // Clicking a bug remove link calls the confirm_grant_removal
93 // method with the correct parameters.82 // method with the correct parameters.
94 test_remove_bug_grant_click: function() {83 test_remove_bug_grant_click: function() {
9584
=== modified file 'lib/lp/registry/model/teammembership.py'
--- lib/lp/registry/model/teammembership.py 2012-08-14 23:27:07 +0000
+++ lib/lp/registry/model/teammembership.py 2012-08-28 04:39:25 +0000
@@ -65,7 +65,6 @@
65 SQLBase,65 SQLBase,
66 sqlvalues,66 sqlvalues,
67 )67 )
68from lp.services.features import getFeatureFlag
69from lp.services.mail.helpers import (68from lp.services.mail.helpers import (
70 get_contact_email_addresses,69 get_contact_email_addresses,
71 get_email_template,70 get_email_template,
@@ -343,13 +342,11 @@
343 _fillTeamParticipation(self.person, self.team)342 _fillTeamParticipation(self.person, self.team)
344 elif old_status in ACTIVE_STATES:343 elif old_status in ACTIVE_STATES:
345 _cleanTeamParticipation(self.person, self.team)344 _cleanTeamParticipation(self.person, self.team)
346 flag = 'disclosure.unsubscribe_jobs.enabled'345 # A person has left the team so they may no longer have access
347 if bool(getFeatureFlag(flag)):346 # to some artifacts shared with the team. We need to run a job
348 # A person has left the team so they may no longer have access347 # to remove any subscriptions to such artifacts.
349 # to some artifacts shared with the team. We need to run a job348 getUtility(IRemoveArtifactSubscriptionsJobSource).create(
350 # to remove any subscriptions to such artifacts.349 user, grantee=self.person)
351 getUtility(IRemoveArtifactSubscriptionsJobSource).create(
352 user, grantee=self.person)
353 else:350 else:
354 # Changed from an inactive state to another inactive one, so no351 # Changed from an inactive state to another inactive one, so no
355 # need to fill/clean the TeamParticipation table.352 # need to fill/clean the TeamParticipation table.
356353
=== modified file 'lib/lp/registry/services/sharingservice.py'
--- lib/lp/registry/services/sharingservice.py 2012-08-16 06:06:36 +0000
+++ lib/lp/registry/services/sharingservice.py 2012-08-28 04:39:25 +0000
@@ -59,7 +59,6 @@
59from lp.registry.model.teammembership import TeamParticipation59from lp.registry.model.teammembership import TeamParticipation
60from lp.services.database.lpstorm import IStore60from lp.services.database.lpstorm import IStore
61from lp.services.database.stormexpr import ColumnSelect61from lp.services.database.stormexpr import ColumnSelect
62from lp.services.features import getFeatureFlag
63from lp.services.searchbuilder import any62from lp.services.searchbuilder import any
64from lp.services.webapp.authorization import (63from lp.services.webapp.authorization import (
65 available_with_permission,64 available_with_permission,
@@ -81,12 +80,6 @@
81 """See `IService`."""80 """See `IService`."""
82 return 'sharing'81 return 'sharing'
8382
84 @property
85 def write_enabled(self):
86 return (
87 bool(getFeatureFlag(
88 'disclosure.enhanced_sharing.writable')))
89
90 def checkPillarAccess(self, pillar, information_type, person):83 def checkPillarAccess(self, pillar, information_type, person):
91 """See `ISharingService`."""84 """See `ISharingService`."""
92 policy = getUtility(IAccessPolicySource).find(85 policy = getUtility(IAccessPolicySource).find(
@@ -350,15 +343,12 @@
350 result = []343 result = []
351 request = get_current_web_service_request()344 request = get_current_web_service_request()
352 browser_request = IWebBrowserOriginatingRequest(request)345 browser_request = IWebBrowserOriginatingRequest(request)
353 details_enabled = bool((getFeatureFlag(
354 'disclosure.enhanced_sharing_details.enabled')))
355 # We need to precache icon and validity information for the batch.346 # We need to precache icon and validity information for the batch.
356 grantee_ids = [grantee[0].id for grantee in grant_permissions]347 grantee_ids = [grantee[0].id for grantee in grant_permissions]
357 list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(348 list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(
358 grantee_ids, need_icon=True, need_validity=True))349 grantee_ids, need_icon=True, need_validity=True))
359 for (grantee, permissions, shared_artifact_types) in grant_permissions:350 for (grantee, permissions, shared_artifact_types) in grant_permissions:
360 some_things_shared = (351 some_things_shared = len(shared_artifact_types) > 0
361 details_enabled and len(shared_artifact_types) > 0)
362 grantee_permissions = {}352 grantee_permissions = {}
363 for (policy, permission) in permissions.iteritems():353 for (policy, permission) in permissions.iteritems():
364 grantee_permissions[policy.type.name] = permission.name354 grantee_permissions[policy.type.name] = permission.name
@@ -386,9 +376,6 @@
386 # We do not support adding grantees to project groups.376 # We do not support adding grantees to project groups.
387 assert not IProjectGroup.providedBy(pillar)377 assert not IProjectGroup.providedBy(pillar)
388378
389 if not self.write_enabled:
390 raise Unauthorized("This feature is not yet enabled.")
391
392 # Separate out the info types according to permission.379 # Separate out the info types according to permission.
393 information_types = permissions.keys()380 information_types = permissions.keys()
394 info_types_for_all = [381 info_types_for_all = [
@@ -463,9 +450,6 @@
463 information_types=None):450 information_types=None):
464 """See `ISharingService`."""451 """See `ISharingService`."""
465452
466 if not self.write_enabled:
467 raise Unauthorized("This feature is not yet enabled.")
468
469 policy_source = getUtility(IAccessPolicySource)453 policy_source = getUtility(IAccessPolicySource)
470 if information_types is None:454 if information_types is None:
471 # We delete all policy grants for the pillar.455 # We delete all policy grants for the pillar.
@@ -491,9 +475,8 @@
491 to_delete = list(ap_grant_flat.findArtifactsByGrantee(475 to_delete = list(ap_grant_flat.findArtifactsByGrantee(
492 grantee, pillar_policies))476 grantee, pillar_policies))
493 if len(to_delete) > 0:477 if len(to_delete) > 0:
494 accessartifact_grant_source = getUtility(478 getUtility(IAccessArtifactGrantSource).revokeByArtifact(
495 IAccessArtifactGrantSource)479 to_delete, [grantee])
496 accessartifact_grant_source.revokeByArtifact(to_delete, [grantee])
497480
498 # Create a job to remove subscriptions for artifacts the grantee can no481 # Create a job to remove subscriptions for artifacts the grantee can no
499 # longer see.482 # longer see.
@@ -512,9 +495,6 @@
512 bugs=None):495 bugs=None):
513 """See `ISharingService`."""496 """See `ISharingService`."""
514497
515 if not self.write_enabled:
516 raise Unauthorized("This feature is not yet enabled.")
517
518 artifacts = []498 artifacts = []
519 if branches:499 if branches:
520 artifacts.extend(branches)500 artifacts.extend(branches)
@@ -524,8 +504,7 @@
524 accessartifact_source = getUtility(IAccessArtifactSource)504 accessartifact_source = getUtility(IAccessArtifactSource)
525 artifacts_to_delete = accessartifact_source.find(artifacts)505 artifacts_to_delete = accessartifact_source.find(artifacts)
526 # Revoke access to bugs/branches for the specified grantee.506 # Revoke access to bugs/branches for the specified grantee.
527 accessartifact_grant_source = getUtility(IAccessArtifactGrantSource)507 getUtility(IAccessArtifactGrantSource).revokeByArtifact(
528 accessartifact_grant_source.revokeByArtifact(
529 artifacts_to_delete, [grantee])508 artifacts_to_delete, [grantee])
530509
531 # Create a job to remove subscriptions for artifacts the grantee can no510 # Create a job to remove subscriptions for artifacts the grantee can no
@@ -537,9 +516,6 @@
537 ignore_permissions=False):516 ignore_permissions=False):
538 """See `ISharingService`."""517 """See `ISharingService`."""
539518
540 if not ignore_permissions and not self.write_enabled:
541 raise Unauthorized("This feature is not yet enabled.")
542
543 artifacts = []519 artifacts = []
544 if branches:520 if branches:
545 artifacts.extend(branches)521 artifacts.extend(branches)
546522
=== modified file 'lib/lp/registry/services/tests/test_sharingservice.py'
--- lib/lp/registry/services/tests/test_sharingservice.py 2012-08-16 06:06:36 +0000
+++ lib/lp/registry/services/tests/test_sharingservice.py 2012-08-28 04:39:25 +0000
@@ -56,13 +56,6 @@
56from lp.testing.pages import LaunchpadWebServiceCaller56from lp.testing.pages import LaunchpadWebServiceCaller
5757
5858
59WRITE_FLAG = {
60 'disclosure.enhanced_sharing.writable': 'true',
61 'disclosure.enhanced_sharing_details.enabled': 'true',
62 'jobs.celery.enabled_classes': 'RemoveArtifactSubscriptionsJob'}
63DETAILS_FLAG = {'disclosure.enhanced_sharing_details.enabled': 'true'}
64
65
66class TestSharingService(TestCaseWithFactory):59class TestSharingService(TestCaseWithFactory):
67 """Tests for the SharingService."""60 """Tests for the SharingService."""
6861
@@ -71,6 +64,9 @@
71 def setUp(self):64 def setUp(self):
72 super(TestSharingService, self).setUp()65 super(TestSharingService, self).setUp()
73 self.service = getUtility(IService, 'sharing')66 self.service = getUtility(IService, 'sharing')
67 self.useFixture(FeatureFixture({
68 'jobs.celery.enabled_classes': 'RemoveArtifactSubscriptionsJob',
69 }))
7470
75 def _makeGranteeData(self, grantee, policy_permissions,71 def _makeGranteeData(self, grantee, policy_permissions,
76 shared_artifact_types):72 shared_artifact_types):
@@ -234,12 +230,11 @@
234 [policy1, policy2] = getUtility(IAccessPolicySource).findByPillar(230 [policy1, policy2] = getUtility(IAccessPolicySource).findByPillar(
235 [product])231 [product])
236 grantee = self.factory.makePerson()232 grantee = self.factory.makePerson()
237 with FeatureFixture(DETAILS_FLAG):233 grantees = self.service.jsonGranteeData(
238 grantees = self.service.jsonGranteeData(234 [(grantee, {
239 [(grantee, {235 policy1: SharingPermission.ALL,
240 policy1: SharingPermission.ALL,236 policy2: SharingPermission.SOME},
241 policy2: SharingPermission.SOME},237 [policy1.type, policy2.type])])
242 [policy1.type, policy2.type])])
243 expected_data = self._makeGranteeData(238 expected_data = self._makeGranteeData(
244 grantee,239 grantee,
245 [(policy1.type, SharingPermission.ALL),240 [(policy1.type, SharingPermission.ALL),
@@ -247,24 +242,6 @@
247 [policy1.type, policy2.type])242 [policy1.type, policy2.type])
248 self.assertContentEqual([expected_data], grantees)243 self.assertContentEqual([expected_data], grantees)
249244
250 def test_jsonGranteeData_with_Some_without_flag(self):
251 # jsonGranteeData returns the expected data for a grantee with
252 # permissions which include SOME and the feature flag not set.
253 product = self.factory.makeProduct()
254 [policy1, policy2] = getUtility(IAccessPolicySource).findByPillar(
255 [product])
256 grantee = self.factory.makePerson()
257 grantees = self.service.jsonGranteeData(
258 [(grantee, {
259 policy1: SharingPermission.ALL,
260 policy2: SharingPermission.SOME}, [policy2.type])])
261 expected_data = self._makeGranteeData(
262 grantee,
263 [(policy1.type, SharingPermission.ALL),
264 (policy2.type, SharingPermission.SOME)], [policy2.type])
265 expected_data['shared_items_exist'] = False
266 self.assertContentEqual([expected_data], grantees)
267
268 def test_jsonGranteeData_without_Some(self):245 def test_jsonGranteeData_without_Some(self):
269 # jsonGranteeData returns the expected data for a grantee with only ALL246 # jsonGranteeData returns the expected data for a grantee with only ALL
270 # permissions.247 # permissions.
@@ -272,10 +249,8 @@
272 [policy1, policy2] = getUtility(IAccessPolicySource).findByPillar(249 [policy1, policy2] = getUtility(IAccessPolicySource).findByPillar(
273 [product])250 [product])
274 grantee = self.factory.makePerson()251 grantee = self.factory.makePerson()
275 with FeatureFixture(DETAILS_FLAG):252 grantees = self.service.jsonGranteeData(
276 grantees = self.service.jsonGranteeData(253 [(grantee, {policy1: SharingPermission.ALL}, [])])
277 [(grantee, {
278 policy1: SharingPermission.ALL}, [])])
279 expected_data = self._makeGranteeData(254 expected_data = self._makeGranteeData(
280 grantee,255 grantee,
281 [(policy1.type, SharingPermission.ALL)], [])256 [(policy1.type, SharingPermission.ALL)], [])
@@ -290,10 +265,8 @@
290 icon = self.factory.makeLibraryFileAlias(265 icon = self.factory.makeLibraryFileAlias(
291 filename='smurf.png', content_type='image/png')266 filename='smurf.png', content_type='image/png')
292 grantee = self.factory.makeTeam(icon=icon)267 grantee = self.factory.makeTeam(icon=icon)
293 with FeatureFixture(DETAILS_FLAG):268 grantees = self.service.jsonGranteeData(
294 grantees = self.service.jsonGranteeData(269 [(grantee, {policy1: SharingPermission.ALL}, [])])
295 [(grantee, {
296 policy1: SharingPermission.ALL}, [])])
297 expected_data = self._makeGranteeData(270 expected_data = self._makeGranteeData(
298 grantee,271 grantee,
299 [(policy1.type, SharingPermission.ALL)], [])272 [(policy1.type, SharingPermission.ALL)], [])
@@ -312,8 +285,7 @@
312 self.factory.makeAccessPolicyArtifact(285 self.factory.makeAccessPolicyArtifact(
313 artifact=artifact_grant.abstract_artifact, policy=access_policy)286 artifact=artifact_grant.abstract_artifact, policy=access_policy)
314287
315 with FeatureFixture(DETAILS_FLAG):288 grantees = self.service.getPillarGranteeData(pillar)
316 grantees = self.service.getPillarGranteeData(pillar)
317 expected_grantees = [289 expected_grantees = [
318 self._makeGranteeData(290 self._makeGranteeData(
319 grantee,291 grantee,
@@ -540,9 +512,8 @@
540 InformationType.PRIVATESECURITY: SharingPermission.ALL,512 InformationType.PRIVATESECURITY: SharingPermission.ALL,
541 InformationType.USERDATA: SharingPermission.SOME,513 InformationType.USERDATA: SharingPermission.SOME,
542 InformationType.PROPRIETARY: SharingPermission.NOTHING}514 InformationType.PROPRIETARY: SharingPermission.NOTHING}
543 with FeatureFixture(WRITE_FLAG):515 grantee_data = self.service.sharePillarInformation(
544 grantee_data = self.service.sharePillarInformation(516 pillar, grantee, grantor, permissions)
545 pillar, grantee, grantor, permissions)
546 policies = getUtility(IAccessPolicySource).findByPillar([pillar])517 policies = getUtility(IAccessPolicySource).findByPillar([pillar])
547 policy_grant_source = getUtility(IAccessPolicyGrantSource)518 policy_grant_source = getUtility(IAccessPolicyGrantSource)
548 grants = policy_grant_source.findByPolicy(policies)519 grants = policy_grant_source.findByPolicy(policies)
@@ -619,9 +590,8 @@
619590
620 permissions = {591 permissions = {
621 grant.policy.type: SharingPermission.SOME}592 grant.policy.type: SharingPermission.SOME}
622 with FeatureFixture(WRITE_FLAG):593 grantee_data = self.service.sharePillarInformation(
623 grantee_data = self.service.sharePillarInformation(594 pillar, grantee, self.factory.makePerson(), permissions)
624 pillar, grantee, self.factory.makePerson(), permissions)
625 self.assertIsNone(grantee_data['grantee_entry'])595 self.assertIsNone(grantee_data['grantee_entry'])
626596
627 def test_granteePillarInformationInvisibleInformationTypes(self):597 def test_granteePillarInformationInvisibleInformationTypes(self):
@@ -629,13 +599,12 @@
629 # information types.599 # information types.
630 product = self.factory.makeProduct()600 product = self.factory.makeProduct()
631 grantee = self.factory.makePerson()601 grantee = self.factory.makePerson()
632 with FeatureFixture(WRITE_FLAG):602 with admin_logged_in():
633 with admin_logged_in():603 self.service.deletePillarGrantee(
634 self.service.deletePillarGrantee(604 product, product.owner, product.owner)
635 product, product.owner, product.owner)605 result_data = self.service.sharePillarInformation(
636 result_data = self.service.sharePillarInformation(606 product, grantee, product.owner,
637 product, grantee, product.owner,607 {InformationType.USERDATA: SharingPermission.ALL})
638 {InformationType.USERDATA: SharingPermission.ALL})
639 # The owner is granted access on product creation. So we need to allow608 # The owner is granted access on product creation. So we need to allow
640 # for that in the check below.609 # for that in the check below.
641 self.assertContentEqual(610 self.assertContentEqual(
@@ -645,42 +614,27 @@
645 def _assert_sharePillarInformationUnauthorized(self, pillar):614 def _assert_sharePillarInformationUnauthorized(self, pillar):
646 # sharePillarInformation raises an Unauthorized exception if the user615 # sharePillarInformation raises an Unauthorized exception if the user
647 # is not permitted to do so.616 # is not permitted to do so.
648 with FeatureFixture(WRITE_FLAG):617 grantee = self.factory.makePerson()
649 grantee = self.factory.makePerson()618 user = self.factory.makePerson()
650 user = self.factory.makePerson()619 self.assertRaises(
651 self.assertRaises(620 Unauthorized, self.service.sharePillarInformation,
652 Unauthorized, self.service.sharePillarInformation,621 pillar, grantee, user,
653 pillar, grantee, user,622 {InformationType.USERDATA: SharingPermission.ALL})
654 {InformationType.USERDATA: SharingPermission.ALL})
655623
656 def test_sharePillarInformationAnonymous(self):624 def test_sharePillarInformationAnonymous(self):
657 # Anonymous users are not allowed.625 # Anonymous users are not allowed.
658 with FeatureFixture(WRITE_FLAG):626 product = self.factory.makeProduct()
659 product = self.factory.makeProduct()627 login(ANONYMOUS)
660 login(ANONYMOUS)628 self._assert_sharePillarInformationUnauthorized(product)
661 self._assert_sharePillarInformationUnauthorized(product)
662629
663 def test_sharePillarInformationAnyone(self):630 def test_sharePillarInformationAnyone(self):
664 # Unauthorized users are not allowed.631 # Unauthorized users are not allowed.
665 with FeatureFixture(WRITE_FLAG):632 product = self.factory.makeProduct()
666 product = self.factory.makeProduct()633 login_person(self.factory.makePerson())
667 login_person(self.factory.makePerson())634 self._assert_sharePillarInformationUnauthorized(product)
668 self._assert_sharePillarInformationUnauthorized(product)635
669636 def _assert_deletePillarGrantee(self, pillar, types_to_delete=None,
670 def test_sharePillarInformation_without_flag(self):637 pillar_type=None):
671 # The feature flag needs to be enabled.
672 owner = self.factory.makePerson()
673 product = self.factory.makeProduct(owner=owner)
674 login_person(owner)
675 grantee = self.factory.makePerson()
676 user = self.factory.makePerson()
677 self.assertRaises(
678 Unauthorized, self.service.sharePillarInformation,
679 product, grantee, user,
680 {InformationType.USERDATA: SharingPermission.ALL})
681
682 def _assert_deletePillarGrantee(
683 self, pillar, types_to_delete=None, pillar_type=None):
684 access_policies = getUtility(IAccessPolicySource).findByPillar(638 access_policies = getUtility(IAccessPolicySource).findByPillar(
685 (pillar,))639 (pillar,))
686 information_types = [ap.type for ap in access_policies]640 information_types = [ap.type for ap in access_policies]
@@ -701,9 +655,8 @@
701 self.factory.makeAccessPolicyArtifact(655 self.factory.makeAccessPolicyArtifact(
702 artifact=artifact, policy=access_policy)656 artifact=artifact, policy=access_policy)
703 # Delete data for a specific information type.657 # Delete data for a specific information type.
704 with FeatureFixture(WRITE_FLAG):658 self.service.deletePillarGrantee(
705 self.service.deletePillarGrantee(659 pillar, grantee, pillar.owner, types_to_delete)
706 pillar, grantee, pillar.owner, types_to_delete)
707 # Assemble the expected data for the remaining access grants for660 # Assemble the expected data for the remaining access grants for
708 # grantee.661 # grantee.
709 expected_data = []662 expected_data = []
@@ -768,43 +721,30 @@
768 def test_deletePillarGranteeInvisibleInformationTypes(self):721 def test_deletePillarGranteeInvisibleInformationTypes(self):
769 # Deleting a pillar grantee returns the resulting invisible info types.722 # Deleting a pillar grantee returns the resulting invisible info types.
770 product = self.factory.makeProduct()723 product = self.factory.makeProduct()
771 with FeatureFixture(WRITE_FLAG):724 with admin_logged_in():
772 with admin_logged_in():725 invisible_information_types = self.service.deletePillarGrantee(
773 invisible_information_types = self.service.deletePillarGrantee(726 product, product.owner, product.owner)
774 product, product.owner, product.owner)
775 self.assertContentEqual(727 self.assertContentEqual(
776 ['Private', 'Private Security'], invisible_information_types)728 ['Private', 'Private Security'], invisible_information_types)
777729
778 def _assert_deletePillarGranteeUnauthorized(self, pillar):730 def _assert_deletePillarGranteeUnauthorized(self, pillar):
779 # deletePillarGrantee raises an Unauthorized exception if the user731 # deletePillarGrantee raises an Unauthorized exception if the user
780 # is not permitted to do so.732 # is not permitted to do so.
781 with FeatureFixture(WRITE_FLAG):733 self.assertRaises(
782 self.assertRaises(734 Unauthorized, self.service.deletePillarGrantee,
783 Unauthorized, self.service.deletePillarGrantee,735 pillar, pillar.owner, pillar.owner, [InformationType.USERDATA])
784 pillar, pillar.owner, pillar.owner, [InformationType.USERDATA])
785736
786 def test_deletePillarGranteeAnonymous(self):737 def test_deletePillarGranteeAnonymous(self):
787 # Anonymous users are not allowed.738 # Anonymous users are not allowed.
788 with FeatureFixture(WRITE_FLAG):739 product = self.factory.makeProduct()
789 product = self.factory.makeProduct()740 login(ANONYMOUS)
790 login(ANONYMOUS)741 self._assert_deletePillarGranteeUnauthorized(product)
791 self._assert_deletePillarGranteeUnauthorized(product)
792742
793 def test_deletePillarGranteeAnyone(self):743 def test_deletePillarGranteeAnyone(self):
794 # Unauthorized users are not allowed.744 # Unauthorized users are not allowed.
795 with FeatureFixture(WRITE_FLAG):745 product = self.factory.makeProduct()
796 product = self.factory.makeProduct()746 login_person(self.factory.makePerson())
797 login_person(self.factory.makePerson())747 self._assert_deletePillarGranteeUnauthorized(product)
798 self._assert_deletePillarGranteeUnauthorized(product)
799
800 def test_deletePillarGrantee_without_flag(self):
801 # The feature flag needs to be enabled.
802 owner = self.factory.makePerson()
803 product = self.factory.makeProduct(owner=owner)
804 login_person(owner)
805 self.assertRaises(
806 Unauthorized, self.service.deletePillarGrantee,
807 product, product.owner, product.owner, [InformationType.USERDATA])
808748
809 def _assert_deleteGranteeRemoveSubscriptions(self,749 def _assert_deleteGranteeRemoveSubscriptions(self,
810 types_to_delete=None):750 types_to_delete=None):
@@ -839,9 +779,8 @@
839 bug.subscribe(person, product.owner)779 bug.subscribe(person, product.owner)
840780
841 # Delete data for specified information types or all.781 # Delete data for specified information types or all.
842 with FeatureFixture(WRITE_FLAG):782 self.service.deletePillarGrantee(
843 self.service.deletePillarGrantee(783 product, grantee, product.owner, types_to_delete)
844 product, grantee, product.owner, types_to_delete)
845 with block_on_job(self):784 with block_on_job(self):
846 transaction.commit()785 transaction.commit()
847786
@@ -907,9 +846,8 @@
907 apgfs = getUtility(IAccessPolicyGrantFlatSource)846 apgfs = getUtility(IAccessPolicyGrantFlatSource)
908 self.assertEqual(1, grants.count())847 self.assertEqual(1, grants.count())
909848
910 with FeatureFixture(WRITE_FLAG):849 self.service.revokeAccessGrants(
911 self.service.revokeAccessGrants(850 pillar, grantee, pillar.owner, bugs=bugs, branches=branches)
912 pillar, grantee, pillar.owner, bugs=bugs, branches=branches)
913 with block_on_job(self):851 with block_on_job(self):
914 transaction.commit()852 transaction.commit()
915853
@@ -993,10 +931,8 @@
993 for bug in bugs or []:931 for bug in bugs or []:
994 self.assertIn(person, bug.getDirectSubscribers())932 self.assertIn(person, bug.getDirectSubscribers())
995933
996 with FeatureFixture(WRITE_FLAG):934 self.service.revokeAccessGrants(
997 self.service.revokeAccessGrants(935 pillar, team_grantee, pillar.owner, bugs=bugs, branches=branches)
998 pillar, team_grantee, pillar.owner,
999 bugs=bugs, branches=branches)
1000 with block_on_job(self):936 with block_on_job(self):
1001 transaction.commit()937 transaction.commit()
1002938
@@ -1042,43 +978,27 @@
1042 bug = self.factory.makeBug(978 bug = self.factory.makeBug(
1043 target=product, information_type=InformationType.USERDATA)979 target=product, information_type=InformationType.USERDATA)
1044 grantee = self.factory.makePerson()980 grantee = self.factory.makePerson()
1045 with FeatureFixture(WRITE_FLAG):981 self.assertRaises(
1046 self.assertRaises(982 Unauthorized, self.service.revokeAccessGrants,
1047 Unauthorized, self.service.revokeAccessGrants,983 product, grantee, product.owner, bugs=[bug])
1048 product, grantee, product.owner, bugs=[bug])
1049984
1050 def test_revokeAccessGrantsAnonymous(self):985 def test_revokeAccessGrantsAnonymous(self):
1051 # Anonymous users are not allowed.986 # Anonymous users are not allowed.
1052 with FeatureFixture(WRITE_FLAG):987 login(ANONYMOUS)
1053 login(ANONYMOUS)988 self._assert_revokeAccessGrantsUnauthorized()
1054 self._assert_revokeAccessGrantsUnauthorized()
1055989
1056 def test_revokeAccessGrantsAnyone(self):990 def test_revokeAccessGrantsAnyone(self):
1057 # Unauthorized users are not allowed.991 # Unauthorized users are not allowed.
1058 with FeatureFixture(WRITE_FLAG):992 login_person(self.factory.makePerson())
1059 login_person(self.factory.makePerson())993 self._assert_revokeAccessGrantsUnauthorized()
1060 self._assert_revokeAccessGrantsUnauthorized()
1061
1062 def test_revokeAccessGrants_without_flag(self):
1063 # The feature flag needs to be enabled.
1064 owner = self.factory.makePerson()
1065 product = self.factory.makeProduct(owner=owner)
1066 bug = self.factory.makeBug(
1067 target=product, information_type=InformationType.USERDATA)
1068 grantee = self.factory.makePerson()
1069 login_person(owner)
1070 self.assertRaises(
1071 Unauthorized, self.service.revokeAccessGrants,
1072 product, grantee, product.owner, bugs=[bug])
1073994
1074 def _assert_ensureAccessGrants(self, user, bugs, branches,995 def _assert_ensureAccessGrants(self, user, bugs, branches,
1075 grantee=None):996 grantee=None):
1076 # Creating access grants works as expected.997 # Creating access grants works as expected.
1077 if not grantee:998 if not grantee:
1078 grantee = self.factory.makePerson()999 grantee = self.factory.makePerson()
1079 with FeatureFixture(WRITE_FLAG):1000 self.service.ensureAccessGrants(
1080 self.service.ensureAccessGrants(1001 [grantee], user, bugs=bugs, branches=branches)
1081 [grantee], user, bugs=bugs, branches=branches)
10821002
1083 # Check that grantee has expected access grants.1003 # Check that grantee has expected access grants.
1084 shared_bugs = []1004 shared_bugs = []
@@ -1133,8 +1053,7 @@
1133 information_type=InformationType.USERDATA)1053 information_type=InformationType.USERDATA)
1134 # Create an existing access grant.1054 # Create an existing access grant.
1135 grantee = self.factory.makePerson()1055 grantee = self.factory.makePerson()
1136 with FeatureFixture(WRITE_FLAG):1056 self.service.ensureAccessGrants([grantee], owner, bugs=[bug])
1137 self.service.ensureAccessGrants([grantee], owner, bugs=[bug])
1138 # Test with a new bug as well as the one for which access is already1057 # Test with a new bug as well as the one for which access is already
1139 # granted.1058 # granted.
1140 self._assert_ensureAccessGrants(owner, [bug, bug2], None, grantee)1059 self._assert_ensureAccessGrants(owner, [bug, bug2], None, grantee)
@@ -1146,35 +1065,20 @@
1146 bug = self.factory.makeBug(1065 bug = self.factory.makeBug(
1147 target=product, information_type=InformationType.USERDATA)1066 target=product, information_type=InformationType.USERDATA)
1148 grantee = self.factory.makePerson()1067 grantee = self.factory.makePerson()
1149 with FeatureFixture(WRITE_FLAG):1068 self.assertRaises(
1150 self.assertRaises(1069 Unauthorized, self.service.ensureAccessGrants, [grantee], user,
1151 Unauthorized, self.service.ensureAccessGrants,1070 bugs=[bug])
1152 [grantee], user, bugs=[bug])
11531071
1154 def test_ensureAccessGrantsAnonymous(self):1072 def test_ensureAccessGrantsAnonymous(self):
1155 # Anonymous users are not allowed.1073 # Anonymous users are not allowed.
1156 with FeatureFixture(WRITE_FLAG):1074 login(ANONYMOUS)
1157 login(ANONYMOUS)1075 self._assert_ensureAccessGrantsUnauthorized(ANONYMOUS)
1158 self._assert_ensureAccessGrantsUnauthorized(ANONYMOUS)
11591076
1160 def test_ensureAccessGrantsAnyone(self):1077 def test_ensureAccessGrantsAnyone(self):
1161 # Unauthorized users are not allowed.1078 # Unauthorized users are not allowed.
1162 with FeatureFixture(WRITE_FLAG):1079 anyone = self.factory.makePerson()
1163 anyone = self.factory.makePerson()1080 login_person(anyone)
1164 login_person(anyone)1081 self._assert_ensureAccessGrantsUnauthorized(anyone)
1165 self._assert_ensureAccessGrantsUnauthorized(anyone)
1166
1167 def test_ensureAccessGrants_without_flag(self):
1168 # The feature flag needs to be enabled.
1169 owner = self.factory.makePerson()
1170 product = self.factory.makeProduct(owner=owner)
1171 bug = self.factory.makeBug(
1172 target=product, information_type=InformationType.USERDATA)
1173 grantee = self.factory.makePerson()
1174 login_person(owner)
1175 self.assertRaises(
1176 Unauthorized, self.service.ensureAccessGrants,
1177 [grantee], product.owner, bugs=[bug])
11781082
1179 def test_getSharedArtifacts(self):1083 def test_getSharedArtifacts(self):
1180 # Test the getSharedArtifacts method.1084 # Test the getSharedArtifacts method.
@@ -1385,14 +1289,13 @@
1385 right_person = self.factory.makePerson()1289 right_person = self.factory.makePerson()
1386 right_team = self.factory.makeTeam(members=[right_person])1290 right_team = self.factory.makeTeam(members=[right_person])
1387 wrong_person = self.factory.makePerson()1291 wrong_person = self.factory.makePerson()
1388 with FeatureFixture(WRITE_FLAG):1292 with admin_logged_in():
1389 with admin_logged_in():1293 self.service.sharePillarInformation(
1390 self.service.sharePillarInformation(1294 product, right_team, product.owner,
1391 product, right_team, product.owner,1295 {InformationType.USERDATA: SharingPermission.ALL})
1392 {InformationType.USERDATA: SharingPermission.ALL})1296 self.service.sharePillarInformation(
1393 self.service.sharePillarInformation(1297 product, wrong_person, product.owner,
1394 product, wrong_person, product.owner,1298 {InformationType.PRIVATESECURITY: SharingPermission.ALL})
1395 {InformationType.PRIVATESECURITY: SharingPermission.ALL})
1396 self.assertEqual(1299 self.assertEqual(
1397 False,1300 False,
1398 self.service.checkPillarAccess(1301 self.service.checkPillarAccess(
@@ -1415,11 +1318,10 @@
1415 # an information type.1318 # an information type.
1416 product = self.factory.makeProduct()1319 product = self.factory.makeProduct()
1417 grantee = self.factory.makePerson()1320 grantee = self.factory.makePerson()
1418 with FeatureFixture(WRITE_FLAG):1321 with admin_logged_in():
1419 with admin_logged_in():1322 self.service.sharePillarInformation(
1420 self.service.sharePillarInformation(1323 product, grantee, product.owner,
1421 product, grantee, product.owner,1324 {InformationType.USERDATA: SharingPermission.ALL})
1422 {InformationType.USERDATA: SharingPermission.ALL})
1423 # The owner is granted access on product creation. So we need to allow1325 # The owner is granted access on product creation. So we need to allow
1424 # for that in the check below.1326 # for that in the check below.
1425 self.assertContentEqual(1327 self.assertContentEqual(
@@ -1431,10 +1333,9 @@
1431 # checkPillarAccess checks whether the user has full access to1333 # checkPillarAccess checks whether the user has full access to
1432 # an information type.1334 # an information type.
1433 product = self.factory.makeProduct()1335 product = self.factory.makeProduct()
1434 with FeatureFixture(WRITE_FLAG):1336 with admin_logged_in():
1435 with admin_logged_in():1337 self.service.deletePillarGrantee(
1436 self.service.deletePillarGrantee(1338 product, product.owner, product.owner)
1437 product, product.owner, product.owner)
1438 self.assertContentEqual(1339 self.assertContentEqual(
1439 [(InformationType.PRIVATESECURITY, 0),1340 [(InformationType.PRIVATESECURITY, 0),
1440 (InformationType.USERDATA, 0)],1341 (InformationType.USERDATA, 0)],
@@ -1499,14 +1400,13 @@
14991400
1500 def _sharePillarInformation(self):1401 def _sharePillarInformation(self):
1501 pillar_uri = canonical_url(self.pillar, force_local_path=True)1402 pillar_uri = canonical_url(self.pillar, force_local_path=True)
1502 with FeatureFixture(WRITE_FLAG):1403 return self._named_post(
1503 return self._named_post(1404 'sharePillarInformation', pillar=pillar_uri,
1504 'sharePillarInformation', pillar=pillar_uri,1405 grantee=self.grantee_uri,
1505 grantee=self.grantee_uri,1406 user=self.grantor_uri,
1506 user=self.grantor_uri,1407 permissions={
1507 permissions={1408 InformationType.USERDATA.title:
1508 InformationType.USERDATA.title:1409 SharingPermission.ALL.title})
1509 SharingPermission.ALL.title})
15101410
15111411
1512class TestLaunchpadlib(ApiTestMixin, TestCaseWithFactory):1412class TestLaunchpadlib(ApiTestMixin, TestCaseWithFactory):
@@ -1518,9 +1418,6 @@
1518 super(TestLaunchpadlib, self).setUp()1418 super(TestLaunchpadlib, self).setUp()
1519 self.launchpad = self.factory.makeLaunchpadService(person=self.owner)1419 self.launchpad = self.factory.makeLaunchpadService(person=self.owner)
1520 self.service = self.launchpad.load('+services/sharing')1420 self.service = self.launchpad.load('+services/sharing')
1521 flag = FeatureFixture(WRITE_FLAG)
1522 flag.setUp()
1523 self.addCleanup(flag.cleanUp)
1524 transaction.commit()1421 transaction.commit()
1525 self._sharePillarInformation()1422 self._sharePillarInformation()
15261423
15271424
=== modified file 'lib/lp/registry/tests/test_teammembership.py'
--- lib/lp/registry/tests/test_teammembership.py 2012-08-14 23:27:07 +0000
+++ lib/lp/registry/tests/test_teammembership.py 2012-08-28 04:39:25 +0000
@@ -504,7 +504,7 @@
504 The number of db queries should be constant not O(depth).504 The number of db queries should be constant not O(depth).
505 """505 """
506 self.assertStatementCount(506 self.assertStatementCount(
507 7,507 9,
508 self.team5.setMembershipData, self.no_priv,508 self.team5.setMembershipData, self.no_priv,
509 TeamMembershipStatus.DEACTIVATED, self.team5.teamowner)509 TeamMembershipStatus.DEACTIVATED, self.team5.teamowner)
510510
@@ -998,7 +998,6 @@
998998
999 def setUp(self):999 def setUp(self):
1000 self.useFixture(FeatureFixture({1000 self.useFixture(FeatureFixture({
1001 'disclosure.unsubscribe_jobs.enabled': 'true',
1002 'jobs.celery.enabled_classes': 'RemoveArtifactSubscriptionsJob',1001 'jobs.celery.enabled_classes': 'RemoveArtifactSubscriptionsJob',
1003 }))1002 }))
1004 super(TestTeamMembershipJobs, self).setUp()1003 super(TestTeamMembershipJobs, self).setUp()
10051004
=== modified file 'lib/lp/services/features/flags.py'
--- lib/lp/services/features/flags.py 2012-08-14 18:51:43 +0000
+++ lib/lp/services/features/flags.py 2012-08-28 04:39:25 +0000
@@ -197,12 +197,6 @@
197 '',197 '',
198 '',198 '',
199 ''),199 ''),
200 ('disclosure.add-team-person-picker.enabled',
201 'boolean',
202 'Allows users to add a new team directly from the person picker.',
203 '',
204 '',
205 ''),
206 ('bugs.autoconfirm.enabled_distribution_names',200 ('bugs.autoconfirm.enabled_distribution_names',
207 'space delimited',201 'space delimited',
208 ('Enables auto-confirming bugtasks for distributions (and their '202 ('Enables auto-confirming bugtasks for distributions (and their '
@@ -233,34 +227,6 @@
233 '',227 '',
234 '',228 '',
235 ''),229 ''),
236 ('disclosure.enhanced_sharing.enabled',
237 'boolean',
238 ('If true, will allow the use of the new sharing view and apis used '
239 'for the new disclosure data model to view but not write data.'),
240 '',
241 'Sharing overview',
242 ''),
243 ('disclosure.enhanced_sharing_details.enabled',
244 'boolean',
245 ('If true, enables the details page for viewing the `Some` things that'
246 'shared with a user or team.'),
247 '',
248 '',
249 ''),
250 ('disclosure.enhanced_sharing.writable',
251 'boolean',
252 ('If true, will allow the use of the new sharing view and apis used '
253 'to edit the new disclosure data model.'),
254 '',
255 'Sharing management',
256 ''),
257 ('disclosure.unsubscribe_jobs.enabled',
258 'boolean',
259 ('If true, the jobs to unsubscribe users who lose access to bugs'
260 'and branches are run.'),
261 '',
262 '',
263 ''),
264 ('registry.upcoming_work_view.enabled',230 ('registry.upcoming_work_view.enabled',
265 'boolean',231 'boolean',
266 ('If true, the new upcoming work view of teams is available.'),232 ('If true, the new upcoming work view of teams is available.'),