def test_data_team_subscription_member_looks(self): # For a team subscription, subscriber_data_js has can_edit # set to true for team member. bug = self._makeBugWithNoSubscribers() member = self.factory.makePerson() teamowner = self.factory.makePerson(name="team-owner", displayname="Team Owner") subscriber = self.factory.makeTeam(name='team', displayname='Team Name', owner=teamowner, members=[member]) with person_logged_in(subscriber.teamowner): bug.subscribe(subscriber, subscriber.teamowner, level=BugNotificationLevel.LIFECYCLE) harness = LaunchpadFormHarness(bug, BugPortletSubscribersWithDetails) api_request = IWebServiceClientRequest(harness.request) expected_result = { 'subscriber': { 'name': 'team', 'display_name': 'Team Name', 'is_team': True, 'can_edit': True, 'web_link': canonical_url(subscriber), 'self_link': absoluteURL(subscriber, api_request), 'display_subscribed_by': \ 'Subscribed by Team Owner (team-owner)', }, 'subscription_level': "Lifecycle", } with person_logged_in(subscriber.teamowner): self.assertEqual(dumps([expected_result]), harness.view.subscriber_data_js)
def test_data_subscription_lp_admin(self): # For a subscription, subscriber_data_js has can_edit # set to true for a Launchpad admin. question = self._makeQuestionWithNoSubscribers() member = self.factory.makePerson() subscriber = self.factory.makePerson(name='user', displayname='Subscriber Name') with person_logged_in(member): question.subscribe(subscriber, subscriber) view = create_view(question, '+portlet-subscribers-details') api_request = IWebServiceClientRequest(view.request) expected_result = { 'subscriber': { 'name': 'user', 'display_name': 'Subscriber Name', 'is_team': False, 'can_edit': True, 'web_link': canonical_url(subscriber), 'self_link': absoluteURL(subscriber, api_request) }, 'subscription_level': "Direct", } # Login as admin admin = getUtility(IPersonSet).find(ADMIN_EMAIL).any() with person_logged_in(admin): self.assertEqual(dumps([expected_result]), view.subscriber_data_js)
def test_data_person_subscription(self): # subscriber_data_js returns JSON string of a list # containing all subscriber information needed for # subscribers_list.js subscribers loading. bug = self._makeBugWithNoSubscribers() subscriber = self.factory.makePerson(name='user', displayname='Subscriber Name') with person_logged_in(subscriber): bug.subscribe(subscriber, subscriber, level=BugNotificationLevel.LIFECYCLE) harness = LaunchpadFormHarness(bug, BugPortletSubscribersWithDetails) api_request = IWebServiceClientRequest(harness.request) expected_result = { 'subscriber': { 'name': 'user', 'display_name': 'Subscriber Name', 'is_team': False, 'can_edit': False, 'web_link': canonical_url(subscriber), 'self_link': absoluteURL(subscriber, api_request), 'display_subscribed_by': 'Self-subscribed', }, 'subscription_level': "Lifecycle", } self.assertEqual(dumps([expected_result]), harness.view.subscriber_data_js)
def test_data_team_subscription(self): # For a team subscription, subscriber_data_js has is_team set # to true. question = self._makeQuestionWithNoSubscribers() teamowner = self.factory.makePerson(name="team-owner", displayname="Team Owner") subscriber = self.factory.makeTeam(name='team', displayname='Team Name', owner=teamowner) with person_logged_in(subscriber.teamowner): question.subscribe(subscriber, subscriber.teamowner) view = create_view(question, '+portlet-subscribers-details') api_request = IWebServiceClientRequest(view.request) expected_result = { 'subscriber': { 'name': 'team', 'display_name': 'Team Name', 'is_team': True, 'can_edit': False, 'web_link': canonical_url(subscriber), 'self_link': absoluteURL(subscriber, api_request) }, 'subscription_level': "Direct", } self.assertEqual(dumps([expected_result]), view.subscriber_data_js)
def test_data_team_subscription_member_looks(self): # For a team subscription, answercontact_data_js has can_edit # set to true for team member. question = self.factory.makeQuestion() member = self.factory.makePerson() teamowner = self.factory.makePerson( name="team-owner", displayname="Team Owner") contact = self.factory.makeTeam( name='team', displayname='Team Name', owner=teamowner, members=[member]) contact.addLanguage(getUtility(ILanguageSet)['en']) with person_logged_in(contact.teamowner): question.target.addAnswerContact(contact, contact.teamowner) view = create_view(question.target, '+portlet-answercontacts-details') api_request = IWebServiceClientRequest(view.request) expected_result = { 'subscriber': { 'name': 'team', 'display_name': 'Team Name', 'is_team': True, 'can_edit': True, 'web_link': canonical_url(contact), 'self_link': absoluteURL(contact, api_request) } } with person_logged_in(contact.teamowner): self.assertEqual( dumps([expected_result]), view.answercontact_data_js)
def test_data_person_answercontact(self): # answercontact_data_js returns JSON string of a list # containing all contact information needed for # subscribers_list.js loading. question = self.factory.makeQuestion() contact = self.factory.makePerson( name='user', displayname='Contact Name') contact.addLanguage(getUtility(ILanguageSet)['en']) with person_logged_in(contact): question.target.addAnswerContact(contact, contact) view = create_view(question.target, '+portlet-answercontacts-details') api_request = IWebServiceClientRequest(view.request) expected_result = { 'subscriber': { 'name': 'user', 'display_name': 'Contact Name', 'is_team': False, 'can_edit': False, 'web_link': canonical_url(contact), 'self_link': absoluteURL(contact, api_request) } } self.assertEqual( dumps([expected_result]), view.answercontact_data_js)
def test_team_admin_subscription(self): # Make a team subscription where the user is an admin, and see what # we record. user = self.factory.makePerson() target = self.factory.makeProduct() request = LaunchpadTestRequest() team = self.factory.makeTeam() with person_logged_in(team.teamowner): team.addMember(user, team.teamowner, status=TeamMembershipStatus.ADMIN) sub = target.addBugSubscription(team, team.teamowner) expose_user_subscriptions_to_js(user, [sub], request) info = IJSONRequestCache(request).objects['subscription_info'] self.assertEqual(len(info), 1) # One target. target_info = info[0] self.assertEqual(target_info['target_title'], target.title) self.assertEqual(target_info['target_url'], canonical_url(target, rootsite='mainsite')) self.assertEqual(len(target_info['filters']), 1) # One filter. filter_info = target_info['filters'][0] self.assertEqual(filter_info['filter'], sub.bug_filters[0]) self.assertTrue(filter_info['subscriber_is_team']) self.assertTrue(filter_info['user_is_team_admin']) self.assertTrue(filter_info['can_mute']) self.assertFalse(filter_info['is_muted']) self.assertEqual(filter_info['subscriber_title'], team.title) self.assertEqual(filter_info['subscriber_link'], absoluteURL(team, IWebServiceClientRequest(request))) self.assertEqual(filter_info['subscriber_url'], canonical_url(team, rootsite='mainsite'))
def test_data_target_owner_answercontact_looks(self): # Answercontact_data_js has can_edit set to true for target owner. distro = self.factory.makeDistribution() question = self.factory.makeQuestion(target=distro) contact = self.factory.makePerson( name='user', displayname='Contact Name') contact.addLanguage(getUtility(ILanguageSet)['en']) with person_logged_in(contact): question.target.addAnswerContact(contact, contact) view = create_view(question.target, '+portlet-answercontacts-details') api_request = IWebServiceClientRequest(view.request) expected_result = { 'subscriber': { 'name': 'user', 'display_name': 'Contact Name', 'is_team': False, 'can_edit': True, 'web_link': canonical_url(contact), 'self_link': absoluteURL(contact, api_request) } } with person_logged_in(distro.owner): self.assertEqual( dumps([expected_result]), view.answercontact_data_js)
def test_data_subscription_lp_admin(self): # For a subscription, answercontact_data_js has can_edit # set to true for a Launchpad admin. question = self.factory.makeQuestion() member = self.factory.makePerson() contact = self.factory.makePerson( name='user', displayname='Contact Name') contact.addLanguage(getUtility(ILanguageSet)['en']) with person_logged_in(member): question.target.addAnswerContact(contact, contact) view = create_view(question.target, '+portlet-answercontacts-details') api_request = IWebServiceClientRequest(view.request) expected_result = { 'subscriber': { 'name': 'user', 'display_name': 'Contact Name', 'is_team': False, 'can_edit': True, 'web_link': canonical_url(contact), 'self_link': absoluteURL(contact, api_request) } } # Login as admin admin = getUtility(IPersonSet).find(ADMIN_EMAIL).any() with person_logged_in(admin): self.assertEqual( dumps([expected_result]), view.answercontact_data_js)
def test_data_person_subscription_subscriber(self): # For a subscription, subscriber_data_js has can_edit # set to true for the subscriber. bug = self._makeBugWithNoSubscribers() subscriber = self.factory.makePerson(name='user', displayname='Subscriber Name') subscribed_by = self.factory.makePerson(name='someone', displayname='Someone') with person_logged_in(subscriber): bug.subscribe(subscriber, subscribed_by, level=BugNotificationLevel.LIFECYCLE) harness = LaunchpadFormHarness(bug, BugPortletSubscribersWithDetails) api_request = IWebServiceClientRequest(harness.request) expected_result = { 'subscriber': { 'name': 'user', 'display_name': 'Subscriber Name', 'is_team': False, 'can_edit': True, 'web_link': canonical_url(subscriber), 'self_link': absoluteURL(subscriber, api_request), 'display_subscribed_by': 'Subscribed by Someone (someone)', }, 'subscription_level': "Lifecycle", } with person_logged_in(subscribed_by): self.assertEqual(dumps([expected_result]), harness.view.subscriber_data_js)
def test_data_subscription_lp_admin(self): # For a subscription, subscriber_data_js has can_edit # set to true for a Launchpad admin. bug = self._makeBugWithNoSubscribers() member = self.factory.makePerson() subscriber = self.factory.makePerson(name='user', displayname='Subscriber Name') with person_logged_in(member): bug.subscribe(subscriber, subscriber, level=BugNotificationLevel.LIFECYCLE) harness = LaunchpadFormHarness(bug, BugPortletSubscribersWithDetails) api_request = IWebServiceClientRequest(harness.request) expected_result = { 'subscriber': { 'name': 'user', 'display_name': 'Subscriber Name', 'is_team': False, 'can_edit': True, 'web_link': canonical_url(subscriber), 'self_link': absoluteURL(subscriber, api_request), 'display_subscribed_by': 'Self-subscribed', }, 'subscription_level': "Lifecycle", } # Login as admin admin = getUtility(IPersonSet).find(ADMIN_EMAIL).any() with person_logged_in(admin): self.assertEqual(dumps([expected_result]), harness.view.subscriber_data_js)
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 test_jsoncache_contents(self): product = self.factory.makeProduct() question = self.factory.makeQuestion(target=product) login_person(product.owner) # It works even for anonymous users, so no log-in is needed. view = create_initialized_view( question.target, '+portlet-answercontacts', rootsite='answers') cache = IJSONRequestCache(view.request).objects context_url_data = { 'web_link': canonical_url(product, rootsite='mainsite'), 'self_link': absoluteURL(product, IWebServiceClientRequest(view.request)), } self.assertEqual(cache[product.name + '_answer_portlet_url_data'], context_url_data)
def expose_user_subscriptions_to_js(user, subscriptions, request): """Make the user's subscriptions available to JavaScript.""" api_request = IWebServiceClientRequest(request) info = {} if user is None: administered_teams = [] else: administered_teams = user.administrated_teams for subscription in subscriptions: target = subscription.target record = info.get(target) if record is None: record = dict(target_title=target.title, target_url=canonical_url(target, rootsite='mainsite'), filters=[]) info[target] = record subscriber = subscription.subscriber for filter in subscription.bug_filters: is_team = subscriber.is_team user_is_team_admin = (is_team and subscriber in administered_teams) team_has_contact_address = (is_team and subscriber.preferredemail is not None) mailing_list = subscriber.mailing_list user_is_on_team_mailing_list = ( team_has_contact_address and mailing_list is not None and mailing_list.is_usable and mailing_list.getSubscription(subscriber) is not None) record['filters'].append( dict(filter=filter, subscriber_link=absoluteURL(subscriber, api_request), subscriber_url=canonical_url(subscriber, rootsite='mainsite'), target_bugs_url=canonical_url(target, rootsite='bugs'), subscriber_title=subscriber.title, subscriber_is_team=is_team, user_is_team_admin=user_is_team_admin, team_has_contact_address=team_has_contact_address, user_is_on_team_mailing_list=user_is_on_team_mailing_list, can_mute=filter.isMuteAllowed(user), is_muted=filter.muted(user) is not None, target_title=target.title)) info = info.values() info.sort(key=itemgetter('target_url')) IJSONRequestCache(request).objects['subscription_info'] = info
def test_self_subscription(self): # Make a subscription directly for the user and see what we record. user = self.factory.makePerson() target = self.factory.makeProduct() request = LaunchpadTestRequest() with person_logged_in(user): sub = target.addBugSubscription(user, user) expose_user_subscriptions_to_js(user, [sub], request) info = IJSONRequestCache(request).objects['subscription_info'] filter_info = info[0]['filters'][0] self.assertFalse(filter_info['subscriber_is_team']) self.assertEqual(filter_info['subscriber_title'], user.title) self.assertFalse(filter_info['can_mute']) self.assertFalse(filter_info['is_muted']) self.assertEqual(filter_info['subscriber_link'], absoluteURL(user, IWebServiceClientRequest(request))) self.assertEqual(filter_info['subscriber_url'], canonical_url(user, rootsite='mainsite'))
def test_team_member_subscription(self): # Make a team subscription where the user is not an admin, and # see what we record. user = self.factory.makePerson() target = self.factory.makeProduct() request = LaunchpadTestRequest() team = self.factory.makeTeam(members=[user]) with person_logged_in(team.teamowner): sub = target.addBugSubscription(team, team.teamowner) expose_user_subscriptions_to_js(user, [sub], request) info = IJSONRequestCache(request).objects['subscription_info'] filter_info = info[0]['filters'][0] self.assertTrue(filter_info['subscriber_is_team']) self.assertFalse(filter_info['user_is_team_admin']) self.assertTrue(filter_info['can_mute']) self.assertFalse(filter_info['is_muted']) self.assertEqual(filter_info['subscriber_title'], team.title) self.assertEqual(filter_info['subscriber_link'], absoluteURL(team, IWebServiceClientRequest(request))) self.assertEqual(filter_info['subscriber_url'], canonical_url(team, rootsite='mainsite'))
def test_data_person_subscription(self): # subscriber_data_js returns JSON string of a list # containing all subscriber information needed for # subscribers_list.js subscribers loading. question = self._makeQuestionWithNoSubscribers() subscriber = self.factory.makePerson(name='user', displayname='Subscriber Name') with person_logged_in(subscriber): question.subscribe(subscriber, subscriber) view = create_view(question, '+portlet-subscribers-details') api_request = IWebServiceClientRequest(view.request) expected_result = { 'subscriber': { 'name': 'user', 'display_name': 'Subscriber Name', 'is_team': False, 'can_edit': False, 'web_link': canonical_url(subscriber), 'self_link': absoluteURL(subscriber, api_request) }, 'subscription_level': "Direct", } self.assertEqual(dumps([expected_result]), view.subscriber_data_js)
def api_request(self): return IWebServiceClientRequest(self.request)
def __call__(self): name = self.request.form.get('name') if name is None: raise MissingInputError('name', '') search_text = self.request.form.get('search_text') if search_text is None: raise MissingInputError('search_text', '') search_filter = self.request.form.get('search_filter') try: factory = getUtility(IVocabularyFactory, name) except ComponentLookupError: raise UnexpectedFormData( 'Unknown vocabulary %r' % name) vocabulary = factory(self.context) if IHugeVocabulary.providedBy(vocabulary): matches = vocabulary.searchForTerms(search_text, search_filter) total_size = matches.count() else: matches = list(vocabulary) total_size = len(matches) batch_navigator = BatchNavigator(matches, self.request) # We need to collate what IPickerEntrySource adapters are required for # the items in the current batch. We expect that the batch will be # homogenous and so only one adapter instance is required, but we # allow for the case where the batch may contain disparate entries # requiring different adapter implementations. # A mapping from adapter class name -> adapter instance adapter_cache = {} # A mapping from adapter class name -> list of vocab terms picker_entry_terms = {} for term in batch_navigator.currentBatch(): picker_entry_source = IPickerEntrySource(term.value) adapter_class = picker_entry_source.__class__.__name__ picker_terms = picker_entry_terms.get(adapter_class) if picker_terms is None: picker_terms = [] picker_entry_terms[adapter_class] = picker_terms adapter_cache[adapter_class] = picker_entry_source picker_terms.append(term.value) # A mapping from vocab terms -> picker entries picker_term_entries = {} # For the list of terms associated with a picker adapter, we get the # corresponding picker entries by calling the adapter. for adapter_class, term_values in picker_entry_terms.items(): picker_entries = adapter_cache[adapter_class].getPickerEntries( term_values, self.context) for term_value, picker_entry in izip(term_values, picker_entries): picker_term_entries[term_value] = picker_entry result = [] for term in batch_navigator.currentBatch(): entry = dict(value=term.token, title=term.title) # The canonical_url without just the path (no hostname) can # be passed directly into the REST PATCH call. api_request = IWebServiceClientRequest(self.request) try: entry['api_uri'] = canonical_url( term.value, request=api_request, path_only_if_possible=True) except NoCanonicalUrl: # The exception is caught, because the api_url is only # needed for inplace editing via a REST call. The # form picker doesn't need the api_url. entry['api_uri'] = 'Could not find canonical url.' picker_entry = picker_term_entries[term.value] if picker_entry.description is not None: if len(picker_entry.description) > MAX_DESCRIPTION_LENGTH: entry['description'] = ( picker_entry.description[:MAX_DESCRIPTION_LENGTH - 3] + '...') else: entry['description'] = picker_entry.description if picker_entry.image is not None: entry['image'] = picker_entry.image if picker_entry.css is not None: entry['css'] = picker_entry.css if picker_entry.alt_title is not None: entry['alt_title'] = picker_entry.alt_title if picker_entry.title_link is not None: entry['title_link'] = picker_entry.title_link if picker_entry.details is not None: entry['details'] = picker_entry.details if picker_entry.alt_title_link is not None: entry['alt_title_link'] = picker_entry.alt_title_link if picker_entry.link_css is not None: entry['link_css'] = picker_entry.link_css if picker_entry.badges: entry['badges'] = picker_entry.badges if picker_entry.metadata is not None: entry['metadata'] = picker_entry.metadata if picker_entry.target_type is not None: entry['target_type'] = picker_entry.target_type result.append(entry) self.request.response.setHeader('Content-type', 'application/json') return simplejson.dumps(dict(total_size=total_size, entries=result))
def _test_data_private_team_subscription(self, authenticated_user): # For a private team subscription, the team name and url are rendered # for authenticated users. bug = self._makeBugWithNoSubscribers() # Set up a private direct subscriber. teamowner = self.factory.makePerson(name="team-owner", displayname="Team Owner") direct_subscriber = self.factory.makeTeam( name='team', displayname='Team Name', owner=teamowner, visibility=PersonVisibility.PRIVATE) with person_logged_in(teamowner): bug.subscribe(direct_subscriber, direct_subscriber.teamowner, level=BugNotificationLevel.LIFECYCLE) # Set up a private indirect subscriber. indirect_teamowner = self.factory.makePerson( name="indirect-team-owner", displayname="Indirect Team Owner") indirect_subscriber = self.factory.makeTeam( name='indirect-team', displayname='Indirect Team Name', owner=indirect_teamowner, visibility=PersonVisibility.PRIVATE) with person_logged_in(indirect_teamowner): bug.default_bugtask.target.addSubscription(indirect_subscriber, indirect_teamowner) request = LaunchpadTestRequest() expected_result = [] view = create_initialized_view(bug, '+bug-portlet-subscribers-details', request=request) if authenticated_user: any_person = self.factory.makePerson() login_person(any_person, request) api_request = IWebServiceClientRequest(request) naked_subscriber = removeSecurityProxy(direct_subscriber) naked_indirect_subscriber = removeSecurityProxy( indirect_subscriber) expected_result = [{ 'subscriber': { 'name': 'team', 'display_name': 'Team Name', 'is_team': True, 'can_edit': False, 'web_link': canonical_url(naked_subscriber, rootsite='mainsite'), 'self_link': absoluteURL(naked_subscriber, api_request), 'display_subscribed_by': \ 'Subscribed by Team Owner (team-owner)', }, 'subscription_level': "Lifecycle", }, { 'subscriber': { 'name': 'indirect-team', 'display_name': 'Indirect Team Name', 'is_team': True, 'can_edit': False, 'web_link': canonical_url(naked_indirect_subscriber, rootsite='mainsite'), 'self_link': absoluteURL( naked_indirect_subscriber, api_request), }, 'subscription_level': "Maybe", }] self.assertEqual(dumps(expected_result), view.subscriber_data_js)