Start out by verifying the members page is sane.
>>> browser.open('http://launchpad.dev/~ubuntu-team/+members')
>>> 'Ubuntu Team' in browser.contents
True
Let's take a look at Colin's subscription page. Colin is an
administrator and his subscription never expires.
>>> browser.addHeader('Authorization', 'Basic foo.bar@canonical.com:test')
>>> browser.reload()
>>> url = '/~ubuntu-team/+member/kamion'
>>> browser.getLink(url=url).click()
>>> print browser.title
Colin Watson's membership : ...Ubuntu Team... team
>>> "Active member" in browser.contents
True
>>> browser.getControl(name='admin').value
['yes']
>>> browser.getControl(name='expires').value
['never']
Post an incomplete date and remove his administrator status.
There is some TestBrowser voodoo at work here. The datepicker widget now
allows you to render it disabled, which is neat because in the compound
widget that we have made it shows more clearly when the date is relevant and
when it is not if we disable it when it is not relevant (when the expiration
is set to "Never" with the radio button).
The Zope TestBrowser is smart enough to detect that the widget was rendered
with the input disabled, but not smart enough to play out the JavaScript
which would enable the input when the radio button was clicked to indicate
that a specific expiration date was desired. There is also no TestBrowser
way to "enable" the input. So, we have to reach into the guts of the
TestBrowser to manually re-enable the input. That's what the
control.mech_control.disabled=False stuff is.
>>> browser.getControl(name='admin').value = ['no']
>>> browser.getControl(name='expires').value = ['date']
>>> expiry = browser.getControl(name='membership.expirationdate')
>>> expiry.mech_control.disabled = False # control may have been disabled
>>> expiry.value = 'ssdf'
>>> browser.getControl('Change').click()
We get a nice error message
>>> for tag in find_tags_by_class(browser.contents, 'message'):
... print tag.renderContents()
Invalid expiration: Invalid date value
Give up on change, nothing should have changed with Colin:
>>> from zope.component import getUtility
>>> from lp.registry.interfaces.person import IPersonSet
>>> from lp.registry.interfaces.teammembership import ITeamMembershipSet
>>> from canonical.launchpad.ftests import login, logout, ANONYMOUS
>>> login(ANONYMOUS)
>>> personset = getUtility(IPersonSet)
>>> teammembershipset = getUtility(ITeamMembershipSet)
>>> ubuntu_team = personset.getByName('ubuntu-team')
>>> kamion = personset.getByName('kamion')
>>> kamion_membership = teammembershipset.getByPersonAndTeam(
... kamion, ubuntu_team)
>>> kamion_membership.status.title
'Administrator'
>>> print kamion_membership.dateexpires
None
>>> logout()
Now revoke Colin's administrator status and make him expire in November
next year -- successfully.
>>> from datetime import datetime, timedelta
>>> expire_date = datetime.utcnow() + timedelta(days=365)
>>> browser.getControl(name='admin').value = ['no']
>>> browser.getControl(name='expires').value = ['date']
>>> expiry = browser.getControl(name='membership.expirationdate')
>>> expiry.mech_control.disabled = False # control may have been disabled
>>> expiry.value = expire_date.strftime('%Y-%m-%d')
>>> browser.getControl(name='comment').value = 'Arfie'
>>> browser.getControl('Change').click()
We're redirected to the +members page
>>> browser.url
'http://launchpad.dev/~ubuntu-team/+members'
>>> login(ANONYMOUS)
>>> kamion_membership = teammembershipset.getByPersonAndTeam(
... kamion, ubuntu_team)
>>> print kamion_membership.status.title
Approved
>>> kamion_membership.dateexpires.date() == expire_date.date()
True
>>> print kamion_membership.last_change_comment
Arfie
>>> logout()
If we revisit Colin's membership page we'll see the comment field is
pre-populated with the last comment.
>>> url = '/~ubuntu-team/+member/kamion'
>>> browser.getLink(url=url).click()
>>> # Do not use 'print' for the following test as it will eliminate potential
>>> # leading and trailing whitespace, which we don't want.
>>> browser.getControl(name='comment').value
'Arfie'
Jeff is also an administrator and his subscription never expires, but he can
demote himself. He starts by paging though the memberships, then he deselects
the administrator control on the membership page.
>>> jdub_browser = setupBrowser(auth='Basic jeff.waugh@ubuntulinux.com:jdub')
>>> jdub_browser.open('http://launchpad.dev/~ubuntu-team/+members')
>>> jdub_browser.getLink('Next').click()
>>> url = '/~ubuntu-team/+member/jdub'
>>> jdub_browser.getLink(url=url).click()
>>> print jdub_browser.title
Jeff Waugh's membership : ...Ubuntu Team... team
>>> "Active member" in jdub_browser.contents
True
>>> jdub_browser.getControl(name='admin').value = ['no']
>>> jdub_browser.getControl('Change').click()
>>> jdub_browser.url
'http://launchpad.dev/~ubuntu-team/+members'
>>> login(ANONYMOUS)
>>> jdub = personset.getByName('jdub')
>>> jdub_membership = teammembershipset.getByPersonAndTeam(
... jdub, ubuntu_team)
>>> jdub_membership.status.title
'Approved'
>>> logout()
Sample person had his membership declined to the guadamen group. Test
that the page works and that foo.bar@canonical can access it.
>>> browser.open('http://launchpad.dev/~guadamen/+member/name12/')
>>> 'Declined member' in browser.contents
True
Dave Miller is a proposed member in Ubuntu Gnome Team.
If two people try to accept him as a member at the same time, the first one
should succeed and the second one receive a nice error message.
>>> browser.open('http://launchpad.dev/~name18/+members')
>>> url = '/~name18/+member/justdave'
>>> browser.getLink(url=url).click()
>>> second_browser = setupBrowser(auth='Basic foo.bar@canonical.com:test')
>>> second_browser.open('http://launchpad.dev' + url)
Approve the membership in the first browser.
>>> browser.getControl('Approve').click()
We're redirected to the members page.
>>> browser.url
'http://launchpad.dev/~name18/+members'
>>> login(ANONYMOUS)
>>> dave = personset.getByName('justdave')
>>> ubuntu_gnome_team = personset.getByName('name18')
>>> dave_membership = teammembershipset.getByPersonAndTeam(
... dave, ubuntu_gnome_team)
>>> dave_membership.status.title
'Approved'
>>> logout()
But in the second browser with the stale data we get an error message:
>>> second_browser.getControl('Approve').click()
>>> message = (
... 'The membership request for Dave Miller has already been processed')
>>> message in second_browser.contents
True
An admin can see the former members of the team.
>>> browser.open('http://launchpad.dev/~name18/+members')
>>> print extract_text(
... find_tag_by_id(browser.contents, 'inactivemembers'))
Name Joined in Status...
Other users cannot see the former members of the team.
>>> user_browser.open('http://launchpad.dev/~name18/+members')
>>> print find_tag_by_id(user_browser.contents, 'inactivemembers')
None
Team Participation page
=======================
The team participation page shows the team in which a person is a direct
member, as well as the teams in which they are an indirect member.
Kiko has not joined any teams:
>>> anon_browser.open('http://launchpad.dev/~kiko/+participation')
>>> print extract_text(
... find_tag_by_id(anon_browser.contents, 'no-participation'))
Christian Reis has not yet joined any teams.
>>> print find_tag_by_id(anon_browser.contents, 'participation')
None
Sample Person has both direct and indirect memberships:
>>> anon_browser.open('http://launchpad.dev/~name12/+participation')
>>> content = find_main_content(anon_browser.contents)
>>> print find_tag_by_id(content, 'no-participation')
None
>>> print extract_text(
... find_tag_by_id(content, 'participation'))
Team Joined Role Via Mailing List
HWDB Team 2009-07-09 Member — —
Landscape Developers 2006-07-11 Owner — —
Launchpad Users 2008-11-26 Owner — —
Ubuntu Gnome Team — Member Warty Security Team —
Warty Security Team 2007-01-26 Member — —
User can see links to register teams and change their mailing list
subscriptions on their own participation page.
>>> print find_tag_by_id(content, 'participation-actions')
None
>>> user_browser.open('http://launchpad.dev/~no-priv/+participation')
>>> actions = find_tag_by_id(
... user_browser.contents, 'participation-actions')
>>> print extract_text(actions)
Register a team
Change mailing list subscriptions
>>> user_browser.getLink('Register a team')
>>> user_browser.getLink('Change mailing list subscriptions')
Teams also have a participation page, but it does not include a mailing
list column.
>>> admin_browser.open('http://launchpad.dev/~admins/+participation')
>>> print extract_text(
... find_tag_by_id(admin_browser.contents, 'participation'))
Team Joined Role Via
Mailing List Experts 2007-10-04 Owner —