def subscriber_data(self): """Return subscriber_ids in a form suitable for JavaScript use.""" bug = IBug(self.context) data = self.direct_subscriber_data(bug) others = list(bug.getIndirectSubscribers()) # If we have made it to here then the logged in user can see the # bug, hence they can see any indirect subscribers. include_private = self.user is not None if include_private: precache_permission_for_objects( self.request, 'launchpad.LimitedView', others) for person in others: if person == self.user: # Skip the current user viewing the page, continue if not include_private and person.private: # Do not include private teams if there's no logged in user. continue subscriber = { 'name': person.name, 'display_name': person.displayname, 'web_link': canonical_url(person, rootsite='mainsite'), 'self_link': absoluteURL(person, self.api_request), 'is_team': person.is_team, 'can_edit': False, } record = { 'subscriber': subscriber, 'subscription_level': 'Maybe', } data.append(record) return data
def sorted_subscriptions(self): """Get the list of subscriptions to the specification. The list is sorted such that subscriptions you can unsubscribe appear before all other subscriptions. """ can_unsubscribe = [] cannot_unsubscribe = [] subscribers = [] for subscription in self.context.subscriptions: subscribers.append(subscription.person) if subscription.person == self.user: can_unsubscribe = [subscription] + can_unsubscribe elif subscription.canBeUnsubscribedByUser(self.user): can_unsubscribe.append(subscription) else: cannot_unsubscribe.append(subscription) # Cache permission so private subscribers can be viewed. # The security adaptor will do the job also but we don't want or need # the expense of running several complex SQL queries. precache_permission_for_objects(self.request, 'launchpad.LimitedView', subscribers) sorted_subscriptions = can_unsubscribe + cannot_unsubscribe return sorted_subscriptions
def subscriptions(self): """Return a decorated list of branch subscriptions.""" # Cache permissions so private subscribers can be rendered. # The security adaptor will do the job also but we don't want or need # the expense of running several complex SQL queries. subscriptions = list(self.context.subscriptions) person_ids = [sub.personID for sub in subscriptions] list( getUtility(IPersonSet).getPrecachedPersonsFromIDs( person_ids, need_validity=True)) if self.user is not None: subscribers = [ subscription.person for subscription in subscriptions ] precache_permission_for_objects(self.request, "launchpad.LimitedView", subscribers) visible_subscriptions = [ subscription for subscription in subscriptions if check_permission('launchpad.LimitedView', subscription.person) ] return sorted(visible_subscriptions, key=lambda subscription: subscription.person.displayname)
def sorted_subscriptions(self): """Get the list of subscriptions to the specification. The list is sorted such that subscriptions you can unsubscribe appear before all other subscriptions. """ can_unsubscribe = [] cannot_unsubscribe = [] subscribers = [] for subscription in self.context.subscriptions: subscribers.append(subscription.person) if subscription.person == self.user: can_unsubscribe = [subscription] + can_unsubscribe elif subscription.canBeUnsubscribedByUser(self.user): can_unsubscribe.append(subscription) else: cannot_unsubscribe.append(subscription) # Cache permission so private subscribers can be viewed. # The security adaptor will do the job also but we don't want or need # the expense of running several complex SQL queries. precache_permission_for_objects( self.request, 'launchpad.LimitedView', subscribers) sorted_subscriptions = can_unsubscribe + cannot_unsubscribe return sorted_subscriptions
def _precacheViewPermissions(self, branches): """Precache the launchpad.View permissions on the branches.""" # XXX: TimPenhey 2009-06-08 bug=324546 # Until there is an API to do this nicely, shove the launchpad.view # permission into the request cache directly. precache_permission_for_objects( self.request, 'launchpad.View', branches) return branches
def _precacheViewPermissions(self, branches): """Precache the launchpad.View permissions on the branches.""" # XXX: TimPenhey 2009-06-08 bug=324546 # Until there is an API to do this nicely, shove the launchpad.view # permission into the request cache directly. precache_permission_for_objects(self.request, 'launchpad.View', branches) return branches
def eager_load(rows): subscriptions = map(itemgetter(0), rows) precache_permission_for_objects(None, 'launchpad.View', subscriptions) archives = load_related(Archive, subscriptions, ['archive_id']) list( getUtility(IPersonSet).getPrecachedPersonsFromIDs( [archive.ownerID for archive in archives], need_validity=True))
def test_authorized_kw_arg(self): # Method invocation with context being a kw argument. bar = Object() request = LaunchpadTestRequest() login(ANONYMOUS, request) precache_permission_for_objects(request, 'launchpad.Edit', [bar]) obj_to_invoke = AvailableWithPermissionObject() foo = Object() obj_to_invoke.test_function_bar(foo=foo, bar=bar)
def test_default_request(self): # If no request is provided, the current interaction is used. class Boring(object): """A boring, but weakref-able object.""" obj = Boring() request = LaunchpadTestRequest() login(ANONYMOUS, request) precache_permission_for_objects(None, 'launchpad.View', [obj]) self.assertTrue(check_permission('launchpad.View', obj))
def expose_user_administered_teams_to_js(request, user, context, absoluteURL=absoluteURL): """Make the list of teams the user administers available to JavaScript.""" # XXX: Robert Collins workaround multiple calls making this cause # timeouts: see bug 788510. objects = IJSONRequestCache(request).objects if 'administratedTeams' in objects: return info = [] api_request = IWebServiceClientRequest(request) is_distro = IDistribution.providedBy(context) if is_distro: # If the context is a distro AND a bug supervisor is set then we only # allow subscriptions from members of the bug supervisor team. bug_supervisor = context.bug_supervisor else: bug_supervisor = None if user is not None: administrated_teams = set(user.administrated_teams) if administrated_teams: # Get this only if we need to. membership = set(user.teams_participated_in) # Only consider teams the user is both in and administers: # If the user is not a member of the team itself, then # skip it, because structural subscriptions and their # filters can only be edited by the subscriber. # This can happen if the user is an owner but not a member. administers_and_in = membership.intersection(administrated_teams) list( getUtility(IPersonSet).getPrecachedPersonsFromIDs( [team.id for team in administers_and_in], need_preferred_email=True)) # If the requester is the user, they're at least an admin in # all of these teams. Precache launchpad.(Limited)View so we # can see the necessary attributes. current_user = IPerson(get_current_principal(), None) if current_user is not None and user == current_user: for perm in ('launchpad.View', 'launchpad.LimitedView'): precache_permission_for_objects(None, perm, administers_and_in) for team in sorted(administers_and_in, key=attrgetter('name')): if (bug_supervisor is not None and not team.inTeam(bug_supervisor)): continue info.append({ 'has_preferredemail': team.preferredemail is not None, 'link': absoluteURL(team, api_request), 'title': team.unique_displayname, 'url': canonical_url(team), }) objects['administratedTeams'] = info
def _make_formatter(self, cache_permission=False): # Helper to create the formatter and optionally cache the permission. formatter = getAdapter(self.team, IPathAdapter, 'fmt') clear_cache() request = LaunchpadTestRequest() any_person = self.factory.makePerson() if cache_permission: login_person(any_person, request) precache_permission_for_objects( request, 'launchpad.LimitedView', [self.team]) return formatter, request, any_person
def initialize(self): # If we have made it to here then the logged in user can see the # bug, hence they can see any assignees and subscribers. # The security adaptor will do the job also but we don't want or need # the expense of running several complex SQL queries. authorised_people = [] for task in self.bugtasks: if task.assignee is not None: authorised_people.append(task.assignee) authorised_people.extend(self.subscribers) precache_permission_for_objects( self.request, 'launchpad.LimitedView', authorised_people)
def test_precaching_permissions(self): # The precache_permission_for_objects function updates the security # policy cache for the permission specified. class Boring(object): """A boring, but weakref-able object.""" objects = [Boring(), Boring()] request = LaunchpadTestRequest() login(ANONYMOUS, request) precache_permission_for_objects(request, 'launchpad.View', objects) # Confirm that the objects have the permission set. self.assertTrue(check_permission('launchpad.View', objects[0])) self.assertTrue(check_permission('launchpad.View', objects[1]))
def expose_user_administered_teams_to_js(request, user, context, absoluteURL=absoluteURL): """Make the list of teams the user administers available to JavaScript.""" # XXX: Robert Collins workaround multiple calls making this cause # timeouts: see bug 788510. objects = IJSONRequestCache(request).objects if 'administratedTeams' in objects: return info = [] api_request = IWebServiceClientRequest(request) is_distro = IDistribution.providedBy(context) if is_distro: # If the context is a distro AND a bug supervisor is set then we only # allow subscriptions from members of the bug supervisor team. bug_supervisor = context.bug_supervisor else: bug_supervisor = None if user is not None: administrated_teams = set(user.administrated_teams) if administrated_teams: # Get this only if we need to. membership = set(user.teams_participated_in) # Only consider teams the user is both in and administers: # If the user is not a member of the team itself, then # skip it, because structural subscriptions and their # filters can only be edited by the subscriber. # This can happen if the user is an owner but not a member. administers_and_in = membership.intersection(administrated_teams) list(getUtility(IPersonSet).getPrecachedPersonsFromIDs( [team.id for team in administers_and_in], need_preferred_email=True)) # If the requester is the user, they're at least an admin in # all of these teams. Precache launchpad.(Limited)View so we # can see the necessary attributes. current_user = IPerson(get_current_principal(), None) if current_user is not None and user == current_user: for perm in ('launchpad.View', 'launchpad.LimitedView'): precache_permission_for_objects( None, perm, administers_and_in) for team in administers_and_in: if (bug_supervisor is not None and not team.inTeam(bug_supervisor)): continue info.append({ 'has_preferredemail': team.preferredemail is not None, 'link': absoluteURL(team, api_request), 'title': team.title, 'url': canonical_url(team), }) objects['administratedTeams'] = info
def initialize(self): super(BranchView, self).initialize() self.branch = self.context self.notices = [] # Cache permission so private team owner can be rendered. # The security adaptor will do the job also but we don't want or need # the expense of running several complex SQL queries. authorised_people = [self.branch.owner] if self.user is not None: precache_permission_for_objects( self.request, "launchpad.LimitedView", authorised_people) # Replace our context with a decorated branch, if it is not already # decorated. if not isinstance(self.context, DecoratedBranch): self.context = DecoratedBranch(self.context)
def test_limitedView_visible_attributes(self): """Users with LimitedView can know identifying information like name, displayname, and unique_name, but cannot know other information like team members. """ some_person = self.factory.makePerson() request = LaunchpadTestRequest() # First login as a person who has limitedView permission. precache_permission_for_objects( request, 'launchpad.LimitedView', [self.priv_team]) login_person(some_person, participation=request) self.assertEqual('priv-team', self.priv_team.name) self.assertEqual('Priv Team', self.priv_team.displayname) self.assertEqual( 'Priv Team (priv-team)', self.priv_team.unique_displayname) self.assertIsNone(self.priv_team.icon) self.assertRaises(Unauthorized, getattr, self.priv_team, 'allmembers')
def test_limitedView_visible_attributes(self): """Users with LimitedView can know identifying information like name, displayname, and unique_name, but cannot know other information like team members. """ some_person = self.factory.makePerson() request = LaunchpadTestRequest() # First login as a person who has limitedView permission. precache_permission_for_objects(request, 'launchpad.LimitedView', [self.priv_team]) login_person(some_person, participation=request) self.assertEqual('priv-team', self.priv_team.name) self.assertEqual('Priv Team', self.priv_team.displayname) self.assertEqual('Priv Team (priv-team)', self.priv_team.unique_displayname) self.assertIsNone(self.priv_team.icon) self.assertRaises(Unauthorized, getattr, self.priv_team, 'allmembers')
def _bugtasks(self): """The list of non-conjoined bugtasks targeted to this milestone.""" # Put the results in a list so that iterating over it multiple # times in this method does not make multiple queries. non_conjoined_slaves = self.context.bugtasks(self.user) # Checking bug permissions is expensive. We know from the query that # the user has at least launchpad.View on the bugtasks and their bugs. # NB: this is in principle unneeded due to injection of permission in # the model layer now. precache_permission_for_objects( self.request, 'launchpad.View', non_conjoined_slaves) precache_permission_for_objects( self.request, 'launchpad.View', [task.bug for task in non_conjoined_slaves]) # We want the assignees loaded as we show them in the milestone home # page. list(getUtility(IPersonSet).getPrecachedPersonsFromIDs( [bug.assigneeID for bug in non_conjoined_slaves], need_validity=True)) return non_conjoined_slaves
def _bugtasks(self): """The list of non-conjoined bugtasks targeted to this milestone.""" # Put the results in a list so that iterating over it multiple # times in this method does not make multiple queries. non_conjoined_slaves = self.context.bugtasks(self.user) # Checking bug permissions is expensive. We know from the query that # the user has at least launchpad.View on the bugtasks and their bugs. # NB: this is in principle unneeded due to injection of permission in # the model layer now. precache_permission_for_objects(self.request, 'launchpad.View', non_conjoined_slaves) precache_permission_for_objects( self.request, 'launchpad.View', [task.bug for task in non_conjoined_slaves]) # We want the assignees loaded as we show them in the milestone home # page. list( getUtility(IPersonSet).getPrecachedPersonsFromIDs( [bug.assigneeID for bug in non_conjoined_slaves], need_validity=True)) return non_conjoined_slaves
def direct_subscriber_data(self, bug): """Get the direct subscriber data. This method is isolated from the subscriber_data_js so that query count testing can be done accurately and robustly. """ data = [] details = list(bug.getDirectSubscribersWithDetails()) for person, subscribed_by, subscription in details: can_edit = subscription.canBeUnsubscribedByUser(self.user) if person == self.user: # Skip the current user viewing the page. continue if self.user is None and person.private: # Do not include private teams if there's no logged in user. continue # If we have made it to here then the logged in user can see the # bug, hence they can see any subscribers. # The security adaptor will do the job also but we don't want or # need the expense of running several complex SQL queries. precache_permission_for_objects(self.request, 'launchpad.LimitedView', [person]) subscriber = { 'name': person.name, 'display_name': person.displayname, 'web_link': canonical_url(person, rootsite='mainsite'), 'self_link': absoluteURL(person, self.api_request), 'is_team': person.is_team, 'can_edit': can_edit, 'display_subscribed_by': subscription.display_subscribed_by, } record = { 'subscriber': subscriber, 'subscription_level': str(removeSecurityProxy(subscription.bug_notification_level)), } data.append(record) return data
def subscriptions_with_tokens(self): """Return all the persons archive subscriptions with the token for each. The result is formatted as a list of dicts to make the TALS code cleaner. """ subscriber_set = getUtility(IArchiveSubscriberSet) subs_with_tokens = subscriber_set.getBySubscriberWithActiveToken( self.context) subscriptions = map(itemgetter(0), subs_with_tokens) precache_permission_for_objects(None, 'launchpad.View', subscriptions) archives = load_related(Archive, subscriptions, ['archive_id']) list( getUtility(IPersonSet).getPrecachedPersonsFromIDs( [archive.ownerID for archive in archives], need_validity=True)) for archive in archives: get_property_cache(archive)._known_subscribers = [self.user] # Turn the result set into a list of dicts so it can be easily # accessed in TAL. Note that we need to ensure that only one # PersonalArchiveSubscription is included for each archive, # as the person might have participation in multiple # subscriptions (via different teams). unique_archives = set() personal_subscription_tokens = [] for subscription, token in subs_with_tokens: if subscription.archive in unique_archives: continue unique_archives.add(subscription.archive) personal_subscription = PersonalArchiveSubscription( self.context, subscription.archive) personal_subscription_tokens.append({ 'subscription': personal_subscription, 'token': token }) return personal_subscription_tokens
def subscriptions(self): """Return a decorated list of branch subscriptions.""" # Cache permissions so private subscribers can be rendered. # The security adaptor will do the job also but we don't want or need # the expense of running several complex SQL queries. person_ids = [sub.personID for sub in self.context.subscriptions] list(getUtility(IPersonSet).getPrecachedPersonsFromIDs( person_ids, need_validity=True)) if self.user is not None: subscribers = [ subscription.person for subscription in self.context.subscriptions] precache_permission_for_objects( self.request, "launchpad.LimitedView", subscribers) visible_subscriptions = [ subscription for subscription in self.context.subscriptions if check_permission('launchpad.LimitedView', subscription.person)] return sorted( visible_subscriptions, key=lambda subscription: subscription.person.displayname)
def direct_subscriber_data(self, bug): """Get the direct subscriber data. This method is isolated from the subscriber_data_js so that query count testing can be done accurately and robustly. """ data = [] details = list(bug.getDirectSubscribersWithDetails()) for person, subscribed_by, subscription in details: can_edit = subscription.canBeUnsubscribedByUser(self.user) if person == self.user: # Skip the current user viewing the page. continue if self.user is None and person.private: # Do not include private teams if there's no logged in user. continue # If we have made it to here then the logged in user can see the # bug, hence they can see any subscribers. # The security adaptor will do the job also but we don't want or # need the expense of running several complex SQL queries. precache_permission_for_objects( self.request, 'launchpad.LimitedView', [person]) subscriber = { 'name': person.name, 'display_name': person.displayname, 'web_link': canonical_url(person, rootsite='mainsite'), 'self_link': absoluteURL(person, self.api_request), 'is_team': person.is_team, 'can_edit': can_edit, 'display_subscribed_by': subscription.display_subscribed_by, } record = { 'subscriber': subscriber, 'subscription_level': str( removeSecurityProxy(subscription.bug_notification_level)), } data.append(record) return data
def subscriptions_with_tokens(self): """Return all the persons archive subscriptions with the token for each. The result is formatted as a list of dicts to make the TALS code cleaner. """ subscriber_set = getUtility(IArchiveSubscriberSet) subs_with_tokens = subscriber_set.getBySubscriberWithActiveToken(self.context) subscriptions = map(itemgetter(0), subs_with_tokens) precache_permission_for_objects(None, "launchpad.View", subscriptions) archives = load_related(Archive, subscriptions, ["archive_id"]) list( getUtility(IPersonSet).getPrecachedPersonsFromIDs( [archive.ownerID for archive in archives], need_validity=True ) ) for archive in archives: get_property_cache(archive)._known_subscribers = [self.user] # Turn the result set into a list of dicts so it can be easily # accessed in TAL. Note that we need to ensure that only one # PersonalArchiveSubscription is included for each archive, # as the person might have participation in multiple # subscriptions (via different teams). unique_archives = set() personal_subscription_tokens = [] for subscription, token in subs_with_tokens: if subscription.archive in unique_archives: continue unique_archives.add(subscription.archive) personal_subscription = PersonalArchiveSubscription(self.context, subscription.archive) personal_subscription_tokens.append({"subscription": personal_subscription, "token": token}) return personal_subscription_tokens