Merge lp:~edwin-grubbs/launchpad/bug-498181-addmember-notify-oops into lp:launchpad

Proposed by Edwin Grubbs
Status: Merged
Approved by: Curtis Hovey
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~edwin-grubbs/launchpad/bug-498181-addmember-notify-oops
Merge into: lp:launchpad
Diff against target: 73 lines (+35/-3)
3 files modified
lib/canonical/launchpad/mailnotification.py (+5/-2)
lib/lp/registry/interfaces/person.py (+2/-0)
lib/lp/registry/stories/webservice/xx-person.txt (+28/-1)
To merge this branch: bzr merge lp:~edwin-grubbs/launchpad/bug-498181-addmember-notify-oops
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code Approve
Review via email: mp+17333@code.launchpad.net

Commit message

Fix oops when a user proposes another person as a member of a team via the REST API.

To post a comment you must log in.
Revision history for this message
Edwin Grubbs (edwin-grubbs) wrote :

Summary
-------

In the UI, a user can only propose themself or a team they admin as a
member of another team. Some users of launchpadlib, started proposing
other people to keep track of their mentees. When the proposed member's
email addresses are hidden, this would result in an oops, since
addMember() would trigger an event that tries to email all the
admins of the team with the Reply-To header set to the email of
the proposed member. Since the member is being proposed by someone
else in the same way that teams are proposed, the Reply-To
will be set to the reviewer's email address.

Tests
-----

./bin/test -vv -t webservice/xx-person.txt

Demo and Q/A
------------

With launchpadlib, propose a member with hidden email addresses.

Revision history for this message
Curtis Hovey (sinzui) wrote :

This is a fine compromise betweent he API and Web interfaces. I have one grammatical suggestion.

=== modified file 'lib/canonical/launchpad/mailnotification.py'
--- lib/canonical/launchpad/mailnotification.py 2009-12-05 18:37:28 +0000
+++ lib/canonical/launchpad/mailnotification.py 2010-01-14 01:55:22 +0000
@@ -953,10 +953,13 @@
             'new-member-notification-for-admins.txt')
         subject = '%s joined %s' % (person.name, team.name)
     elif membership.status == proposed:
- if person.isTeam():
+ # In the UI, a user can only propose themself or a team they

grammar: s/themself/himself/

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== renamed file 'lib/canonical/launchpad/emailtemplates/pending-membership-approval-for-teams.txt' => 'lib/canonical/launchpad/emailtemplates/pending-membership-approval-for-third-party.txt'
=== modified file 'lib/canonical/launchpad/mailnotification.py'
--- lib/canonical/launchpad/mailnotification.py 2009-12-05 18:37:28 +0000
+++ lib/canonical/launchpad/mailnotification.py 2010-01-14 23:01:13 +0000
@@ -953,10 +953,13 @@
953 'new-member-notification-for-admins.txt')953 'new-member-notification-for-admins.txt')
954 subject = '%s joined %s' % (person.name, team.name)954 subject = '%s joined %s' % (person.name, team.name)
955 elif membership.status == proposed:955 elif membership.status == proposed:
956 if person.isTeam():956 # In the UI, a user can only propose himself or a team he
957 # admins. Some users of the REST API have a workflow, where
958 # they propose users that are designated as mentees (Bug 498181).
959 if reviewer != person:
957 headers = {"Reply-To": reviewer.preferredemail.email}960 headers = {"Reply-To": reviewer.preferredemail.email}
958 template = get_email_template(961 template = get_email_template(
959 'pending-membership-approval-for-teams.txt')962 'pending-membership-approval-for-third-party.txt')
960 else:963 else:
961 headers = {"Reply-To": person.preferredemail.email}964 headers = {"Reply-To": person.preferredemail.email}
962 template = get_email_template('pending-membership-approval.txt')965 template = get_email_template('pending-membership-approval.txt')
963966
=== modified file 'lib/lp/registry/interfaces/person.py'
--- lib/lp/registry/interfaces/person.py 2010-01-07 06:27:46 +0000
+++ lib/lp/registry/interfaces/person.py 2010-01-14 23:01:13 +0000
@@ -1421,6 +1421,8 @@
14211421
1422 :param status: `TeamMembershipStatus` value must be either1422 :param status: `TeamMembershipStatus` value must be either
1423 Approved, Proposed or Admin.1423 Approved, Proposed or Admin.
1424 If the new member is a team, the status will be changed to
1425 Invited unless the user is also an admin of that team.
14241426
1425 :param force_team_add: If the person is actually a team and1427 :param force_team_add: If the person is actually a team and
1426 force_team_add is False, the team will actually be invited to1428 force_team_add is False, the team will actually be invited to
14271429
=== modified file 'lib/lp/registry/stories/webservice/xx-person.txt'
--- lib/lp/registry/stories/webservice/xx-person.txt 2009-12-17 10:33:34 +0000
+++ lib/lp/registry/stories/webservice/xx-person.txt 2010-01-14 23:01:13 +0000
@@ -545,7 +545,34 @@
545 ... "/~landscape-developers/+member/salgado").jsonBody()['status']545 ... "/~landscape-developers/+member/salgado").jsonBody()['status']
546 u'Deactivated'546 u'Deactivated'
547547
548Adding an arbitrary member to a team:548Though it is not possible through the Launchpad UI, some users of the
549REST API propose other people (as opposed to teams) as part of a
550mentoring process (Bug 498181).
551
552 >>> from canonical.launchpad.testing.pages import webservice_for_person
553 >>> from canonical.launchpad.webapp.interfaces import OAuthPermission
554 >>> from lp.registry.interfaces.person import IPersonSet
555 >>> from zope.component import getUtility
556 >>> login(ANONYMOUS)
557 >>> owner = getUtility(IPersonSet).getByName('owner')
558 >>> logout()
559 >>> owner_webservice = webservice_for_person(
560 ... owner, permission=OAuthPermission.WRITE_PRIVATE)
561
562 # The sample user (name12) is used to verify that it works when
563 # the new member's email address is hidden.
564 >>> print owner_webservice.named_post(
565 ... webservice.getAbsoluteUrl('~otherteam'), 'addMember', {},
566 ... person=webservice.getAbsoluteUrl('/~name12'),
567 ... status='Proposed', comment='Just a test')
568 HTTP/1.1 200 Ok
569 ...
570 >>> owner_webservice.get("/~otherteam/+member/name12"
571 ... ).jsonBody()['status']
572 u'Proposed'
573
574Adding a team as a new member will result in the membership being
575set to the Invited status.
549576
550 >>> print webservice.named_post(577 >>> print webservice.named_post(
551 ... ubuntu_team['self_link'], 'addMember', {},578 ... ubuntu_team['self_link'], 'addMember', {},