def traverse(self, name): """Traverse the paths of a feed. If a query string is provided it is normalized. 'bugs' paths and persons ('~') are special cased. """ # Normalize the query string so caching is more effective. This is # done by simply sorting the entries. # XXX bac 20071019, we would like to normalize with respect to case # too but cannot due to a problem with the bug search requiring status # values to be of a particular case. See bug 154562. query_string = self.request.get('QUERY_STRING', '') fields = sorted(query_string.split('&')) normalized_query_string = '&'.join(fields) if query_string != normalized_query_string: # We must empty the traversal stack to prevent an error # when calling RedirectionView.publishTraverse(). self.request.setTraversalStack([]) target = "%s%s?%s" % (self.request.getApplicationURL(), self.request['PATH_INFO'], normalized_query_string) redirect = RedirectionView(target, self.request, 301) return redirect # Handle the two formats of urls: # http://feeds.launchpad.net/bugs/+bugs.atom?... # http://feeds.launchpad.net/bugs/1/bug.atom if name == 'bugs': stack = self.request.getTraversalStack() if len(stack) == 0: raise NotFound(self, '', self.request) bug_id = stack.pop() if bug_id.startswith('+'): if config.launchpad.is_bug_search_feed_active: return getUtility(IBugTaskSet) else: raise Unauthorized("Bug search feed deactivated") else: self.request.stepstogo.consume() return getUtility(IBugSet).getByNameOrID(bug_id) # Redirect to the canonical name before doing the lookup. if canonical_name(name) != name: return self.redirectSubTree(canonical_url(self.context) + canonical_name(name), status=301) try: if name.startswith('~'): # Handle persons and teams. # http://feeds.launchpad.net/~salgado/latest-bugs.html person = getUtility(IPersonSet).getByName(name[1:]) return person else: # Otherwise, handle products, projects, and distros return getUtility(IPillarNameSet)[name] except NotFoundError: raise NotFound(self, name, self.request)
def traverse(self, name): """Traverse the paths of a feed. If a query string is provided it is normalized. 'bugs' paths and persons ('~') are special cased. """ # Normalize the query string so caching is more effective. This is # done by simply sorting the entries. # XXX bac 20071019, we would like to normalize with respect to case # too but cannot due to a problem with the bug search requiring status # values to be of a particular case. See bug 154562. query_string = self.request.get('QUERY_STRING', '') fields = sorted(query_string.split('&')) normalized_query_string = '&'.join(fields) if query_string != normalized_query_string: # We must empty the traversal stack to prevent an error # when calling RedirectionView.publishTraverse(). self.request.setTraversalStack([]) target = "%s%s?%s" % (self.request.getApplicationURL(), self.request['PATH_INFO'], normalized_query_string) redirect = RedirectionView(target, self.request, 301) return redirect # Handle the two formats of urls: # http://feeds.launchpad.net/bugs/+bugs.atom?... # http://feeds.launchpad.net/bugs/1/bug.atom if name == 'bugs': stack = self.request.getTraversalStack() if len(stack) == 0: raise NotFound(self, '', self.request) bug_id = stack.pop() if bug_id.startswith('+'): if config.launchpad.is_bug_search_feed_active: return getUtility(IBugTaskSet) else: raise Unauthorized("Bug search feed deactivated") else: self.request.stepstogo.consume() return getUtility(IBugSet).getByNameOrID(bug_id) # Redirect to the canonical name before doing the lookup. if canonical_name(name) != name: return self.redirectSubTree( canonical_url(self.context) + canonical_name(name), status=301) try: if name.startswith('~'): # Handle persons and teams. # http://feeds.launchpad.net/~salgado/latest-bugs.html person = getUtility(IPersonSet).getByName(name[1:]) return person else: # Otherwise, handle products, projects, and distros return getUtility(IPillarNameSet)[name] except NotFoundError: raise NotFound(self, name, self.request)
def traverse(self, name): if name in self.stepto_utilities: return getUtility(self.stepto_utilities[name]) if name == '~': person = getUtility(ILaunchBag).user if person is None: raise Unauthorized() # Keep the context and the subtree so that # bugs.l.n/~/+assignedbugs goes to the person's canonical # assigned list. return self.redirectSubTree( canonical_url(self.context) + "~" + canonical_name(person.name), status=302) elif name.startswith('~'): # Allow traversal to ~foo for People if canonical_name(name) != name: # (for instance, uppercase username?) if self.request.method == 'POST': raise POSTToNonCanonicalURL return self.redirectSubTree( canonical_url(self.context) + canonical_name(name), status=301) else: person = getUtility(IPersonSet).getByName(name[1:]) if person is None: return person # Check to see if this is a team, and if so, whether the # logged in user is allowed to view the team, by virtue of # team membership or Launchpad administration. if (person.is_team and not check_permission('launchpad.LimitedView', person)): return None # Only admins are permitted to see suspended users. if person.account_status == AccountStatus.SUSPENDED: if not check_permission('launchpad.Moderate', person): raise GoneError( 'User is suspended: %s' % name) if person.account_status == AccountStatus.PLACEHOLDER: if not check_permission('launchpad.Moderate', person): return None return person # Dapper and Edgy shipped with https://launchpad.net/bazaar hard coded # into the Bazaar Launchpad plugin (part of Bazaar core). So in theory # we need to support this URL until 2011 (although I suspect the API # will break much sooner than that) or updates sent to # {dapper,edgy}-updates. Probably all irrelevant, as I suspect the # number of people using the plugin in edgy and dapper is 0. if name == 'bazaar' and IXMLRPCRequest.providedBy(self.request): return getUtility(IBazaarApplication) # account for common typing mistakes if canonical_name(name) != name: if self.request.method == 'POST': raise POSTToNonCanonicalURL return self.redirectSubTree( (canonical_url(self.context, request=self.request) + canonical_name(name)), status=301) pillar = getUtility(IPillarNameSet).getByName( name, ignore_inactive=False) if pillar is None: return None if IProduct.providedBy(pillar): if not pillar.active: # Emergency brake for public but inactive products: # These products should not be shown to ordinary users. # The root problem is that many views iterate over products, # inactive products included, and access attributes like # name, displayname or call canonical_url(product) -- # and finally throw the data away, if the product is # inactive. So we cannot make these attributes inaccessible # for inactive public products. On the other hand, we # require the permission launchpad.View to protect private # products. # This means that we cannot simply check if the current # user has the permission launchpad.View for an inactive # product. user = getUtility(ILaunchBag).user if user is None: return None user = IPersonRoles(user) if (not user.in_commercial_admin and not user.in_admin and not user.in_registry_experts): return None if check_permission('launchpad.LimitedView', pillar): if pillar.name != name: # This pillar was accessed through one of its aliases, so we # must redirect to its canonical URL. return self.redirectSubTree( canonical_url(pillar, self.request), status=301) return pillar return None
def traverse(self, name): if name in self.stepto_utilities: return getUtility(self.stepto_utilities[name]) if name == '~': person = getUtility(ILaunchBag).user if person is None: raise Unauthorized() # Keep the context and the subtree so that # bugs.l.n/~/+assignedbugs goes to the person's canonical # assigned list. return self.redirectSubTree( canonical_url(self.context) + "~" + canonical_name(person.name), status=302) elif name.startswith('~'): # Allow traversal to ~foo for People if canonical_name(name) != name: # (for instance, uppercase username?) if self.request.method == 'POST': raise POSTToNonCanonicalURL return self.redirectSubTree( canonical_url(self.context) + canonical_name(name), status=301) else: person = getUtility(IPersonSet).getByName(name[1:]) if person is None: return person # Check to see if this is a team, and if so, whether the # logged in user is allowed to view the team, by virtue of # team membership or Launchpad administration. if (person.is_team and not check_permission('launchpad.LimitedView', person)): raise NotFound(self.context, name) # Only admins are permitted to see suspended users. if person.account_status == AccountStatus.SUSPENDED: if not check_permission('launchpad.Moderate', person): raise GoneError( 'User is suspended: %s' % name) return person # Dapper and Edgy shipped with https://launchpad.net/bazaar hard coded # into the Bazaar Launchpad plugin (part of Bazaar core). So in theory # we need to support this URL until 2011 (although I suspect the API # will break much sooner than that) or updates sent to # {dapper,edgy}-updates. Probably all irrelevant, as I suspect the # number of people using the plugin in edgy and dapper is 0. if name == 'bazaar' and IXMLRPCRequest.providedBy(self.request): return getUtility(IBazaarApplication) # account for common typing mistakes if canonical_name(name) != name: if self.request.method == 'POST': raise POSTToNonCanonicalURL return self.redirectSubTree( (canonical_url(self.context, request=self.request) + canonical_name(name)), status=301) pillar = getUtility(IPillarNameSet).getByName( name, ignore_inactive=False) if pillar is None: return None if IProduct.providedBy(pillar): if not pillar.active: # Emergency brake for public but inactive products: # These products should not be shown to ordinary users. # The root problem is that many views iterate over products, # inactive products included, and access attributes like # name, displayname or call canonical_url(product) -- # and finally throw the data away, if the product is # inactive. So we cannot make these attributes inaccessible # for inactive public products. On the other hand, we # require the permission launchpad.View to protect private # products. # This means that we cannot simply check if the current # user has the permission launchpad.View for an inactive # product. user = getUtility(ILaunchBag).user if user is None: return None user = IPersonRoles(user) if (not user.in_commercial_admin and not user.in_admin and not user.in_registry_experts): return None if check_permission('launchpad.LimitedView', pillar): if pillar.name != name: # This pillar was accessed through one of its aliases, so we # must redirect to its canonical URL. return self.redirectSubTree( canonical_url(pillar, self.request), status=301) return pillar return None