launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #15145
[Merge] lp:~stevenk/launchpad/new-branch-search into lp:launchpad
Steve Kowalik has proposed merging lp:~stevenk/launchpad/new-branch-search into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #793830 in Launchpad itself: "Branch:+register-merge / Specification:+linkbranch time out due to substring matching many tables"
https://bugs.launchpad.net/launchpad/+bug/793830
For more details, see:
https://code.launchpad.net/~stevenk/launchpad/new-branch-search/+merge/147840
Destroy the current branch search paradigm. Unfortunately, now I can't finish this description since I've killed myself for using the word 'paradigm'.
IBranchCollection.search(), its one friend and three other semi-related but unused methods have met their timely demise, replaced with search_branches which doesn't do stupid things like looking for the search terms against Product.name or SourcePackageName. I have declared that only used in tests is unused, and forced the tests to make use of other methods.
search_branches will only match against Branch.name, with a few shortcuts that will return singular branches if we're passed a URL, lp: shortform or unique_name.
The branch vocabularies have been rewritten substaintly to rely on search_branches, since all of the branch search functionality makes use of them.
--
https://code.launchpad.net/~stevenk/launchpad/new-branch-search/+merge/147840
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/new-branch-search into lp:launchpad.
=== modified file 'lib/lp/code/browser/widgets/tests/test_branchpopupwidget.py'
--- lib/lp/code/browser/widgets/tests/test_branchpopupwidget.py 2012-01-01 02:58:52 +0000
+++ lib/lp/code/browser/widgets/tests/test_branchpopupwidget.py 2013-02-12 05:42:24 +0000
@@ -211,7 +211,7 @@
# Make a popup restricted to a particular product.
vocab = BranchRestrictedOnProductVocabulary(self.launch_bag.product)
- self.assertEqual(vocab.product, self.launch_bag.product)
+ self.assertEqual(vocab.context, self.launch_bag.product)
popup = self.makeBranchPopup(vocab)
# Make a branch on a different product.
=== modified file 'lib/lp/code/feed/branch.py'
--- lib/lp/code/feed/branch.py 2011-12-30 07:32:58 +0000
+++ lib/lp/code/feed/branch.py 2013-02-12 05:42:24 +0000
@@ -162,15 +162,12 @@
Only `self.quantity` revisions are returned.
"""
- from lp.code.model.branch import Branch
collection = self._getCollection().visibleByUser(
None).withLifecycleStatus(*DEFAULT_BRANCH_STATUS_IN_LISTING)
branches = collection.getBranches(eager_load=False)
branches.order_by(
- Desc(Branch.date_last_modified),
- Asc(Branch.target_suffix),
- Desc(Branch.lifecycle_status),
- Asc(Branch.name))
+ Desc('Branch.date_last_modified'), Asc('Branch.target_suffix'),
+ Desc('Branch.lifecycle_status'), Asc('Branch.name'))
branches.config(limit=self.quantity)
return list(branches)
=== modified file 'lib/lp/code/interfaces/branchcollection.py'
--- lib/lp/code/interfaces/branchcollection.py 2013-01-07 02:40:55 +0000
+++ lib/lp/code/interfaces/branchcollection.py 2013-02-12 05:42:24 +0000
@@ -161,36 +161,15 @@
def isPrivate():
"""Restrict the collection to private branches."""
- def isExclusive():
- """Restrict the collection to branches owned by exclusive people."""
-
def isSeries():
"""Restrict the collection to branches those linked to series."""
def ownedBy(person):
"""Restrict the collection to branches owned by 'person'."""
- def ownedByTeamMember(person):
- """Restrict the collection to branches owned by 'person' or a team
- of which person is a member.
- """
-
def registeredBy(person):
"""Restrict the collection to branches registered by 'person'."""
- def relatedTo(person):
- """Restrict the collection to branches related to 'person'.
-
- That is, branches that 'person' owns, registered or is subscribed to.
- """
-
- def search(search_term):
- """Search the collection for branches matching 'search_term'.
-
- :param search_term: A string.
- :return: An `ICountableIterator`.
- """
-
def scanned():
"""Restrict the collection to branches that have been scanned."""
=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py 2013-01-16 06:41:43 +0000
+++ lib/lp/code/model/branch.py 2013-02-12 05:42:24 +0000
@@ -147,6 +147,7 @@
validate_person,
validate_public_person,
)
+from lp.registry.interfaces.role import IPersonRoles
from lp.registry.interfaces.sharingjob import (
IRemoveArtifactSubscriptionsJobSource,
)
@@ -1630,6 +1631,9 @@
if user is None:
return [public_branch_filter]
+ if IPersonRoles(user).in_admin:
+ return []
+
artifact_grant_query = Coalesce(
ArrayIntersects(
SQL('%s.access_grants' % branch_class.__storm_table__),
=== modified file 'lib/lp/code/model/branchcollection.py'
--- lib/lp/code/model/branchcollection.py 2012-10-18 19:06:48 +0000
+++ lib/lp/code/model/branchcollection.py 2013-02-12 05:42:24 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Implementations of `IBranchCollection`."""
@@ -6,11 +6,13 @@
__metaclass__ = type
__all__ = [
'GenericBranchCollection',
+ 'search_branches',
]
from collections import defaultdict
from functools import partial
from operator import attrgetter
+from urlparse import urlparse
from lazr.restful.utils import safe_hasattr
from storm.expr import (
@@ -20,10 +22,8 @@
In,
Join,
LeftJoin,
- Or,
Select,
SQL,
- Union,
With,
)
from storm.info import ClassAlias
@@ -63,15 +63,14 @@
from lp.code.model.codereviewvote import CodeReviewVoteReference
from lp.code.model.revision import Revision
from lp.code.model.seriessourcepackagebranch import SeriesSourcePackageBranch
-from lp.registry.enums import EXCLUSIVE_TEAM_POLICY
+from lp.registry.interfaces.distroseries import IDistroSeries
+from lp.registry.interfaces.person import IPerson
+from lp.registry.interfaces.product import IProduct
+from lp.registry.interfaces.sourcepackagename import ISourcePackageName
from lp.registry.model.distribution import Distribution
from lp.registry.model.distroseries import DistroSeries
-from lp.registry.model.person import (
- Owner,
- Person,
- )
+from lp.registry.model.person import Person
from lp.registry.model.product import Product
-from lp.registry.model.sourcepackagename import SourcePackageName
from lp.registry.model.teammembership import TeamParticipation
from lp.services.database.bulk import (
load_referencing,
@@ -87,7 +86,6 @@
from lp.services.database.sqlbase import quote
from lp.services.propertycache import get_property_cache
from lp.services.searchbuilder import any
-from lp.services.webapp.vocabulary import CountableIterator
class GenericBranchCollection:
@@ -614,13 +612,6 @@
return self._filterBy([
Branch.information_type.is_in(PRIVATE_INFORMATION_TYPES)])
- def isExclusive(self):
- """See `IBranchCollection`."""
- return self._filterBy(
- [Person.membership_policy.is_in(EXCLUSIVE_TEAM_POLICY)],
- table=Person,
- join=Join(Person, Branch.ownerID == Person.id))
-
def isSeries(self):
"""See `IBranchCollection`."""
# ProductSeries import's this module.
@@ -634,85 +625,10 @@
"""See `IBranchCollection`."""
return self._filterBy([Branch.owner == person], symmetric=False)
- def ownedByTeamMember(self, person):
- """See `IBranchCollection`."""
- subquery = Select(
- TeamParticipation.teamID,
- where=TeamParticipation.personID == person.id)
- filter = [In(Branch.ownerID, subquery)]
-
- return self._filterBy(filter, symmetric=False)
-
def registeredBy(self, person):
"""See `IBranchCollection`."""
return self._filterBy([Branch.registrant == person], symmetric=False)
- def relatedTo(self, person):
- """See `IBranchCollection`."""
- return self._filterBy(
- [Branch.id.is_in(
- Union(
- Select(Branch.id, Branch.owner == person),
- Select(Branch.id, Branch.registrant == person),
- Select(Branch.id,
- And(BranchSubscription.person == person,
- BranchSubscription.branch == Branch.id))))],
- symmetric=False)
-
- def _getExactMatch(self, search_term):
- """Return the exact branch that 'search_term' matches, or None."""
- search_term = search_term.rstrip('/')
- branch_set = getUtility(IBranchLookup)
- branch = branch_set.getByUniqueName(search_term)
- if branch is None:
- branch = branch_set.getByUrl(search_term)
- return branch
-
- def search(self, search_term):
- """See `IBranchCollection`."""
- # XXX: JonathanLange 2009-02-23 bug 372591: This matches the old
- # search algorithm that used to live in vocabularies/dbojects.py. It's
- # not actually very good -- really it should match based on substrings
- # of the unique name and sort based on relevance.
- branch = self._getExactMatch(search_term)
- if branch is not None:
- if branch in self.getBranches(eager_load=False):
- return CountableIterator(1, [branch])
- else:
- return CountableIterator(0, [])
- like_term = '%' + search_term + '%'
- # Match the Branch name or the URL.
- queries = [Select(Branch.id,
- Or(Branch.name.like(like_term),
- Branch.url == search_term))]
- # Match the product name.
- if 'product' not in self._exclude_from_search:
- queries.append(Select(
- Branch.id,
- And(Branch.product == Product.id,
- Product.name.like(like_term))))
-
- # Match the owner name.
- queries.append(Select(
- Branch.id,
- And(Branch.owner == Owner.id, Owner.name.like(like_term))))
-
- # Match the package bits.
- queries.append(
- Select(Branch.id,
- And(Branch.sourcepackagename == SourcePackageName.id,
- Branch.distroseries == DistroSeries.id,
- DistroSeries.distribution == Distribution.id,
- Or(SourcePackageName.name.like(like_term),
- DistroSeries.name.like(like_term),
- Distribution.name.like(like_term)))))
-
- # Get the results.
- collection = self._filterBy([Branch.id.is_in(Union(*queries))])
- results = collection.getBranches(eager_load=False).order_by(
- Branch.name, Branch.id)
- return CountableIterator(results.count(), results)
-
def scanned(self):
"""See `IBranchCollection`."""
return self._filterBy([Branch.last_scanned != None])
@@ -863,3 +779,67 @@
raise InvalidFilter(
"Cannot filter for branches visible by user %r, already "
"filtering for %r" % (person, self._user))
+
+
+def search_branches(context, user, search_term, extra_joins=[],
+ extra_clauses=[]):
+ store = IStore(Branch)
+
+ # If the search_term is a full URL, grab the branch and return it.
+ if search_term and search_term.startswith('lp:'):
+ return _known_visible_branch(
+ getUtility(IBranchLookup).getByUrl(search_term), context, user)
+ if search_term and search_term.startswith('http'):
+ # Look up the branch by its URL.
+ branch_url = getUtility(IBranchLookup).getByUrl(search_term)
+ if branch_url:
+ return _known_visible_branch(branch_url, context, user)
+ # If that fails, strip off the path and search by its unique name.
+ path = urlparse(search_term)[2][1:]
+ return _known_visible_branch(
+ getUtility(IBranchLookup).getByUniqueName(path), context, user)
+ if search_term and search_term.startswith('~'):
+ return _known_visible_branch(
+ getUtility(IBranchLookup).getByUniqueName(search_term), context,
+ user)
+
+ clauses = get_branch_privacy_filter(user)
+ if IProduct.providedBy(context):
+ col = Branch.productID
+ elif IDistroSeries.providedBy(context):
+ col = Branch.distroseries_id
+ elif ISourcePackageName.providedBy(context):
+ col = Branch.sourcepackagename_id
+ elif IPerson.providedBy(context):
+ extra_joins.extend([
+ Join(Person, Person.id == Branch.ownerID),
+ Join(
+ TeamParticipation, TeamParticipation.personID == context.id)])
+ clauses.append(Branch.ownerID == TeamParticipation.teamID)
+ col = None
+ else:
+ col = None
+ if col:
+ clauses.append(col == context.id)
+ if search_term:
+ clauses.append(Branch.name.like(search_term))
+ origin = [Branch]
+ if extra_joins:
+ origin.extend(extra_joins)
+ if extra_clauses:
+ clauses.extend(extra_clauses)
+
+ return list(store.using(*origin).find(Branch, *clauses))
+
+
+def _known_visible_branch(branch, context, user):
+ if branch is None:
+ return []
+ elif branch.visibleByUser(user):
+ if (context and IProduct.providedBy(context)
+ and branch.product != context):
+ return []
+ if user:
+ get_property_cache(branch)._known_viewers = [user.id]
+ return [branch]
+ return []
=== modified file 'lib/lp/code/model/tests/test_branchcollection.py'
--- lib/lp/code/model/tests/test_branchcollection.py 2012-10-18 19:20:49 +0000
+++ lib/lp/code/model/tests/test_branchcollection.py 2013-02-12 05:42:24 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for branch collections."""
@@ -31,19 +31,18 @@
)
from lp.code.interfaces.codehosting import LAUNCHPAD_SERVICES
from lp.code.model.branch import Branch
-from lp.code.model.branchcollection import GenericBranchCollection
+from lp.code.model.branchcollection import (
+ GenericBranchCollection,
+ search_branches,
+ )
from lp.code.tests.helpers import remove_all_sample_data_branches
from lp.registry.enums import PersonVisibility
from lp.registry.interfaces.person import TeamMembershipPolicy
from lp.registry.interfaces.pocket import PackagePublishingPocket
-from lp.services.database.interfaces import (
- DEFAULT_FLAVOR,
- IStoreSelector,
- MAIN_STORE,
- )
+from lp.services.database.lpstorm import IStore
+from lp.services.webapp.publisher import canonical_url
from lp.testing import (
person_logged_in,
- run_with_login,
StormStatementRecorder,
TestCaseWithFactory,
)
@@ -93,10 +92,9 @@
layer = DatabaseFunctionalLayer
def setUp(self):
- TestCaseWithFactory.setUp(self)
+ super(TestGenericBranchCollection, self).setUp()
remove_all_sample_data_branches()
- self.store = getUtility(IStoreSelector).get(
- MAIN_STORE, DEFAULT_FLAVOR)
+ self.store = IStore(Branch)
def test_provides_branchcollection(self):
# `GenericBranchCollection` provides the `IBranchCollection`
@@ -257,16 +255,6 @@
collection = self.all_branches.ownedBy(branch.owner)
self.assertEqual([branch], list(collection.getBranches()))
- def test_ownedByTeamMember(self):
- # 'ownedBy' returns a new collection restricted to branches owned by
- # any team of which the given person is a member.
- person = self.factory.makePerson()
- team = self.factory.makeTeam(members=[person])
- branch = self.factory.makeAnyBranch(owner=team)
- self.factory.makeAnyBranch()
- collection = self.all_branches.ownedByTeamMember(person)
- self.assertEqual([branch], list(collection.getBranches()))
-
def test_in_product(self):
# 'inProduct' returns a new collection restricted to branches in the
# given product.
@@ -291,38 +279,6 @@
collection = self.all_branches.inProject(project)
self.assertEqual([branch], list(collection.getBranches()))
- def test_isExclusive(self):
- # 'isExclusive' is restricted to branches owned by exclusive
- # teams and users.
- user = self.factory.makePerson()
- team = self.factory.makeTeam(
- membership_policy=TeamMembershipPolicy.RESTRICTED)
- other_team = self.factory.makeTeam(
- membership_policy=TeamMembershipPolicy.OPEN)
- team_branch = self.factory.makeAnyBranch(owner=team)
- user_branch = self.factory.makeAnyBranch(owner=user)
- self.factory.makeAnyBranch(owner=other_team)
- collection = self.all_branches.isExclusive()
- self.assertContentEqual(
- [team_branch, user_branch], list(collection.getBranches()))
-
- def test_inProduct_and_isExclusive(self):
- # 'inProduct' and 'isExclusive' can combine to form a collection that
- # is restricted to branches of a particular product owned exclusive
- # teams and users.
- team = self.factory.makeTeam(
- membership_policy=TeamMembershipPolicy.RESTRICTED)
- other_team = self.factory.makeTeam(
- membership_policy=TeamMembershipPolicy.OPEN)
- product = self.factory.makeProduct()
- branch = self.factory.makeProductBranch(product=product, owner=team)
- self.factory.makeAnyBranch(owner=team)
- self.factory.makeProductBranch(product=product, owner=other_team)
- collection = self.all_branches.inProduct(product).isExclusive()
- self.assertEqual([branch], list(collection.getBranches()))
- collection = self.all_branches.isExclusive().inProduct(product)
- self.assertEqual([branch], list(collection.getBranches()))
-
def test_isSeries(self):
# 'isSeries' is restricted to branches linked to product series.
series = self.factory.makeProductSeries()
@@ -379,24 +335,6 @@
collection = self.all_branches.ownedBy(person).isPrivate()
self.assertEqual([branch], list(collection.getBranches()))
- def test_ownedByTeamMember_and_inProduct(self):
- # 'ownedBy' and 'inProduct' can combine to form a collection that is
- # restricted to branches of a particular product owned by a particular
- # person or team of which the person is a member.
- person = self.factory.makePerson()
- team = self.factory.makeTeam(members=[person])
- product = self.factory.makeProduct()
- branch = self.factory.makeProductBranch(product=product, owner=person)
- branch2 = self.factory.makeProductBranch(product=product, owner=team)
- self.factory.makeAnyBranch(owner=person)
- self.factory.makeProductBranch(product=product)
- product_branches = self.all_branches.inProduct(product)
- collection = product_branches.ownedByTeamMember(person)
- self.assertContentEqual([branch, branch2], collection.getBranches())
- person_branches = self.all_branches.ownedByTeamMember(person)
- collection = person_branches.inProduct(product)
- self.assertContentEqual([branch, branch2], collection.getBranches())
-
def test_in_source_package(self):
# 'inSourcePackage' returns a new collection that only has branches in
# the given source package.
@@ -560,34 +498,6 @@
collection = self.all_branches.subscribedBy(subscriber)
self.assertEqual([branch], list(collection.getBranches()))
- def test_relatedTo(self):
- # 'relatedTo' returns a collection that has all branches that a user
- # owns, is subscribed to or registered. No other branches are in this
- # collection.
- person = self.factory.makePerson()
- team = self.factory.makeTeam(person)
- owned_branch = self.factory.makeAnyBranch(owner=person)
- # Unsubscribe the owner, to demonstrate that we show owned branches
- # even if they aren't subscribed.
- owned_branch.unsubscribe(person, person)
- # Subscribe two other people to the owned branch to make sure
- # that the BranchSubscription join is doing it right.
- self.factory.makeBranchSubscription(branch=owned_branch)
- self.factory.makeBranchSubscription(branch=owned_branch)
-
- registered_branch = self.factory.makeAnyBranch(
- owner=team, registrant=person)
- subscribed_branch = self.factory.makeAnyBranch()
- subscribed_branch.subscribe(
- person, BranchSubscriptionNotificationLevel.NOEMAIL,
- BranchSubscriptionDiffSize.NODIFF,
- CodeReviewNotificationLevel.NOEMAIL,
- person)
- related_branches = self.all_branches.relatedTo(person)
- self.assertEqual(
- sorted([owned_branch, registered_branch, subscribed_branch]),
- sorted(related_branches.getBranches()))
-
def test_withBranchType(self):
hosted_branch1 = self.factory.makeAnyBranch(
branch_type=BranchType.HOSTED)
@@ -1118,190 +1028,6 @@
self.assertEqual([proposal], list(proposals))
-class TestSearch(TestCaseWithFactory):
- """Tests for IBranchCollection.search()."""
-
- layer = DatabaseFunctionalLayer
-
- def setUp(self):
- TestCaseWithFactory.setUp(self)
- remove_all_sample_data_branches()
- self.collection = getUtility(IAllBranches)
-
- def test_exact_match_unique_name(self):
- # If you search for a unique name of a branch that exists, you'll get
- # a single result with a branch with that branch name.
- branch = self.factory.makeAnyBranch()
- self.factory.makeAnyBranch()
- search_results = self.collection.search(branch.unique_name)
- self.assertEqual([branch], list(search_results))
-
- def test_unique_name_match_not_in_collection(self):
- # If you search for a unique name of a branch that does not exist,
- # you'll get an empty result set.
- branch = self.factory.makeAnyBranch()
- collection = self.collection.inProduct(self.factory.makeProduct())
- search_results = collection.search(branch.unique_name)
- self.assertEqual([], list(search_results))
-
- def test_exact_match_remote_url(self):
- # If you search for the remote URL of a branch, and there's a branch
- # with that URL, you'll get a single result with a branch with that
- # branch name.
- branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED)
- self.factory.makeAnyBranch()
- search_results = self.collection.search(branch.url)
- self.assertEqual([branch], list(search_results))
-
- def test_exact_match_launchpad_url(self):
- # If you search for the Launchpad URL of a branch, and there is a
- # branch with that URL, then you get a single result with that branch.
- branch = self.factory.makeAnyBranch()
- self.factory.makeAnyBranch()
- search_results = self.collection.search(branch.codebrowse_url())
- self.assertEqual([branch], list(search_results))
-
- def test_exact_match_bzr_identity(self):
- # If you search for the bzr identity of a branch, then you get a
- # single result with that branch.
- branch = self.factory.makeAnyBranch()
- self.factory.makeAnyBranch()
- search_results = self.collection.search(branch.bzr_identity)
- self.assertEqual([branch], list(search_results))
-
- def test_exact_match_bzr_identity_development_focus(self):
- # If you search for the development focus and it is set, you get a
- # single result with the development focus branch.
- fooix = self.factory.makeProduct(name='fooix')
- branch = self.factory.makeProductBranch(product=fooix)
- run_with_login(
- fooix.owner, setattr, fooix.development_focus,
- 'branch', branch)
- self.factory.makeAnyBranch()
- search_results = self.collection.search('lp://dev/fooix')
- self.assertEqual([branch], list(search_results))
-
- def test_bad_match_bzr_identity_development_focus(self):
- # If you search for the development focus for a project where one
- # isn't set, you get an empty search result.
- fooix = self.factory.makeProduct(name='fooix')
- self.factory.makeProductBranch(product=fooix)
- self.factory.makeAnyBranch()
- search_results = self.collection.search('lp://dev/fooix')
- self.assertEqual([], list(search_results))
-
- def test_bad_match_bzr_identity_no_project(self):
- # If you search for the development focus for a project where one
- # isn't set, you get an empty search result.
- self.factory.makeAnyBranch()
- search_results = self.collection.search('lp://dev/fooix')
- self.assertEqual([], list(search_results))
-
- def test_exact_match_url_trailing_slash(self):
- # Sometimes, users are inconsiderately unaware of our arbitrary
- # database restrictions and will put trailing slashes on their search
- # queries. Rather bravely, we refuse to explode in this case.
- branch = self.factory.makeAnyBranch()
- self.factory.makeAnyBranch()
- search_results = self.collection.search(branch.codebrowse_url() + '/')
- self.assertEqual([branch], list(search_results))
-
- def test_match_exact_branch_name(self):
- # search returns all branches with the same name as the search term.
- branch1 = self.factory.makeAnyBranch(name='foo')
- branch2 = self.factory.makeAnyBranch(name='foo')
- self.factory.makeAnyBranch()
- search_results = self.collection.search('foo')
- self.assertEqual(sorted([branch1, branch2]), sorted(search_results))
-
- def test_match_sub_branch_name(self):
- # search returns all branches which have a name of which the search
- # term is a substring.
- branch1 = self.factory.makeAnyBranch(name='afoo')
- branch2 = self.factory.makeAnyBranch(name='foob')
- self.factory.makeAnyBranch()
- search_results = self.collection.search('foo')
- self.assertEqual(sorted([branch1, branch2]), sorted(search_results))
-
- def test_match_exact_owner_name(self):
- # search returns all branches which have an owner with a name matching
- # the server.
- person = self.factory.makePerson(name='foo')
- branch1 = self.factory.makeAnyBranch(owner=person)
- branch2 = self.factory.makeAnyBranch(owner=person)
- self.factory.makeAnyBranch()
- search_results = self.collection.search('foo')
- self.assertEqual(sorted([branch1, branch2]), sorted(search_results))
-
- def test_match_sub_owner_name(self):
- # search returns all branches that have an owner name where the search
- # term is a substring of the owner name.
- person1 = self.factory.makePerson(name='foom')
- branch1 = self.factory.makeAnyBranch(owner=person1)
- person2 = self.factory.makePerson(name='afoo')
- branch2 = self.factory.makeAnyBranch(owner=person2)
- self.factory.makeAnyBranch()
- search_results = self.collection.search('foo')
- self.assertEqual(sorted([branch1, branch2]), sorted(search_results))
-
- def test_match_exact_product_name(self):
- # search returns all branches that have a product name where the
- # product name is the same as the search term.
- product = self.factory.makeProduct(name='foo')
- branch1 = self.factory.makeAnyBranch(product=product)
- branch2 = self.factory.makeAnyBranch(product=product)
- self.factory.makeAnyBranch()
- search_results = self.collection.search('foo')
- self.assertEqual(sorted([branch1, branch2]), sorted(search_results))
-
- def test_match_sub_product_name(self):
- # search returns all branches that have a product name where the
- # search terms is a substring of the product name.
- product1 = self.factory.makeProduct(name='foom')
- branch1 = self.factory.makeProductBranch(product=product1)
- product2 = self.factory.makeProduct(name='afoo')
- branch2 = self.factory.makeProductBranch(product=product2)
- self.factory.makeAnyBranch()
- search_results = self.collection.search('foo')
- self.assertEqual(sorted([branch1, branch2]), sorted(search_results))
-
- def test_match_sub_distro_name(self):
- # search returns all branches that have a distro name where the search
- # term is a substring of the distro name.
- branch = self.factory.makePackageBranch()
- self.factory.makeAnyBranch()
- search_term = branch.distribution.name[1:]
- search_results = self.collection.search(search_term)
- self.assertEqual([branch], list(search_results))
-
- def test_match_sub_distroseries_name(self):
- # search returns all branches that have a distro series with a name
- # that the search term is a substring of.
- branch = self.factory.makePackageBranch()
- self.factory.makeAnyBranch()
- search_term = branch.distroseries.name[1:]
- search_results = self.collection.search(search_term)
- self.assertEqual([branch], list(search_results))
-
- def test_match_sub_sourcepackage_name(self):
- # search returns all branches that have a source package with a name
- # that contains the search term.
- branch = self.factory.makePackageBranch()
- self.factory.makeAnyBranch()
- search_term = branch.sourcepackagename.name[1:]
- search_results = self.collection.search(search_term)
- self.assertEqual([branch], list(search_results))
-
- def test_dont_match_product_if_in_product(self):
- # If the container is restricted to the product, then we don't match
- # the product name.
- product = self.factory.makeProduct('foo')
- branch1 = self.factory.makeProductBranch(product=product, name='foo')
- self.factory.makeProductBranch(product=product, name='bar')
- search_results = self.collection.inProduct(product).search('foo')
- self.assertEqual([branch1], list(search_results))
-
-
class TestGetTeamsWithBranches(TestCaseWithFactory):
"""Test the BranchCollection.getTeamsWithBranches method."""
@@ -1403,3 +1129,58 @@
*DEFAULT_BRANCH_STATUS_IN_LISTING)
person_count, team_count = collection.ownerCounts()
self.assertEqual(1, person_count)
+
+
+class TestBranchSearch(TestCaseWithFactory):
+
+ layer = DatabaseFunctionalLayer
+
+ def test_search_branches_with_lp_url(self):
+ branch = self.factory.makeBranch()
+ lp_name = 'lp://dev/' + branch.unique_name
+ self.assertEqual([branch], search_branches(None, None, lp_name))
+
+ def test_search_branches_with_full_url(self):
+ branch = self.factory.makeBranch()
+ url = canonical_url(branch)
+ self.assertEqual([branch], search_branches(None, None, url))
+
+ def test_search_branches_with_unique_name(self):
+ branch = self.factory.makeBranch()
+ self.assertEqual(
+ [branch], search_branches(None, None, branch.unique_name))
+
+ def test_search_branches_anonymous_with_private_branch(self):
+ product = self.factory.makeProduct()
+ self.factory.makeBranch(
+ product=product, information_type=InformationType.USERDATA,
+ name='foobar')
+ self.assertEqual([], search_branches(product, None, 'foobar'))
+
+ def test_search_branches_user_with_hidden_private_branch(self):
+ product = self.factory.makeProduct()
+ user = self.factory.makePerson()
+ self.factory.makeBranch(
+ product=product, information_type=InformationType.USERDATA,
+ name='foobar')
+ self.assertEqual([], search_branches(product, user, 'foobar'))
+
+ def test_search_branches_branch_not_in_context(self):
+ other_product = self.factory.makeProduct()
+ self.factory.makeBranch(name='foobar')
+ self.assertEqual([], search_branches(other_product, None, 'foobar'))
+
+ def test_search_branches_private_branch(self):
+ product = self.factory.makeProduct()
+ owner = self.factory.makePerson()
+ branch = self.factory.makeBranch(
+ product=product, information_type=InformationType.USERDATA,
+ name='foobar', owner=owner)
+ self.assertEqual([branch], search_branches(product, owner, 'foobar'))
+
+ def test_search_branches_user_context(self):
+ owner = self.factory.makePerson()
+ branch = self.factory.makeBranch(owner=owner)
+ branch_2 = self.factory.makeBranch(owner=owner)
+ self.assertContentEqual(
+ [branch, branch_2], search_branches(owner, owner, ''))
=== modified file 'lib/lp/code/stories/feeds/xx-branch-atom.txt'
--- lib/lp/code/stories/feeds/xx-branch-atom.txt 2012-07-05 04:59:52 +0000
+++ lib/lp/code/stories/feeds/xx-branch-atom.txt 2013-02-12 05:42:24 +0000
@@ -99,16 +99,17 @@
If a branch is marked private it will not be displayed. The Landscape
developers team has two branches which are both private.
+
>>> from zope.component import getUtility
>>> from zope.security.proxy import removeSecurityProxy
>>> from lp.code.model.branch import Branch
>>> from lp.code.interfaces.branchcollection import IAllBranches
>>> from lp.registry.interfaces.person import IPersonSet
+ >>> from lp.registry.interfaces.product import IProductSet
>>> login(ANONYMOUS)
- >>> person_set = getUtility(IPersonSet)
- >>> landscape_team = person_set.getByName('landscape-developers')
- >>> test_user = person_set.getByEmail('test@xxxxxxxxxxxxx')
- >>> branches = getUtility(IAllBranches).relatedTo(landscape_team)
+ >>> test_user = getUtility(IPersonSet).getByEmail('test@xxxxxxxxxxxxx')
+ >>> landscape = getUtility(IProductSet)['landscape']
+ >>> branches = getUtility(IAllBranches).inProduct(landscape)
>>> branches = branches.visibleByUser(
... test_user).getBranches().order_by(Branch.id)
>>> for branch in branches:
=== modified file 'lib/lp/code/vocabularies/branch.py'
--- lib/lp/code/vocabularies/branch.py 2012-10-18 17:49:39 +0000
+++ lib/lp/code/vocabularies/branch.py 2013-02-12 05:42:24 +0000
@@ -1,9 +1,8 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Vocabularies that contain branches."""
-
__metaclass__ = type
__all__ = [
@@ -12,17 +11,20 @@
'HostedBranchRestrictedOnOwnerVocabulary',
]
+from storm.locals import Join
from zope.component import getUtility
from zope.interface import implements
from zope.schema.vocabulary import SimpleTerm
from lp.code.enums import BranchType
from lp.code.interfaces.branch import IBranch
-from lp.code.interfaces.branchcollection import IAllBranches
from lp.code.model.branch import Branch
+from lp.code.model.branchcollection import search_branches
+from lp.registry.enums import EXCLUSIVE_TEAM_POLICY
from lp.registry.interfaces.person import IPerson
from lp.registry.interfaces.product import IProduct
from lp.registry.interfaces.productseries import IProductSeries
+from lp.registry.model.person import Person
from lp.services.webapp.interfaces import ILaunchBag
from lp.services.webapp.vocabulary import (
CountableIterator,
@@ -31,12 +33,8 @@
)
-class BranchVocabularyBase(SQLObjectVocabularyBase):
- """A base class for Branch vocabularies.
-
- Override `BranchVocabularyBase._getCollection` to provide the collection
- of branches which make up the vocabulary.
- """
+class BranchVocabulary(SQLObjectVocabularyBase):
+ """A vocabulary for searching branches."""
implements(IHugeVocabulary)
@@ -56,64 +54,45 @@
return iter(search_results).next()
raise LookupError(token)
- def _getCollection(self):
- """Return the collection of branches the vocabulary searches.
-
- Subclasses MUST override and implement this.
- """
- raise NotImplementedError(self._getCollection)
-
- def searchForTerms(self, query=None, vocab_filter=None):
+ def searchForTerms(self, query=None, vocab_filter=None, extra_joins=[],
+ extra_clauses=[]):
"""See `IHugeVocabulary`."""
- logged_in_user = getUtility(ILaunchBag).user
- collection = self._getCollection().visibleByUser(logged_in_user)
- if query is None:
- branches = collection.getBranches(eager_load=False)
- else:
- branches = collection.search(query)
- return CountableIterator(branches.count(), branches, self.toTerm)
+ user = getUtility(ILaunchBag).user
+ branches = search_branches(
+ self.context, user, query, extra_joins=extra_joins,
+ extra_clauses=extra_clauses)
+ return CountableIterator(len(branches), branches, self.toTerm)
def __len__(self):
"""See `IVocabulary`."""
return self.search().count()
-class BranchVocabulary(BranchVocabularyBase):
- """A vocabulary for searching branches.
-
- The name and URL of the branch, the name of the product, and the
- name of the registrant of the branches is checked for the entered
- value.
- """
-
- def _getCollection(self):
- return getUtility(IAllBranches)
-
-
-class BranchRestrictedOnProductVocabulary(BranchVocabularyBase):
- """A vocabulary for searching branches restricted on product.
-
- The query entered checks the name or URL of the branch, or the
- name of the registrant of the branch.
- """
+class BranchRestrictedOnProductVocabulary(BranchVocabulary):
+ """A vocabulary for searching branches restricted on product."""
def __init__(self, context=None):
- BranchVocabularyBase.__init__(self, context)
+ super(BranchRestrictedOnProductVocabulary, self).__init__(context)
if IProduct.providedBy(self.context):
- self.product = self.context
+ self.context = context
elif IProductSeries.providedBy(self.context):
- self.product = self.context.product
+ self.context = context.product
elif IBranch.providedBy(self.context):
- self.product = self.context.product
+ self.context = context.product
else:
# An unexpected type.
raise AssertionError('Unexpected context type')
- def _getCollection(self):
- return getUtility(IAllBranches).inProduct(self.product).isExclusive()
-
-
-class HostedBranchRestrictedOnOwnerVocabulary(BranchVocabularyBase):
+ def searchForTerms(self, query=None, vocab_filter=None):
+ extra_joins = [Join(Person, Person.id == Branch.ownerID)]
+ extra_clauses = [
+ Person.membership_policy.is_in(EXCLUSIVE_TEAM_POLICY)]
+ return super(BranchRestrictedOnProductVocabulary, self).searchForTerms(
+ query, vocab_filter, extra_joins=extra_joins,
+ extra_clauses=extra_clauses)
+
+
+class HostedBranchRestrictedOnOwnerVocabulary(BranchVocabulary):
"""A vocabulary for hosted branches owned by the current user.
These are branches that the user either owns themselves or which are
@@ -123,11 +102,12 @@
def __init__(self, context=None):
"""Pass a Person as context, or anything else for the current user."""
super(HostedBranchRestrictedOnOwnerVocabulary, self).__init__(context)
- if IPerson.providedBy(self.context):
- self.user = context
- else:
- self.user = getUtility(ILaunchBag).user
+ if not IPerson.providedBy(self.context):
+ self.context = getUtility(ILaunchBag).user
- def _getCollection(self):
- owned_branches = getUtility(IAllBranches).ownedByTeamMember(self.user)
- return owned_branches.withBranchType(BranchType.HOSTED)
+ def searchForTerms(self, query=None, vocab_filter=None):
+ extra_clauses = [Branch.branch_type == BranchType.HOSTED]
+ return super(
+ HostedBranchRestrictedOnOwnerVocabulary, self).searchForTerms(
+ query, vocab_filter, extra_joins=[],
+ extra_clauses=extra_clauses)
=== modified file 'lib/lp/code/vocabularies/tests/branch.txt'
--- lib/lp/code/vocabularies/tests/branch.txt 2012-04-30 13:53:06 +0000
+++ lib/lp/code/vocabularies/tests/branch.txt 2013-02-12 05:42:24 +0000
@@ -32,16 +32,6 @@
~stevea/thunderbird/main
~vcs-imports/evolution/main
- >>> print_vocab_branches(branch_vocabulary, 'vcs-imports')
- ~vcs-imports/evolution/import
- ~vcs-imports/evolution/main
- ~vcs-imports/gnome-terminal/import
-
- >>> print_vocab_branches(branch_vocabulary, 'evolution')
- ~carlos/evolution/2.0
- ~vcs-imports/evolution/import
- ~vcs-imports/evolution/main
-
A search with the full branch unique name should also find the branch.
>>> print_vocab_branches(branch_vocabulary, '~name12/firefox/main')
@@ -107,9 +97,6 @@
>>> print_vocab_branches(branch_vocabulary, 'main')
~name12/gnome-terminal/main
- >>> print_vocab_branches(branch_vocabulary, 'vcs-imports')
- ~vcs-imports/gnome-terminal/import
-
If a full unique name is entered that has a different product, the
branch is not part of the vocabulary.
=== modified file 'lib/lp/code/vocabularies/tests/test_branch_vocabularies.py'
--- lib/lp/code/vocabularies/tests/test_branch_vocabularies.py 2012-10-18 17:49:39 +0000
+++ lib/lp/code/vocabularies/tests/test_branch_vocabularies.py 2013-02-12 05:42:24 +0000
@@ -1,11 +1,10 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Test the branch vocabularies."""
__metaclass__ = type
-from unittest import TestCase
from zope.component import getUtility
@@ -16,99 +15,36 @@
)
from lp.registry.enums import TeamMembershipPolicy
from lp.registry.interfaces.product import IProductSet
-from lp.testing import (
- ANONYMOUS,
- login,
- logout,
- )
-from lp.testing.factory import LaunchpadObjectFactory
+from lp.testing import TestCaseWithFactory
from lp.testing.layers import DatabaseFunctionalLayer
-class BranchVocabTestCase(TestCase):
- """A base class for the branch vocabulary test cases."""
- layer = DatabaseFunctionalLayer
-
- def setUp(self):
- # Set up the anonymous security interaction.
- login(ANONYMOUS)
-
- def tearDown(self):
- logout()
-
-
-class TestBranchVocabulary(BranchVocabTestCase):
+class TestBranchVocabulary(TestCaseWithFactory):
"""Test that the BranchVocabulary behaves as expected."""
+ layer = DatabaseFunctionalLayer
+
def setUp(self):
- BranchVocabTestCase.setUp(self)
+ super(TestBranchVocabulary, self).setUp()
self._createBranches()
self.vocab = BranchVocabulary(context=None)
def _createBranches(self):
- factory = LaunchpadObjectFactory()
- widget = factory.makeProduct(name='widget')
- sprocket = factory.makeProduct(name='sprocket')
- # Scotty's branches.
- scotty = factory.makePerson(name='scotty')
- factory.makeProductBranch(
+ widget = self.factory.makeProduct(name='widget')
+ sprocket = self.factory.makeProduct(name='sprocket')
+ scotty = self.factory.makePerson(name='scotty')
+ self.factory.makeProductBranch(
owner=scotty, product=widget, name='fizzbuzz')
- factory.makeProductBranch(
+ self.factory.makeProductBranch(
owner=scotty, product=widget, name='mountain')
- factory.makeProductBranch(
+ self.factory.makeProductBranch(
owner=scotty, product=sprocket, name='fizzbuzz')
- # Spotty's branches.
- spotty = factory.makePerson(name='spotty')
- factory.makeProductBranch(
- owner=spotty, product=widget, name='hill')
- factory.makeProductBranch(
- owner=spotty, product=widget, name='sprocket')
- # Sprocket's branches.
- sprocket_person = factory.makePerson(name='sprocket')
- factory.makeProductBranch(
- owner=sprocket_person, product=widget, name='foo')
def test_fizzbuzzBranches(self):
"""Return branches that match the string 'fizzbuzz'."""
results = self.vocab.searchForTerms('fizzbuzz')
expected = [
- u'~scotty/sprocket/fizzbuzz',
- u'~scotty/widget/fizzbuzz',
- ]
- branch_names = sorted([branch.token for branch in results])
- self.assertEqual(expected, branch_names)
-
- def test_widgetBranches(self):
- """Searches match the product name too."""
- results = self.vocab.searchForTerms('widget')
- expected = [
- u'~scotty/widget/fizzbuzz',
- u'~scotty/widget/mountain',
- u'~spotty/widget/hill',
- u'~spotty/widget/sprocket',
- u'~sprocket/widget/foo',
- ]
- branch_names = sorted([branch.token for branch in results])
- self.assertEqual(expected, branch_names)
-
- def test_spottyBranches(self):
- """Searches also match the registrant name."""
- results = self.vocab.searchForTerms('spotty')
- expected = [
- u'~spotty/widget/hill',
- u'~spotty/widget/sprocket',
- ]
- branch_names = sorted([branch.token for branch in results])
- self.assertEqual(expected, branch_names)
-
- def test_crossAttributeBranches(self):
- """The search checks name, product, and person."""
- results = self.vocab.searchForTerms('rocket')
- expected = [
- u'~scotty/sprocket/fizzbuzz',
- u'~spotty/widget/sprocket',
- u'~sprocket/widget/foo',
- ]
+ u'~scotty/sprocket/fizzbuzz', u'~scotty/widget/fizzbuzz']
branch_names = sorted([branch.token for branch in results])
self.assertEqual(expected, branch_names)
@@ -116,20 +52,15 @@
# If there is a single search result that matches, use that
# as the result.
term = self.vocab.getTermByToken('mountain')
- self.assertEqual(
- '~scotty/widget/mountain',
- term.value.unique_name)
+ self.assertEqual('~scotty/widget/mountain', term.value.unique_name)
def test_multipleQueryResult(self):
# If there are more than one search result, a LookupError is still
# raised.
- self.assertRaises(
- LookupError,
- self.vocab.getTermByToken,
- 'fizzbuzz')
-
-
-class TestRestrictedBranchVocabularyOnProduct(BranchVocabTestCase):
+ self.assertRaises(LookupError, self.vocab.getTermByToken, 'fizzbuzz')
+
+
+class TestRestrictedBranchVocabularyOnProduct(TestCaseWithFactory):
"""Test the BranchRestrictedOnProductVocabulary behaves as expected.
When a BranchRestrictedOnProductVocabulary is used with a product the
@@ -137,8 +68,10 @@
context.
"""
+ layer = DatabaseFunctionalLayer
+
def setUp(self):
- BranchVocabTestCase.setUp(self)
+ super(TestRestrictedBranchVocabularyOnProduct, self).setUp()
self._createBranches()
self.vocab = BranchRestrictedOnProductVocabulary(
context=self._getVocabRestriction())
@@ -148,18 +81,17 @@
return getUtility(IProductSet).getByName('widget')
def _createBranches(self):
- factory = LaunchpadObjectFactory()
- test_product = factory.makeProduct(name='widget')
- other_product = factory.makeProduct(name='sprocket')
- person = factory.makePerson(name='scotty')
- factory.makeProductBranch(
+ test_product = self.factory.makeProduct(name='widget')
+ other_product = self.factory.makeProduct(name='sprocket')
+ person = self.factory.makePerson(name='scotty')
+ self.factory.makeProductBranch(
owner=person, product=test_product, name='main')
- factory.makeProductBranch(
+ self.factory.makeProductBranch(
owner=person, product=test_product, name='mountain')
- factory.makeProductBranch(
+ self.factory.makeProductBranch(
owner=person, product=other_product, name='main')
- person = factory.makePerson(name='spotty')
- factory.makeProductBranch(
+ person = self.factory.makePerson(name='spotty')
+ self.factory.makeProductBranch(
owner=person, product=test_product, name='hill')
self.product = test_product
@@ -169,23 +101,7 @@
The result set should not show ~scotty/sprocket/main.
"""
results = self.vocab.searchForTerms('main')
- expected = [
- u'~scotty/widget/main',
- ]
- branch_names = sorted([branch.token for branch in results])
- self.assertEqual(expected, branch_names)
-
- def test_ownersBranches(self):
- """Look for branches owned by scotty.
-
- The result set should not show ~scotty/sprocket/main.
- """
- results = self.vocab.searchForTerms('scotty')
-
- expected = [
- u'~scotty/widget/main',
- u'~scotty/widget/mountain',
- ]
+ expected = [u'~scotty/widget/main']
branch_names = sorted([branch.token for branch in results])
self.assertEqual(expected, branch_names)
@@ -193,26 +109,20 @@
# If there is a single search result that matches, use that
# as the result.
term = self.vocab.getTermByToken('mountain')
- self.assertEqual(
- '~scotty/widget/mountain',
- term.value.unique_name)
+ self.assertEqual('~scotty/widget/mountain', term.value.unique_name)
def test_multipleQueryResult(self):
# If there are more than one search result, a LookupError is still
# raised.
- self.assertRaises(
- LookupError,
- self.vocab.getTermByToken,
- 'scotty')
+ self.assertRaises(LookupError, self.vocab.getTermByToken, 'scotty')
def test_does_not_contain_inclusive_teams(self):
- factory = LaunchpadObjectFactory()
- open_team = factory.makeTeam(name='open-team',
+ open_team = self.factory.makeTeam(name='open-team',
membership_policy=TeamMembershipPolicy.OPEN)
- delegated_team = factory.makeTeam(name='delegated-team',
+ delegated_team = self.factory.makeTeam(name='delegated-team',
membership_policy=TeamMembershipPolicy.DELEGATED)
for team in [open_team, delegated_team]:
- factory.makeProductBranch(
+ self.factory.makeProductBranch(
owner=team, product=self.product, name='mountain')
results = self.vocab.searchForTerms('mountain')
branch_names = sorted([branch.token for branch in results])
@@ -230,5 +140,4 @@
def _getVocabRestriction(self):
"""Restrict using a branch on widget."""
- return getUtility(IBranchLookup).getByUniqueName(
- '~spotty/widget/hill')
+ return getUtility(IBranchLookup).getByUniqueName('~spotty/widget/hill')
=== modified file 'lib/lp/registry/model/product.py'
--- lib/lp/registry/model/product.py 2013-02-07 06:10:38 +0000
+++ lib/lp/registry/model/product.py 2013-02-12 05:42:24 +0000
@@ -585,8 +585,6 @@
@property
def official_codehosting(self):
- # XXX Need to remove official_codehosting column from Product
- # table.
return self.development_focus.branch is not None
@property
=== modified file 'lib/lp/registry/services/sharingservice.py'
--- lib/lp/registry/services/sharingservice.py 2013-01-09 05:37:18 +0000
+++ lib/lp/registry/services/sharingservice.py 2013-02-12 05:42:24 +0000
@@ -35,7 +35,8 @@
from lp.blueprints.model.specification import Specification
from lp.bugs.interfaces.bugtask import IBugTaskSet
from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
-from lp.code.interfaces.branchcollection import IAllBranches
+from lp.code.model.branch import Branch
+from lp.code.model.branchcollection import search_branches
from lp.registry.enums import (
BranchSharingPolicy,
BugSharingPolicy,
@@ -217,10 +218,9 @@
# Load the branches.
branches = []
if branch_ids:
- all_branches = getUtility(IAllBranches)
- wanted_branches = all_branches.visibleByUser(user).withIds(
- *branch_ids)
- branches = list(wanted_branches.getBranches())
+ clauses = [Branch.id.is_in(branch_ids)]
+ branches = search_branches(
+ None, user, '', extra_clauses=clauses)
specifications = []
if specification_ids:
specifications = load(Specification, specification_ids)
@@ -331,10 +331,9 @@
# Load the branches.
visible_branches = []
if branches_by_id:
- all_branches = getUtility(IAllBranches)
- wanted_branches = all_branches.visibleByUser(person).withIds(
- *branches_by_id.keys())
- visible_branches = list(wanted_branches.getBranches())
+ clauses = [Branch.id.is_in(branches_by_id.keys())]
+ visible_branches = search_branches(
+ None, person, '', extra_clauses=clauses)
visible_specs = []
if specifications:
@@ -367,9 +366,9 @@
# Load the branches.
invisible_branches = []
if branches_by_id:
- all_branches = getUtility(IAllBranches)
- visible_branch_ids = all_branches.visibleByUser(person).withIds(
- *branches_by_id.keys()).getBranchIds()
+ clauses = [Branch.id.is_in(branches_by_id.keys())]
+ visible_branch_ids = [branch.id for branch in search_branches(
+ None, person, '', extra_clauses=clauses)]
invisible_branch_ids = (
set(branches_by_id.keys()).difference(visible_branch_ids))
invisible_branches = [
=== modified file 'lib/lp/services/webapp/configure.zcml'
--- lib/lp/services/webapp/configure.zcml 2012-09-28 07:11:24 +0000
+++ lib/lp/services/webapp/configure.zcml 2013-02-12 05:42:24 +0000
@@ -418,11 +418,11 @@
permission="zope.Public"
/>
- <!-- Define the widget used by fields that use BranchVocabularyBase. -->
+ <!-- Define the widget used by fields that use BranchVocabulary. -->
<view
type="zope.publisher.interfaces.browser.IBrowserRequest"
for="zope.schema.interfaces.IChoice
- lp.code.vocabularies.branch.BranchVocabularyBase"
+ lp.code.vocabularies.branch.BranchVocabulary"
provides="zope.app.form.interfaces.IInputWidget"
factory="lp.code.browser.widgets.branch.BranchPopupWidget"
permission="zope.Public"
Follow ups