Merge lp:~wallyworld/launchpad/expose-bug-infotype-search-66206 into lp:launchpad

Proposed by Ian Booth
Status: Merged
Approved by: Curtis Hovey
Approved revision: no longer in the source branch.
Merged at revision: 15600
Proposed branch: lp:~wallyworld/launchpad/expose-bug-infotype-search-66206
Merge into: lp:launchpad
Prerequisite: lp:~wallyworld/launchpad/proprietary-information-type-933782
Diff against target: 389 lines (+151/-21)
12 files modified
lib/lp/bugs/browser/bugtask.py (+9/-1)
lib/lp/bugs/browser/tests/bugtask-search-views.txt (+36/-0)
lib/lp/bugs/interfaces/bugtarget.py (+2/-1)
lib/lp/bugs/interfaces/bugtask.py (+20/-7)
lib/lp/bugs/model/bugtarget.py (+2/-1)
lib/lp/bugs/model/bugtasksearch.py (+5/-2)
lib/lp/bugs/templates/bugtask-macros-tableview.pt (+17/-1)
lib/lp/bugs/tests/test_bugtask_search.py (+2/-2)
lib/lp/bugs/tests/test_searchtasks_webservice.py (+34/-0)
lib/lp/code/model/branch.py (+1/-1)
lib/lp/registry/services/tests/test_sharingservice.py (+21/-3)
lib/lp/registry/vocabularies.py (+2/-2)
To merge this branch: bzr merge lp:~wallyworld/launchpad/expose-bug-infotype-search-66206
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code Approve
Review via email: mp+114147@code.launchpad.net

Commit message

Update bugtask search UI and webservice API to allow searching bugtasks using information type to filter.

Description of the change

== Implementation ==

This branch allows to advanced bugtask search form and webservice api to be used to search for bugtasks filtering on information type. On the ui, like for Importance and Status, the Information Type checkboxes are all unclicked by default (meaning no filtering). The Proprietary option appears as necessary for projects with commercial subscriptions (if feature flag allows).

There was some whitespace to the right of the status and importance checkboxes on the advanaced bugtask search form so I added the information type checkboxes there. It seems to work well even on narrow screens.

The search backend uses the work done in the previous branch. I made some tweaks to improve the usability. eg the caller can just pass in an iterable of info types rather than having to construct an any().

== Demo ==

See screenshot:
http://people.canonical.com/~ianb/bugsearch-infotype.png

== Tests ==

I enhanced bugtask-search-views.txt to test the search view.
I added a new test case to test the search over the webservice: TestSearchByInformationType

== Lint ==

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/bugs/browser/bugtask.py
  lib/lp/bugs/browser/tests/bugtask-search-views.txt
  lib/lp/bugs/interfaces/bugtarget.py
  lib/lp/bugs/interfaces/bugtask.py
  lib/lp/bugs/model/bugtarget.py
  lib/lp/bugs/model/bugtasksearch.py
  lib/lp/bugs/templates/bugtask-macros-tableview.pt
  lib/lp/bugs/tests/test_bugtask_search.py
  lib/lp/bugs/tests/test_searchtasks_webservice.py
  lib/lp/code/model/branch.py
  lib/lp/registry/vocabularies.py

./lib/lp/bugs/browser/tests/bugtask-search-views.txt
       1: narrative uses a moin header.
     207: narrative uses a moin header.
     222: source exceeds 78 characters.
     286: narrative uses a moin header.
     326: source exceeds 78 characters.
     353: narrative uses a moin header.
     377: source exceeds 78 characters.
     380: source exceeds 78 characters.
     389: narrative uses a moin header.
     451: want exceeds 78 characters.
./lib/lp/bugs/interfaces/bugtask.py
     930: E302 expected 2 blank lines, found 1

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

Thank you very much.

Can you fix the link in ./lib/lp/bugs/interfaces/bugtask.py?

review: Approve (code)
Revision history for this message
Ian Booth (wallyworld) wrote :

Sorry, I'm not sure I follow what you need fixed?

On 10/07/12 22:45, Curtis Hovey wrote:
> Review: Approve code
>
> Thank you very much.
>
> Can you fix the link in ./lib/lp/bugs/interfaces/bugtask.py?
>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/browser/bugtask.py'
--- lib/lp/bugs/browser/bugtask.py 2012-07-10 15:39:46 +0000
+++ lib/lp/bugs/browser/bugtask.py 2012-07-11 01:24:24 +0000
@@ -241,7 +241,10 @@
241from lp.registry.interfaces.projectgroup import IProjectGroup241from lp.registry.interfaces.projectgroup import IProjectGroup
242from lp.registry.interfaces.sourcepackage import ISourcePackage242from lp.registry.interfaces.sourcepackage import ISourcePackage
243from lp.registry.model.personroles import PersonRoles243from lp.registry.model.personroles import PersonRoles
244from lp.registry.vocabularies import MilestoneVocabulary244from lp.registry.vocabularies import (
245 InformationTypeVocabulary,
246 MilestoneVocabulary,
247 )
245from lp.services.config import config248from lp.services.config import config
246from lp.services.features import getFeatureFlag249from lp.services.features import getFeatureFlag
247from lp.services.feeds.browser import (250from lp.services.feeds.browser import (
@@ -3103,6 +3106,11 @@
3103 """Return data used to render the Importance checkboxes."""3106 """Return data used to render the Importance checkboxes."""
3104 return self.getWidgetValues(vocabulary=BugTaskImportance)3107 return self.getWidgetValues(vocabulary=BugTaskImportance)
31053108
3109 def getInformationTypeWidgetValues(self):
3110 """Return data used to render the Information Type checkboxes."""
3111 return self.getWidgetValues(
3112 vocabulary=InformationTypeVocabulary(self.context))
3113
3106 def getMilestoneWidgetValues(self):3114 def getMilestoneWidgetValues(self):
3107 """Return data used to render the milestone checkboxes."""3115 """Return data used to render the milestone checkboxes."""
3108 return self.getWidgetValues("Milestone")3116 return self.getWidgetValues("Milestone")
31093117
=== modified file 'lib/lp/bugs/browser/tests/bugtask-search-views.txt'
--- lib/lp/bugs/browser/tests/bugtask-search-views.txt 2011-12-30 06:14:56 +0000
+++ lib/lp/bugs/browser/tests/bugtask-search-views.txt 2012-07-11 01:24:24 +0000
@@ -350,6 +350,42 @@
350 Mozilla Firefox 1.0350 Mozilla Firefox 1.0
351351
352352
353== Searching by information type ==
354
355The advanced form allows us to query for bugs matching specific
356information types.
357
358First we'll change the information type of one of the bugtasks (we are still
359logged in from earlier):
360
361 >>> from lp.registry.enums import InformationType
362 >>> previous_information_type = open_bugtasks[0].bug.information_type
363 >>> open_bugtasks[0].bug.transitionToInformationType(
364 ... InformationType.USERDATA, getUtility(ILaunchBag).user)
365 True
366 >>> flush_database_updates()
367
368Submit the search:
369
370 >>> form_values = {
371 ... 'search': 'Search bugs in Firefox',
372 ... 'advanced': 1,
373 ... 'field.information_type': 'USERDATA',
374 ... 'field.searchtext': '',
375 ... 'field.orderby': '-importance'}
376
377 >>> mozilla_search_listingview = create_view(mozilla, '+bugs', form_values)
378 >>> userdata_bugtasks = list(mozilla_search_listingview.search().batch)
379 >>> for bugtask in userdata_bugtasks:
380 ... print bugtask.bug.id, bugtask.product.name, bugtask.bug.information_type.name
381 15 thunderbird USERDATA
382
383 >>> open_bugtasks[0].bug.transitionToInformationType(
384 ... previous_information_type, getUtility(ILaunchBag).user)
385 True
386 >>> flush_database_updates()
387
388
353== Constructing search filter urls ==389== Constructing search filter urls ==
354390
355There is a helper method, get_buglisting_search_filter_url(), which can391There is a helper method, get_buglisting_search_filter_url(), which can
356392
=== modified file 'lib/lp/bugs/interfaces/bugtarget.py'
--- lib/lp/bugs/interfaces/bugtarget.py 2012-06-14 21:50:59 +0000
+++ lib/lp/bugs/interfaces/bugtarget.py 2012-07-11 01:24:24 +0000
@@ -70,6 +70,7 @@
70 "search_text": copy_field(IBugTaskSearch['searchtext']),70 "search_text": copy_field(IBugTaskSearch['searchtext']),
71 "status": copy_field(IBugTaskSearch['status']),71 "status": copy_field(IBugTaskSearch['status']),
72 "importance": copy_field(IBugTaskSearch['importance']),72 "importance": copy_field(IBugTaskSearch['importance']),
73 "information_type": copy_field(IBugTaskSearch['information_type']),
73 "assignee": Reference(schema=Interface),74 "assignee": Reference(schema=Interface),
74 "bug_reporter": Reference(schema=Interface),75 "bug_reporter": Reference(schema=Interface),
75 "bug_supervisor": Reference(schema=Interface),76 "bug_supervisor": Reference(schema=Interface),
@@ -258,7 +259,7 @@
258 hardware_is_linked_to_bug=False, linked_branches=None,259 hardware_is_linked_to_bug=False, linked_branches=None,
259 linked_blueprints=None, structural_subscriber=None,260 linked_blueprints=None, structural_subscriber=None,
260 modified_since=None, created_since=None,261 modified_since=None, created_since=None,
261 created_before=None):262 created_before=None, information_type=None):
262 """Search the IBugTasks reported on this entity.263 """Search the IBugTasks reported on this entity.
263264
264 :search_params: a BugTaskSearchParams object265 :search_params: a BugTaskSearchParams object
265266
=== modified file 'lib/lp/bugs/interfaces/bugtask.py'
--- lib/lp/bugs/interfaces/bugtask.py 2012-07-11 01:24:24 +0000
+++ lib/lp/bugs/interfaces/bugtask.py 2012-07-11 01:24:24 +0000
@@ -924,6 +924,10 @@
924 ])924 ])
925925
926926
927# Avoid circular imports
928from lp.registry.enums import InformationType
929
930
927class IBugTaskSearchBase(Interface):931class IBugTaskSearchBase(Interface):
928 """The basic search controls."""932 """The basic search controls."""
929 searchtext = TextLine(title=_("Bug ID or search text."), required=False)933 searchtext = TextLine(title=_("Bug ID or search text."), required=False)
@@ -943,6 +947,14 @@
943 'or list of importances.'),947 'or list of importances.'),
944 value_type=IBugTask['importance'],948 value_type=IBugTask['importance'],
945 required=False)949 required=False)
950 information_type = List(
951 title=_('Information Type'),
952 description=_('Show only bugs with the given information type '
953 'or list of information types.'),
954 value_type=Choice(
955 title=_('Information Type'),
956 vocabulary=InformationType),
957 required=False)
946 assignee = Choice(958 assignee = Choice(
947 title=_('Assignee'),959 title=_('Assignee'),
948 description=_('Person entity assigned for this bug.'),960 description=_('Person entity assigned for this bug.'),
@@ -1180,7 +1192,7 @@
1180 created_since=None, exclude_conjoined_tasks=False, cve=None,1192 created_since=None, exclude_conjoined_tasks=False, cve=None,
1181 upstream_target=None, milestone_dateexpected_before=None,1193 upstream_target=None, milestone_dateexpected_before=None,
1182 milestone_dateexpected_after=None, created_before=None,1194 milestone_dateexpected_after=None, created_before=None,
1183 information_types=None):1195 information_type=None):
11841196
1185 self.bug = bug1197 self.bug = bug
1186 self.searchtext = searchtext1198 self.searchtext = searchtext
@@ -1234,12 +1246,12 @@
1234 self.upstream_target = upstream_target1246 self.upstream_target = upstream_target
1235 self.milestone_dateexpected_before = milestone_dateexpected_before1247 self.milestone_dateexpected_before = milestone_dateexpected_before
1236 self.milestone_dateexpected_after = milestone_dateexpected_after1248 self.milestone_dateexpected_after = milestone_dateexpected_after
1237 if isinstance(information_types, collections.Iterable):1249 if isinstance(information_type, collections.Iterable):
1238 self.information_types = information_types1250 self.information_type = set(information_type)
1239 elif information_types:1251 elif information_type:
1240 self.information_types = (information_types,)1252 self.information_type = set((information_type,))
1241 else:1253 else:
1242 self.information_types = None1254 self.information_type = None
12431255
1244 def setProduct(self, product):1256 def setProduct(self, product):
1245 """Set the upstream context on which to filter the search."""1257 """Set the upstream context on which to filter the search."""
@@ -1385,7 +1397,7 @@
1385 hardware_is_linked_to_bug=False, linked_branches=None,1397 hardware_is_linked_to_bug=False, linked_branches=None,
1386 linked_blueprints=None, structural_subscriber=None,1398 linked_blueprints=None, structural_subscriber=None,
1387 modified_since=None, created_since=None,1399 modified_since=None, created_since=None,
1388 created_before=None):1400 created_before=None, information_type=None):
1389 """Create and return a new instance using the parameter list."""1401 """Create and return a new instance using the parameter list."""
1390 search_params = cls(user=user, orderby=order_by)1402 search_params = cls(user=user, orderby=order_by)
13911403
@@ -1457,6 +1469,7 @@
1457 search_params.modified_since = modified_since1469 search_params.modified_since = modified_since
1458 search_params.created_since = created_since1470 search_params.created_since = created_since
1459 search_params.created_before = created_before1471 search_params.created_before = created_before
1472 search_params.information_type = information_type
14601473
1461 return search_params1474 return search_params
14621475
14631476
=== modified file 'lib/lp/bugs/model/bugtarget.py'
--- lib/lp/bugs/model/bugtarget.py 2012-06-14 21:50:59 +0000
+++ lib/lp/bugs/model/bugtarget.py 2012-07-11 01:24:24 +0000
@@ -81,7 +81,8 @@
81 hardware_owner_is_subscribed_to_bug=False,81 hardware_owner_is_subscribed_to_bug=False,
82 hardware_is_linked_to_bug=False, linked_branches=None,82 hardware_is_linked_to_bug=False, linked_branches=None,
83 linked_blueprints=None, modified_since=None,83 linked_blueprints=None, modified_since=None,
84 created_since=None, created_before=None):84 created_since=None, created_before=None,
85 information_type=None):
85 """See `IHasBugs`."""86 """See `IHasBugs`."""
86 if status is None:87 if status is None:
87 # If no statuses are supplied, default to the88 # If no statuses are supplied, default to the
8889
=== modified file 'lib/lp/bugs/model/bugtasksearch.py'
--- lib/lp/bugs/model/bugtasksearch.py 2012-07-11 01:24:24 +0000
+++ lib/lp/bugs/model/bugtasksearch.py 2012-07-11 01:24:24 +0000
@@ -182,6 +182,8 @@
182182
183def search_value_to_storm_where_condition(comp, search_value):183def search_value_to_storm_where_condition(comp, search_value):
184 """Convert a search value to a Storm WHERE condition."""184 """Convert a search value to a Storm WHERE condition."""
185 if zope_isinstance(search_value, (set, list, tuple)):
186 search_value = any(*search_value)
185 if zope_isinstance(search_value, any):187 if zope_isinstance(search_value, any):
186 # When an any() clause is provided, the argument value188 # When an any() clause is provided, the argument value
187 # is a list of acceptable filter values.189 # is a list of acceptable filter values.
@@ -734,9 +736,10 @@
734 extra_clauses.append(736 extra_clauses.append(
735 BugTaskFlat.datecreated < params.created_before)737 BugTaskFlat.datecreated < params.created_before)
736738
737 if params.information_types:739 if params.information_type:
738 extra_clauses.append(740 extra_clauses.append(
739 BugTaskFlat.information_type.is_in(params.information_types))741 search_value_to_storm_where_condition(
742 BugTaskFlat.information_type, params.information_type))
740743
741 query = And(extra_clauses)744 query = And(extra_clauses)
742745
743746
=== modified file 'lib/lp/bugs/templates/bugtask-macros-tableview.pt'
--- lib/lp/bugs/templates/bugtask-macros-tableview.pt 2012-06-27 19:23:40 +0000
+++ lib/lp/bugs/templates/bugtask-macros-tableview.pt 2012-07-11 01:24:24 +0000
@@ -273,7 +273,7 @@
273 </tal:checkbox>273 </tal:checkbox>
274 </div>274 </div>
275 </td>275 </td>
276 <td width="30%">276 <td width="25%">
277 <div><label>Importance:</label></div>277 <div><label>Importance:</label></div>
278 <div tal:repeat="widget_value view/getImportanceWidgetValues">278 <div tal:repeat="widget_value view/getImportanceWidgetValues">
279 <tal:checkbox279 <tal:checkbox
@@ -289,6 +289,22 @@
289 </tal:checkbox>289 </tal:checkbox>
290 </div>290 </div>
291 </td>291 </td>
292 <td width="35%">
293 <div><label>Information Type:</label></div>
294 <div tal:repeat="widget_value view/getInformationTypeWidgetValues">
295 <tal:checkbox
296 define="widget_id string:information_type.${widget_value/title}">
297 <input name="field.information_type:list"
298 type="checkbox"
299 tal:attributes="value widget_value/value;
300 checked widget_value/checked;
301 id widget_id"/>
302 <label style="font-weight: normal"
303 tal:content="widget_value/title"
304 tal:attributes="for widget_id">Public</label>
305 </tal:checkbox>
306 </div>
307 </td>
292 </tr>308 </tr>
293 </table>309 </table>
294 </fieldset>310 </fieldset>
295311
=== modified file 'lib/lp/bugs/tests/test_bugtask_search.py'
--- lib/lp/bugs/tests/test_bugtask_search.py 2012-07-11 01:24:24 +0000
+++ lib/lp/bugs/tests/test_bugtask_search.py 2012-07-11 01:24:24 +0000
@@ -417,11 +417,11 @@
417 InformationType.EMBARGOEDSECURITY, self.owner)417 InformationType.EMBARGOEDSECURITY, self.owner)
418 params = self.getBugTaskSearchParams(418 params = self.getBugTaskSearchParams(
419 user=self.owner,419 user=self.owner,
420 information_types=InformationType.EMBARGOEDSECURITY)420 information_type=InformationType.EMBARGOEDSECURITY)
421 self.assertSearchFinds(params, [self.bugtasks[2]])421 self.assertSearchFinds(params, [self.bugtasks[2]])
422 params = self.getBugTaskSearchParams(422 params = self.getBugTaskSearchParams(
423 user=self.owner,423 user=self.owner,
424 information_types=InformationType.UNEMBARGOEDSECURITY)424 information_type=InformationType.UNEMBARGOEDSECURITY)
425 self.assertSearchFinds(params, [])425 self.assertSearchFinds(params, [])
426426
427 def test_omit_duplicate_bugs(self):427 def test_omit_duplicate_bugs(self):
428428
=== modified file 'lib/lp/bugs/tests/test_searchtasks_webservice.py'
--- lib/lp/bugs/tests/test_searchtasks_webservice.py 2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/tests/test_searchtasks_webservice.py 2012-07-11 01:24:24 +0000
@@ -5,6 +5,7 @@
55
6__metaclass__ = type6__metaclass__ = type
77
8from lp.registry.enums import InformationType
8from lp.testing import (9from lp.testing import (
9 person_logged_in,10 person_logged_in,
10 TestCaseWithFactory,11 TestCaseWithFactory,
@@ -81,3 +82,36 @@
81 # validation is performed for the linked_blueprints parameter, and82 # validation is performed for the linked_blueprints parameter, and
82 # thus no error is returned when we pass rubbish.83 # thus no error is returned when we pass rubbish.
83 self.search("beta", linked_blueprints="Teabags!")84 self.search("beta", linked_blueprints="Teabags!")
85
86
87class TestSearchByInformationType(TestCaseWithFactory):
88 """Tests for the information_type parameter."""
89
90 layer = DatabaseFunctionalLayer
91
92 def setUp(self):
93 super(TestSearchByInformationType, self).setUp()
94 self.owner = self.factory.makePerson()
95 with person_logged_in(self.owner):
96 self.product = self.factory.makeProduct()
97 self.bug = self.factory.makeBug(
98 product=self.product,
99 information_type=InformationType.EMBARGOEDSECURITY)
100 self.webservice = LaunchpadWebServiceCaller(
101 'launchpad-library', 'salgado-change-anything')
102
103 def search(self, api_version, **kwargs):
104 return self.webservice.named_get(
105 '/%s' % self.product.name, 'searchTasks',
106 api_version=api_version, **kwargs).jsonBody()
107
108 def test_search_returns_results(self):
109 # A matching search returns results.
110 response = self.search(
111 "devel", information_type="Embargoed Security")
112 self.assertEqual(response['total_size'], 1)
113
114 def test_search_returns_no_results(self):
115 # A non-matching search returns no results.
116 response = self.search("devel", information_type="User Data")
117 self.assertEqual(response['total_size'], 0)
84118
=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py 2012-07-11 01:24:24 +0000
+++ lib/lp/code/model/branch.py 2012-07-11 01:24:24 +0000
@@ -1318,7 +1318,7 @@
1318 # Branches linked to private bugs can be private.1318 # Branches linked to private bugs can be private.
1319 params = BugTaskSearchParams(1319 params = BugTaskSearchParams(
1320 user=user, linked_branches=self.id,1320 user=user, linked_branches=self.id,
1321 information_types=PRIVATE_INFORMATION_TYPES)1321 information_type=PRIVATE_INFORMATION_TYPES)
1322 bug_ids = getUtility(IBugTaskSet).searchBugIds(params)1322 bug_ids = getUtility(IBugTaskSet).searchBugIds(params)
1323 return bug_ids.count() > 01323 return bug_ids.count() > 0
13241324
13251325
=== modified file 'lib/lp/registry/services/tests/test_sharingservice.py'
--- lib/lp/registry/services/tests/test_sharingservice.py 2012-07-11 01:24:24 +0000
+++ lib/lp/registry/services/tests/test_sharingservice.py 2012-07-11 01:24:24 +0000
@@ -402,6 +402,25 @@
402 login_person(self.factory.makePerson())402 login_person(self.factory.makePerson())
403 self._assert_getPillarShareesUnauthorized(product)403 self._assert_getPillarShareesUnauthorized(product)
404404
405 def _assert_sharee_data(self, expected, actual):
406 # Assert that the actual and expected sharee data is equal.
407 # Sharee data is a list of (sharee, permissions, info_types) tuples.
408 expected_list = list(expected)
409 actual_list = list(actual)
410 self.assertEqual(len(expected_list), len(list(actual_list)))
411
412 expected_sharee_map = {}
413 for data in expected_list:
414 expected_sharee_map[data[0]] = data[1:]
415 actual_sharee_map = {}
416 for data in actual_list:
417 actual_sharee_map[data[0]] = data[1:]
418
419 for sharee, expected_permissions, expected_info_types in expected:
420 actual_permissions, actual_info_types = actual_sharee_map[sharee]
421 self.assertContentEqual(expected_permissions, actual_permissions)
422 self.assertContentEqual(expected_info_types, actual_info_types)
423
405 def _assert_sharePillarInformation(self, pillar, pillar_type=None):424 def _assert_sharePillarInformation(self, pillar, pillar_type=None):
406 """sharePillarInformations works and returns the expected data."""425 """sharePillarInformations works and returns the expected data."""
407 sharee = self.factory.makePerson()426 sharee = self.factory.makePerson()
@@ -464,7 +483,7 @@
464 expected_sharee_data = self._makeShareeData(483 expected_sharee_data = self._makeShareeData(
465 sharee, expected_permissions,484 sharee, expected_permissions,
466 [InformationType.EMBARGOEDSECURITY, InformationType.USERDATA])485 [InformationType.EMBARGOEDSECURITY, InformationType.USERDATA])
467 self.assertEqual(expected_sharee_data, sharee_data)486 self.assertContentEqual(expected_sharee_data, sharee_data)
468 # Check that getPillarSharees returns what we expect.487 # Check that getPillarSharees returns what we expect.
469 if pillar_type == 'product':488 if pillar_type == 'product':
470 expected_sharee_grants = [489 expected_sharee_grants = [
@@ -618,8 +637,7 @@
618 policy, SharingPermission.ALL) for policy in access_policies])637 policy, SharingPermission.ALL) for policy in access_policies])
619 owner_data = (pillar.owner, policy_permissions, [])638 owner_data = (pillar.owner, policy_permissions, [])
620 expected_data.append(owner_data)639 expected_data.append(owner_data)
621 640 self._assert_sharee_data(
622 self.assertContentEqual(
623 expected_data, self.service.getPillarSharees(pillar))641 expected_data, self.service.getPillarSharees(pillar))
624642
625 def test_deleteProductShareeAll(self):643 def test_deleteProductShareeAll(self):
626644
=== modified file 'lib/lp/registry/vocabularies.py'
--- lib/lp/registry/vocabularies.py 2012-07-11 01:24:24 +0000
+++ lib/lp/registry/vocabularies.py 2012-07-11 01:24:24 +0000
@@ -2276,8 +2276,8 @@
2276 IProduct.providedBy(subscription_context) and2276 IProduct.providedBy(subscription_context) and
2277 subscription_context.has_current_commercial_subscription)2277 subscription_context.has_current_commercial_subscription)
2278 already_proprietary = (2278 already_proprietary = (
2279 safe_hasattr(context, 'information_type')2279 safe_hasattr(context, 'information_type') and
2280 and context.information_type == InformationType.PROPRIETARY)2280 context.information_type == InformationType.PROPRIETARY)
2281 if has_commercial_subscription or already_proprietary:2281 if has_commercial_subscription or already_proprietary:
2282 types.append(InformationType.PROPRIETARY)2282 types.append(InformationType.PROPRIETARY)
2283 # Disallow public items for projects with private bugs.2283 # Disallow public items for projects with private bugs.