← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~bac/launchpad/bug-689719 into lp:launchpad

 

Brad Crittenden has proposed merging lp:~bac/launchpad/bug-689719 into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  #689719 Remove team polls
  https://bugs.launchpad.net/bugs/689719


= Summary =

Remove the polls feature from Launchpad.

== Proposed fix ==

Rip, rip, rip.

== Pre-implementation notes ==

Talks and querying with Curtis regarding existing data.

== Implementation details ==

N/A

== Tests ==

bin/test -vvm lp.registry

== Demo and Q/A ==

http://dev.launchpad.net/~ubuntu-team/+polls

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/registry/browser/configure.zcml
  lib/lp/registry/adapters.py
  lib/lp/registry/templates/team-index.pt
  lib/lp/registry/browser/tests/test_breadcrumbs.py
  lib/canonical/launchpad/security.py
  lib/canonical/launchpad/pagetitles.py
  lib/lp/registry/templates/team-polls.pt
  lib/lp/registry/configure.zcml
  lib/lp/testing/factory.py
  lib/lp/registry/doc/person-merge.txt
  lib/lp/registry/stories/team/xx-team-home.txt
  lib/lp/registry/browser/person.py
  lib/lp/registry/model/person.py


These are all bogus.


./lib/canonical/launchpad/security.py
     742: E302 expected 2 blank lines, found 1
./lib/canonical/launchpad/pagetitles.py
      58: E302 expected 2 blank lines, found 3
      60: E301 expected 1 blank line, found 0
      69: E301 expected 1 blank line, found 0
      75: E301 expected 1 blank line, found 0
      81: E301 expected 1 blank line, found 0
      87: E301 expected 1 blank line, found 0
     100: E301 expected 1 blank line, found 0
     121: E302 expected 2 blank lines, found 1
     147: E302 expected 2 blank lines, found 1
     151: E302 expected 2 blank lines, found 1
     158: E302 expected 2 blank lines, found 1
     193: E302 expected 2 blank lines, found 1
     202: E302 expected 2 blank lines, found 1
     239: E302 expected 2 blank lines, found 1
     256: E302 expected 2 blank lines, found 1
-- 
https://code.launchpad.net/~bac/launchpad/bug-689719/+merge/43840
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~bac/launchpad/bug-689719 into lp:launchpad.
=== modified file 'lib/canonical/launchpad/pagetitles.py'
--- lib/canonical/launchpad/pagetitles.py	2010-11-08 12:52:43 +0000
+++ lib/canonical/launchpad/pagetitles.py	2010-12-15 22:26:18 +0000
@@ -285,20 +285,6 @@
 person_translations_to_review = ContextDisplayName(
     'Translations for review by %s')
 
-poll_edit = ContextTitle(smartquote('Edit poll "%s"'))
-
-poll_index = ContextTitle(smartquote('Poll: "%s"'))
-
-poll_newoption = ContextTitle(smartquote('New option for poll "%s"'))
-
-def polloption_edit(context, view):
-    """Return the page title to edit a poll's option."""
-    return 'Edit option: %s' % context.title
-
-poll_vote_condorcet = ContextTitle(smartquote('Vote in poll "%s"'))
-
-poll_vote_simple = ContextTitle(smartquote('Vote in poll "%s"'))
-
 product_cvereport = ContextTitle('CVE reports for %s')
 
 product_index = ContextTitle('%s in Launchpad')

=== modified file 'lib/canonical/launchpad/security.py'
--- lib/canonical/launchpad/security.py	2010-12-14 00:03:18 +0000
+++ lib/canonical/launchpad/security.py	2010-12-15 22:26:18 +0000
@@ -130,11 +130,6 @@
     PersonVisibility,
     )
 from lp.registry.interfaces.pillar import IPillar
-from lp.registry.interfaces.poll import (
-    IPoll,
-    IPollOption,
-    IPollSubset,
-    )
 from lp.registry.interfaces.product import (
     IProduct,
     IProductSet,
@@ -858,26 +853,6 @@
         return False
 
 
-class EditPollByTeamOwnerOrTeamAdminsOrAdmins(
-        EditTeamMembershipByTeamOwnerOrTeamAdminsOrAdmins):
-    permission = 'launchpad.Edit'
-    usedfor = IPoll
-
-
-class EditPollSubsetByTeamOwnerOrTeamAdminsOrAdmins(
-        EditPollByTeamOwnerOrTeamAdminsOrAdmins):
-    permission = 'launchpad.Edit'
-    usedfor = IPollSubset
-
-
-class EditPollOptionByTeamOwnerOrTeamAdminsOrAdmins(AuthorizationBase):
-    permission = 'launchpad.Edit'
-    usedfor = IPollOption
-
-    def checkAuthenticated(self, user):
-        return can_edit_team(self.obj.poll.team, user)
-
-
 class AdminDistribution(AdminByAdminsTeam):
     """Soyuz involves huge chunks of data in the archive and librarian,
     so for the moment we are locking down admin and edit on distributions

=== removed file 'lib/canonical/launchpad/tests/test_poll.py'
--- lib/canonical/launchpad/tests/test_poll.py	2010-10-04 19:50:45 +0000
+++ lib/canonical/launchpad/tests/test_poll.py	1970-01-01 00:00:00 +0000
@@ -1,34 +0,0 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-from datetime import (
-    datetime,
-    timedelta,
-    )
-import unittest
-
-import pytz
-
-from canonical.launchpad.ftests import login
-from canonical.testing.layers import LaunchpadFunctionalLayer
-from lp.testing import TestCaseWithFactory
-
-
-class TestPoll(TestCaseWithFactory):
-    layer = LaunchpadFunctionalLayer
-
-    def test_getWinners_handle_polls_with_only_spoilt_votes(self):
-        login('mark@xxxxxxxxxxx')
-        owner = self.factory.makePerson()
-        team = self.factory.makeTeam(owner)
-        poll = self.factory.makePoll(team, 'name', 'title', 'proposition')
-        # Force opening of poll so that we can vote.
-        poll.dateopens = datetime.now(pytz.UTC) - timedelta(minutes=2)
-        poll.storeSimpleVote(owner, None)
-        # Force closing of the poll so that we can call getWinners().
-        poll.datecloses = datetime.now(pytz.UTC)
-        self.failUnless(poll.getWinners() is None, poll.getWinners())
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/registry/adapters.py'
--- lib/lp/registry/adapters.py	2010-09-21 13:39:17 +0000
+++ lib/lp/registry/adapters.py	2010-12-15 22:26:18 +0000
@@ -6,24 +6,15 @@
 __metaclass__ = type
 
 __all__ = [
-    'distroseries_to_launchpadusage',
-    'distroseries_to_serviceusage',
-    'PollSubset',
+    'distroseries_to_distribution',
+    'person_from_principal',
     'productseries_to_product',
     ]
 
 
-from zope.component import getUtility
 from zope.component.interfaces import ComponentLookupError
-from zope.interface import implements
 
 from canonical.launchpad.webapp.interfaces import ILaunchpadPrincipal
-from lp.registry.interfaces.poll import (
-    IPollSet,
-    IPollSubset,
-    PollAlgorithm,
-    PollStatus,
-    )
 
 
 def distroseries_to_distribution(distroseries):
@@ -51,60 +42,6 @@
         raise ComponentLookupError
 
 
-class PollSubset:
-    """Adapt an `IPoll` to an `IPollSubset`."""
-    implements(IPollSubset)
-
-    title = 'Team polls'
-
-    def __init__(self, team=None):
-        self.team = team
-
-    def new(self, name, title, proposition, dateopens, datecloses,
-            secrecy, allowspoilt, poll_type=PollAlgorithm.SIMPLE):
-        """See IPollSubset."""
-        assert self.team is not None, (
-            'team cannot be None to call this method.')
-        return getUtility(IPollSet).new(
-            self.team, name, title, proposition, dateopens,
-            datecloses, secrecy, allowspoilt, poll_type)
-
-    def getByName(self, name, default=None):
-        """See IPollSubset."""
-        assert self.team is not None, (
-            'team cannot be None to call this method.')
-        pollset = getUtility(IPollSet)
-        return pollset.getByTeamAndName(self.team, name, default)
-
-    def getAll(self):
-        """See IPollSubset."""
-        assert self.team is not None, (
-            'team cannot be None to call this method.')
-        return getUtility(IPollSet).selectByTeam(self.team)
-
-    def getOpenPolls(self, when=None):
-        """See IPollSubset."""
-        assert self.team is not None, (
-            'team cannot be None to call this method.')
-        return getUtility(IPollSet).selectByTeam(
-            self.team, [PollStatus.OPEN], orderBy='datecloses', when=when)
-
-    def getClosedPolls(self, when=None):
-        """See IPollSubset."""
-        assert self.team is not None, (
-            'team cannot be None to call this method.')
-        return getUtility(IPollSet).selectByTeam(
-            self.team, [PollStatus.CLOSED], orderBy='datecloses', when=when)
-
-    def getNotYetOpenedPolls(self, when=None):
-        """See IPollSubset."""
-        assert self.team is not None, (
-            'team cannot be None to call this method.')
-        return getUtility(IPollSet).selectByTeam(
-            self.team, [PollStatus.NOT_YET_OPENED],
-            orderBy='dateopens', when=when)
-
-
 def productseries_to_product(productseries):
     """Adapts `IProductSeries` object to `IProduct`.
 

=== modified file 'lib/lp/registry/browser/configure.zcml'
--- lib/lp/registry/browser/configure.zcml	2010-12-10 23:36:06 +0000
+++ lib/lp/registry/browser/configure.zcml	2010-12-15 22:26:18 +0000
@@ -600,75 +600,6 @@
             name="karmacontext-macros"
             template="../templates/karmacontext-macros.pt"/>
     </facet>
-    <facet
-        facet="overview">
-        <browser:menus
-            module="lp.registry.browser.poll"
-            classes="
-                PollOverviewMenu
-                PollActionNavigationMenu
-                PollEditNavigationMenu"/>
-        <browser:defaultView
-            for="lp.registry.interfaces.poll.IPoll"
-            name="+index"/>
-        <browser:navigation
-            module="lp.registry.browser.poll"
-            classes="
-                PollNavigation"/>
-        <browser:url
-            for="lp.registry.interfaces.poll.IPoll"
-            path_expression="string:+poll/${name}"
-            attribute_to_parent="team"/>
-        <browser:pages
-            for="lp.registry.interfaces.poll.IPoll"
-            permission="zope.Public"
-            class="lp.registry.browser.poll.PollView">
-            <browser:page
-                name="+index"
-                template="../templates/poll-index.pt"/>
-        </browser:pages>
-        <browser:pages
-            for="lp.registry.interfaces.poll.IPoll"
-            permission="zope.Public"
-            class="lp.registry.browser.poll.BasePollView">
-            <browser:page
-                name="+portlet-details"
-                template="../templates/poll-portlet-details.pt"/>
-            <browser:page
-                name="+portlet-options"
-                template="../templates/poll-portlet-options.pt"/>
-        </browser:pages>
-        <browser:page
-            name="+vote"
-            for="lp.registry.interfaces.poll.IPoll"
-            permission="launchpad.AnyPerson"
-            class="lp.registry.browser.poll.PollVoteView"/>
-        <browser:page
-            name="+edit"
-            for="lp.registry.interfaces.poll.IPoll"
-            class="lp.registry.browser.poll.PollEditView"
-            permission="launchpad.Edit"
-            template="../templates/poll-edit.pt"/>
-        <browser:page
-            name="+newoption"
-            for="lp.registry.interfaces.poll.IPoll"
-            class="lp.registry.browser.poll.PollOptionAddView"
-            permission="launchpad.Edit"
-            template="../templates/poll-newoption.pt"/>
-        <browser:defaultView
-            for="lp.registry.interfaces.poll.IPollOption"
-            name="+edit"/>
-        <browser:url
-            for="lp.registry.interfaces.poll.IPollOption"
-            path_expression="string:+option/${id}"
-            attribute_to_parent="poll"/>
-        <browser:page
-            name="+edit"
-            for="lp.registry.interfaces.poll.IPollOption"
-            class="lp.registry.browser.poll.PollOptionEditView"
-            permission="launchpad.Edit"
-            template="../templates/polloption-edit.pt"/>
-    </facet>
     <browser:url
         for="lp.registry.interfaces.announcement.IAnnouncement"
         path_expression="string:+announcement/${id}"
@@ -1080,12 +1011,6 @@
             template="../templates/team-index.pt"/>
         <browser:page
             for="lp.registry.interfaces.person.ITeam"
-            class="lp.registry.browser.person.TeamIndexView"
-            permission="zope.Public"
-            name="+portlet-polls"
-            template="../templates/team-portlet-polls.pt"/>
-        <browser:page
-            for="lp.registry.interfaces.person.ITeam"
             permission="zope.Public"
             class="lp.registry.browser.team.TeamMapView"
             name="+map"
@@ -1198,12 +1123,6 @@
             name="+polls"
             template="../templates/team-polls.pt"/>
         <browser:page
-            name="+newpoll"
-            for="lp.registry.interfaces.person.ITeam"
-            class="canonical.launchpad.browser.PollAddView"
-            permission="launchpad.Edit"
-            template="../templates/team-newpoll.pt"/>
-        <browser:page
             name="+members"
             for="lp.registry.interfaces.person.ITeam"
             permission="zope.Public"

=== modified file 'lib/lp/registry/browser/person.py'
--- lib/lp/registry/browser/person.py	2010-12-10 23:10:09 +0000
+++ lib/lp/registry/browser/person.py	2010-12-15 22:26:18 +0000
@@ -284,10 +284,6 @@
     )
 from lp.registry.interfaces.personproduct import IPersonProductFactory
 from lp.registry.interfaces.pillar import IPillarNameSet
-from lp.registry.interfaces.poll import (
-    IPollSet,
-    IPollSubset,
-    )
 from lp.registry.interfaces.product import IProduct
 from lp.registry.interfaces.ssh import (
     ISSHKeySet,
@@ -562,10 +558,6 @@
 
     usedfor = ITeam
 
-    @stepthrough('+poll')
-    def traverse_poll(self, name):
-        return getUtility(IPollSet).getByTeamAndName(self.context, name)
-
     @stepthrough('+invitation')
     def traverse_invitation(self, name):
         # Return the found membership regardless of its status as we know
@@ -1334,17 +1326,6 @@
         text = 'Show member photos'
         return Link(target, text, icon='team')
 
-    def polls(self):
-        target = '+polls'
-        text = 'Show polls'
-        return Link(target, text, icon='info')
-
-    @enabled_with_permission('launchpad.Edit')
-    def add_poll(self):
-        target = '+newpoll'
-        text = 'Create a poll'
-        return Link(target, text, icon='add')
-
     @enabled_with_permission('launchpad.Edit')
     def editemail(self):
         target = '+contactaddress'
@@ -1429,8 +1410,6 @@
         'moderate_mailing_list',
         'editlanguages',
         'map',
-        'polls',
-        'add_poll',
         'join',
         'leave',
         'add_my_teams',
@@ -1451,7 +1430,7 @@
 
     usedfor = ITeam
     facet = 'overview'
-    links = ['profile', 'polls', 'members', 'ppas']
+    links = ['profile', 'members', 'ppas']
 
 
 class TeamMembershipView(LaunchpadView):
@@ -2941,21 +2920,6 @@
             return ''
 
     @cachedproperty
-    def openpolls(self):
-        assert self.context.isTeam()
-        return IPollSubset(self.context).getOpenPolls()
-
-    @cachedproperty
-    def closedpolls(self):
-        assert self.context.isTeam()
-        return IPollSubset(self.context).getClosedPolls()
-
-    @cachedproperty
-    def notyetopenedpolls(self):
-        assert self.context.isTeam()
-        return IPollSubset(self.context).getNotYetOpenedPolls()
-
-    @cachedproperty
     def contributions(self):
         """Cache the results of getProjectsAndCategoriesContributedTo()."""
         return self.context.getProjectsAndCategoriesContributedTo(
@@ -3124,19 +3088,6 @@
         else:
             raise AssertionError('Unknown group to contact.')
 
-    @property
-    def should_show_polls_portlet(self):
-        menu = TeamOverviewMenu(self.context)
-        return (
-            self.has_current_polls or self.closedpolls
-            or menu.add_poll().enabled)
-
-    @property
-    def has_current_polls(self):
-        """Return True if this team has any non-closed polls."""
-        assert self.context.isTeam()
-        return bool(self.openpolls) or bool(self.notyetopenedpolls)
-
     def userIsOwner(self):
         """Return True if the user is the owner of this Team."""
         if self.user is None:

=== removed file 'lib/lp/registry/browser/poll.py'
--- lib/lp/registry/browser/poll.py	2010-11-23 23:22:27 +0000
+++ lib/lp/registry/browser/poll.py	1970-01-01 00:00:00 +0000
@@ -1,469 +0,0 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-__metaclass__ = type
-
-__all__ = [
-    'BasePollView',
-    'PollAddView',
-    'PollEditNavigationMenu',
-    'PollEditView',
-    'PollNavigation',
-    'PollOptionAddView',
-    'PollOptionEditView',
-    'PollOverviewMenu',
-    'PollView',
-    'PollVoteView',
-    'PollBreadcrumb',
-    ]
-
-from z3c.ptcompat import ViewPageTemplateFile
-from zope.app.form.browser import TextWidget
-from zope.component import getUtility
-from zope.event import notify
-from zope.interface import (
-    implements,
-    Interface,
-    )
-from zope.lifecycleevent import ObjectCreatedEvent
-
-from canonical.launchpad.helpers import shortlist
-from canonical.launchpad.webapp import (
-    ApplicationMenu,
-    canonical_url,
-    enabled_with_permission,
-    LaunchpadView,
-    Link,
-    Navigation,
-    NavigationMenu,
-    stepthrough,
-    )
-from canonical.launchpad.webapp.breadcrumb import TitleBreadcrumb
-from lp.app.browser.launchpadform import (
-    action,
-    custom_widget,
-    LaunchpadEditFormView,
-    LaunchpadFormView,
-    )
-from lp.registry.interfaces.poll import (
-    IPoll,
-    IPollOption,
-    IPollOptionSet,
-    IPollSubset,
-    IVoteSet,
-    PollAlgorithm,
-    PollSecrecy,
-    )
-
-
-class PollEditLinksMixin:
-
-    @enabled_with_permission('launchpad.Edit')
-    def addnew(self):
-        text = 'Add new option'
-        return Link('+newoption', text, icon='add')
-
-    @enabled_with_permission('launchpad.Edit')
-    def edit(self):
-        text = 'Change details'
-        return Link('+edit', text, icon='edit')
-
-
-class PollOverviewMenu(ApplicationMenu, PollEditLinksMixin):
-    usedfor = IPoll
-    facet = 'overview'
-    links = ['addnew']
-
-
-class IPollEditMenu(Interface):
-    """A marker interface for the edit navigation menu."""
-
-
-class PollEditNavigationMenu(NavigationMenu, PollEditLinksMixin):
-    usedfor = IPollEditMenu
-    facet = 'overview'
-    links = ['addnew', 'edit']
-
-
-class IPollActionMenu(Interface):
-    """A marker interface for the action menu."""
-
-
-class PollActionNavigationMenu(PollEditNavigationMenu):
-    usedfor = IPollActionMenu
-    links = ['edit']
-
-
-class PollNavigation(Navigation):
-
-    usedfor = IPoll
-
-    @stepthrough('+option')
-    def traverse_option(self, name):
-        return getUtility(IPollOptionSet).getByPollAndId(
-            self.context, int(name))
-
-
-class BasePollView(LaunchpadView):
-    """A base view class to be used in other poll views."""
-
-    token = None
-    gotTokenAndVotes = False
-    feedback = ""
-
-    def setUpTokenAndVotes(self):
-        """Set up the token and votes to be displayed."""
-        if not self.userVoted():
-            return
-
-        # For secret polls we can only display the votes after the token
-        # is submitted.
-        if self.request.method == 'POST' and self.isSecret():
-            self.setUpTokenAndVotesForSecretPolls()
-        elif not self.isSecret():
-            self.setUpTokenAndVotesForNonSecretPolls()
-
-    def setUpTokenAndVotesForNonSecretPolls(self):
-        """Get the votes of the logged in user in this poll.
-
-        Set the votes in instance variables and also set self.gotTokenAndVotes
-        to True, so the templates know they can display the vote.
-
-        This method should be used only on non-secret polls and if the logged
-        in user has voted on this poll.
-        """
-        assert not self.isSecret() and self.userVoted()
-        votes = self.context.getVotesByPerson(self.user)
-        assert votes, (
-            "User %r hasn't voted on poll %r" % (self.user, self.context))
-        if self.isSimple():
-            # Here we have only one vote.
-            self.currentVote = votes[0]
-            self.token = self.currentVote.token
-        elif self.isCondorcet():
-            # Here we have multiple votes, and the token is the same in
-            # all of them.
-            self.currentVotes = sorted(votes, key=lambda v: v.preference)
-            self.token = self.currentVotes[0].token
-        self.gotTokenAndVotes = True
-
-    def setUpTokenAndVotesForSecretPolls(self):
-        """Get the votes with the token provided in the form.
-
-        Set the votes, together with the token in instance variables. Also
-        set self.gotTokenAndVotes to True, so the templates know they can
-        display the vote.
-
-        Return True if there's any vote with the given token and the votes
-        are on this poll.
-
-        This method should be used only on secret polls and if the logged
-        in user has voted on this poll.
-        """
-        assert self.isSecret() and self.userVoted()
-        token = self.request.form.get('token')
-        # Only overwrite self.token if the request contains a 'token'
-        # variable.
-        if token is not None:
-            self.token = token
-        votes = getUtility(IVoteSet).getByToken(self.token)
-        if not votes:
-            self.feedback = ("There's no vote associated with the token %s"
-                             % self.token)
-            return False
-
-        # All votes with a given token must be on the same poll. That means
-        # checking the poll of the first vote is enough.
-        if votes[0].poll != self.context:
-            self.feedback = ("The vote associated with the token %s is not "
-                             "a vote on this poll." % self.token)
-            return False
-
-        if self.isSimple():
-            # A simple poll has only one vote, because you can choose only one
-            # option.
-            self.currentVote = votes[0]
-        elif self.isCondorcet():
-            self.currentVotes = sorted(votes, key=lambda v: v.preference)
-        self.gotTokenAndVotes = True
-        return True
-
-    def userCanVote(self):
-        """Return True if the user is/was eligible to vote on this poll."""
-        return (self.user and self.user.inTeam(self.context.team))
-
-    def userVoted(self):
-        """Return True if the user voted on this poll."""
-        return (self.user and self.context.personVoted(self.user))
-
-    def isCondorcet(self):
-        """Return True if this poll's type is Condorcet."""
-        return self.context.type == PollAlgorithm.CONDORCET
-
-    def isSimple(self):
-        """Return True if this poll's type is Simple."""
-        return self.context.type == PollAlgorithm.SIMPLE
-
-    def isSecret(self):
-        """Return True if this is a secret poll."""
-        return self.context.secrecy == PollSecrecy.SECRET
-
-
-class PollBreadcrumb(TitleBreadcrumb):
-    """Breadcrumb for polls."""
-
-
-class PollView(BasePollView):
-    """A view class to display the results of a poll."""
-    implements(IPollActionMenu)
-
-    def initialize(self):
-        super(PollView, self).initialize()
-        request = self.request
-        if (self.userCanVote() and self.context.isOpen() and
-            self.context.getActiveOptions()):
-            vote_url = canonical_url(self.context, view_name='+vote')
-            request.response.redirect(vote_url)
-
-    def getVotesByOption(self, option):
-        """Return the number of votes the given option received."""
-        return getUtility(IVoteSet).getVotesByOption(option)
-
-    def getPairwiseMatrixWithHeaders(self):
-        """Return the pairwise matrix, with headers being the option's
-        names.
-        """
-        # XXX: kiko 2006-03-13:
-        # The list() call here is necessary because, lo and behold,
-        # it gives us a non-security-proxied list object! Someone come
-        # in and fix this!
-        pairwise_matrix = list(self.context.getPairwiseMatrix())
-        headers = [None]
-        for idx, option in enumerate(self.context.getAllOptions()):
-            headers.append(option.title)
-            # Get a mutable row.
-            row = list(pairwise_matrix[idx])
-            row.insert(0, option.title)
-            pairwise_matrix[idx] = row
-        pairwise_matrix.insert(0, headers)
-        return pairwise_matrix
-
-
-class PollVoteView(BasePollView):
-    """A view class to where the user can vote on a poll.
-
-    If the user already voted, the current vote is displayed and the user can
-    change it. Otherwise he can register his vote.
-    """
-
-    default_template = ViewPageTemplateFile(
-        '../templates/poll-vote-simple.pt')
-    condorcet_template = ViewPageTemplateFile(
-        '../templates/poll-vote-condorcet.pt')
-
-    @property
-    def template(self):
-        if self.isCondorcet():
-            return self.condorcet_template
-        else:
-            return self.default_template
-
-    def initialize(self):
-        """Process the form, if it was submitted."""
-        super(PollVoteView, self).initialize()
-        if not self.isSecret() and self.userVoted():
-            # For non-secret polls, the user's vote is always displayed
-            self.setUpTokenAndVotesForNonSecretPolls()
-
-        if self.request.method != 'POST':
-            return
-
-        if self.isSecret() and self.userVoted():
-            if not self.setUpTokenAndVotesForSecretPolls():
-                # Not possible to get the votes. Probably the token was wrong.
-                return
-
-        if 'showvote' in self.request.form:
-            # The user only wants to see the vote.
-            return
-
-        if not self.context.isOpen():
-            self.feedback = "This poll is not open."
-            return
-
-        if self.isSimple():
-            self.processSimpleVotingForm()
-        else:
-            self.processCondorcetVotingForm()
-
-        # User may have voted, so we need to setup the vote to display again.
-        self.setUpTokenAndVotes()
-
-    def processSimpleVotingForm(self):
-        """Process the simple-voting form to change a user's vote or register
-        a new one.
-
-        This method must not be called if the poll is not open.
-        """
-        assert self.context.isOpen()
-        context = self.context
-        newoption_id = self.request.form.get('newoption')
-        if newoption_id == 'donotchange':
-            self.feedback = "Your vote was not changed."
-            return
-        elif newoption_id == 'donotvote':
-            self.feedback = "You chose not to vote yet."
-            return
-        elif newoption_id == 'none':
-            newoption = None
-        else:
-            newoption = getUtility(IPollOptionSet).getByPollAndId(
-                context, int(newoption_id))
-
-        if self.userVoted():
-            self.currentVote.option = newoption
-            self.feedback = "Your vote was changed successfully."
-        else:
-            self.currentVote = context.storeSimpleVote(self.user, newoption)
-            self.token = self.currentVote.token
-            self.currentVote = self.currentVote
-            if self.isSecret():
-                self.feedback = (
-                    "Your vote has been recorded. If you want to view or "
-                    "change it later you must write down this key: %s"
-                    % self.token)
-            else:
-                self.feedback = (
-                    "Your vote was stored successfully. You can come back to "
-                    "this page at any time before this poll closes to view "
-                    "or change your vote, if you want.")
-
-    def processCondorcetVotingForm(self):
-        """Process the condorcet-voting form to change a user's vote or
-        register a new one.
-
-        This method must not be called if the poll is not open.
-        """
-        assert self.context.isOpen()
-        form = self.request.form
-        activeoptions = shortlist(self.context.getActiveOptions())
-        newvotes = {}
-        for option in activeoptions:
-            try:
-                preference = int(form.get('option_%d' % option.id))
-            except ValueError:
-                # XXX: Guilherme Salgado 2005-09-14:
-                # User tried to specify a value which we can't convert to
-                # an integer. Better thing to do would be to notify the user
-                # and ask him to fix it.
-                preference = None
-            newvotes[option] = preference
-
-        if self.userVoted():
-            # This is a vote change.
-            # For now it's not possible to have votes in an inactive option,
-            # but it'll be in the future as we'll allow people to make options
-            # inactive after a poll opens.
-            assert len(activeoptions) == len(self.currentVotes)
-            for vote in self.currentVotes:
-                vote.preference = newvotes.get(vote.option)
-            self.currentVotes.sort(key=lambda v: v.preference)
-            self.feedback = "Your vote was changed successfully."
-        else:
-            # This is a new vote.
-            votes = self.context.storeCondorcetVote(self.user, newvotes)
-            self.token = votes[0].token
-            self.currentVotes = sorted(votes, key=lambda v: v.preference)
-            if self.isSecret():
-                self.feedback = (
-                    "Your vote has been recorded. If you want to view or "
-                    "change it later you must write down this key: %s"
-                    % self.token)
-            else:
-                self.feedback = (
-                    "Your vote was stored successfully. You can come back to "
-                    "this page at any time before this poll closes to view "
-                    "or change your vote, if you want.")
-
-
-class PollAddView(LaunchpadFormView):
-    """The view class to create a new poll in a given team."""
-
-    schema = IPoll
-    field_names = ["name", "title", "proposition", "allowspoilt", "dateopens",
-                   "datecloses"]
-
-    @property
-    def cancel_url(self):
-        """See `LaunchpadFormView`."""
-        return canonical_url(self.context)
-
-    @action("Continue", name="continue")
-    def continue_action(self, action, data):
-        # XXX: salgado, 2008-10-08: Only secret polls can be created until we
-        # fix https://launchpad.net/bugs/80596.
-        secrecy = PollSecrecy.SECRET
-        poll = IPollSubset(self.context).new(
-            data['name'], data['title'], data['proposition'],
-            data['dateopens'], data['datecloses'], secrecy,
-            data['allowspoilt'])
-        self.next_url = canonical_url(poll)
-        notify(ObjectCreatedEvent(poll))
-
-
-class PollEditView(LaunchpadEditFormView):
-
-    implements(IPollEditMenu)
-    schema = IPoll
-    label = "Edit poll details"
-    field_names = ["name", "title", "proposition", "allowspoilt", "dateopens",
-                   "datecloses"]
-
-    @property
-    def cancel_url(self):
-        """See `LaunchpadFormView`."""
-        return canonical_url(self.context)
-
-    @action("Save", name="save")
-    def save_action(self, action, data):
-        self.updateContextFromData(data)
-        self.next_url = canonical_url(self.context)
-
-
-class PollOptionEditView(LaunchpadEditFormView):
-    """Edit one of a poll's options."""
-
-    schema = IPollOption
-    label = "Edit option details"
-    field_names = ["name", "title"]
-    custom_widget("title", TextWidget, width=30)
-
-    @property
-    def cancel_url(self):
-        """See `LaunchpadFormView`."""
-        return canonical_url(self.context.poll)
-
-    @action("Save", name="save")
-    def save_action(self, action, data):
-        self.updateContextFromData(data)
-        self.next_url = canonical_url(self.context.poll)
-
-
-class PollOptionAddView(LaunchpadFormView):
-    """Create a new option in a given poll."""
-
-    schema = IPollOption
-    label = "Create new poll option"
-    field_names = ["name", "title"]
-    custom_widget("title", TextWidget, width=30)
-
-    @property
-    def cancel_url(self):
-        """See `LaunchpadFormView`."""
-        return canonical_url(self.context)
-
-    @action("Create", name="create")
-    def create_action(self, action, data):
-        polloption = self.context.newOption(data['name'], data['title'])
-        self.next_url = canonical_url(self.context)
-        notify(ObjectCreatedEvent(polloption))

=== removed file 'lib/lp/registry/browser/tests/poll-views.txt'
--- lib/lp/registry/browser/tests/poll-views.txt	2009-12-15 20:33:49 +0000
+++ lib/lp/registry/browser/tests/poll-views.txt	1970-01-01 00:00:00 +0000
@@ -1,134 +0,0 @@
-Poll views
-----------
-
-The polls portlet shows the state of current polls, and links to past
-polls.
-
-    >>> from canonical.launchpad.testing.pages import extract_text
-
-    >>> user = factory.makePerson()
-    >>> team = factory.makeTeam(name='team')
-    >>> owner = team.teamowner
-
-    >>> def create_team_view(team, name=None, principal=None):
-    ...     # XRDS inheritance requires a lot of setup.
-    ...     path_info = '/~%s' % team.name
-    ...     server_url = 'http://launchpad.dev'
-    ...     view = create_view(
-    ...         team, name=name, principal=principal,
-    ...         server_url=server_url, path_info=path_info)
-    ...     view.initialize()
-    ...     return view
-
-The portlet does not render any markup when there are no polls...
-
-    >>> login_person(user)
-    >>> view = create_team_view(team, name='+portlet-polls', principal=user)
-    >>> view.has_current_polls
-    False
-
-    >>> view.should_show_polls_portlet
-    False
-
-    >>> print extract_text(view.render())
-    <BLANKLINE>
-
-Unless the user is a team owner.
-
-    >>> login_person(owner)
-    >>> view = create_team_view(team, name='+portlet-polls', principal=owner)
-    >>> view.has_current_polls
-    False
-
-    >>> view.should_show_polls_portlet
-    True
-
-    >>> print extract_text(view.render())
-    Polls
-    No current polls.
-    Show polls
-    Create a poll
-
-The portlet shows a link to polls to all users when there is a poll, but it
-has not opened.
-
-    >>> import pytz
-    >>> from datetime import datetime, timedelta
-    >>> from lp.registry.interfaces.poll import IPollSubset, PollSecrecy
-
-    >>> open_date = datetime.now().replace(tzinfo=pytz.timezone('UTC'))
-    >>> close_date = open_date + timedelta(weeks=1)
-    >>> poll_subset = IPollSubset(team)
-    >>> poll = poll_subset.new(
-    ...     'name', 'title', 'proposition', open_date, close_date,
-    ...     PollSecrecy.OPEN, False)
-
-    >>> login_person(user)
-    >>> view = create_team_view(team, name='+portlet-polls', principal=user)
-    >>> view.has_current_polls
-    True
-
-    >>> view.should_show_polls_portlet
-    True
-
-    >>> print extract_text(view.render())
-    Polls
-    Show polls
-
-The portlet shows more details to the poll owner.
-
-    >>> login_person(owner)
-    >>> view = create_team_view(team, name='+portlet-polls', principal=owner)
-    >>> view.has_current_polls
-    True
-
-    >>> view.should_show_polls_portlet
-    True
-
-    >>> print extract_text(view.render())
-    Polls
-    title - opens in 5 hours
-    Show polls
-    Create a poll
-
-Current polls are listed in the portlet, the only difference between a user
-and an owner is the owner has a link to create more polls.
-
-    >>> poll.dateopens = open_date - timedelta(weeks=2)
-
-    >>> login_person(user)
-    >>> view = create_team_view(team, name='+portlet-polls', principal=user)
-    >>> print extract_text(view.render())
-    Polls
-    title - closes on ...
-    You have seven days left to vote in this poll.
-    Show polls
-
-    >>> login_person(owner)
-    >>> view = create_team_view(team, name='+portlet-polls', principal=owner)
-    >>> print extract_text(view.render())
-    Polls
-    title - closes on ...
-    You have seven days left to vote in this poll.
-    Show polls
-    Create a poll
-
-When all the polls are closed, the portlet states the case and has a link to
-see the polls.
-
-    >>> poll.datecloses = close_date - timedelta(weeks=2)
-
-    >>> login_person(user)
-    >>> view = create_team_view(team, name='+portlet-polls', principal=user)
-    >>> print extract_text(view.render())
-    Polls
-    No current polls.
-    Show polls
-
-    >>> login_person(owner)
-    >>> view = create_team_view(team, name='+portlet-polls', principal=owner)
-    >>> print extract_text(view.render())
-    Polls
-    No current polls.
-    Show polls
-    Create a poll

=== removed file 'lib/lp/registry/browser/tests/poll-views_0.txt'
--- lib/lp/registry/browser/tests/poll-views_0.txt	2010-10-18 22:24:59 +0000
+++ lib/lp/registry/browser/tests/poll-views_0.txt	1970-01-01 00:00:00 +0000
@@ -1,92 +0,0 @@
-= Poll Pages =
-
-First import some stuff and setup some things we'll use in this test.
-
-  >>> from zope.component import getUtility, getMultiAdapter
-  >>> from zope.publisher.browser import TestRequest
-  >>> from canonical.launchpad.webapp.servers import LaunchpadTestRequest
-  >>> from lp.registry.interfaces.person import IPersonSet
-  >>> from lp.registry.interfaces.poll import IPollSet
-  >>> from datetime import datetime, timedelta
-  >>> login("test@xxxxxxxxxxxxx")
-  >>> ubuntu_team = getUtility(IPersonSet).getByName('ubuntu-team')
-
-
-== Creating new polls ==
-
-When creating a new poll, its start date must be at least 12h after it is
-created.
-
-First we attempt to create a poll which starts 11h from now.  That will fail
-with a proper explanation of why it failed.
-
-  >>> eleven_hours_from_now = datetime.now() + timedelta(hours=11)
-  >>> eleven_hours_from_now = eleven_hours_from_now.strftime(
-  ...     '%Y-%m-%d %H:%M:%S')
-  >>> form = {
-  ...     'field.name': 'test-poll',
-  ...     'field.title': 'test-poll',
-  ...     'field.proposition': 'test-poll',
-  ...     'field.allowspoilt': '1',
-  ...     'field.secrecy': 'SECRET',
-  ...     'field.dateopens': eleven_hours_from_now,
-  ...     'field.datecloses': '2025-06-04',
-  ...     'field.actions.continue': 'Continue'}
-  >>> request = LaunchpadTestRequest(method='POST', form=form)
-  >>> new_poll = getMultiAdapter((ubuntu_team, request), name="+newpoll")
-  >>> new_poll.initialize()
-  >>> print "\n".join(new_poll.errors)
-  A poll cannot open less than 12 hours after it's created.
-
-Now we successfully create a poll which starts 12h from now.
-
-  >>> twelve_hours_from_now = datetime.now() + timedelta(hours=12)
-  >>> twelve_hours_from_now = twelve_hours_from_now.strftime(
-  ...     '%Y-%m-%d %H:%M:%S')
-  >>> form['field.dateopens'] = twelve_hours_from_now
-  >>> request = LaunchpadTestRequest(method='POST', form=form)
-  >>> new_poll = getMultiAdapter((ubuntu_team, request), name="+newpoll")
-  >>> new_poll.initialize()
-  >>> new_poll.errors
-  []
-
-
-== Displaying results of condorcet polls ==
-
-  >>> poll = getUtility(IPollSet).getByTeamAndName(ubuntu_team, 'director-2004')
-  >>> poll.type.title
-  'Condorcet Voting'
-
-Although condorcet polls are disabled now, everything is implemented and we're
-using a pairwise matrix to display the results. It's very trick to create this
-matrix on page templates, so the view provides a method wich return this
-matrix as a python list, with the necessary headers (the option's names).
-
-  >>> poll_results = getMultiAdapter((poll, TestRequest()), name="+index")
-  >>> for row in poll_results.getPairwiseMatrixWithHeaders():
-  ...     print row
-  [None, u'A', u'B', u'C', u'D']
-  [u'A', None, 2L, 2L, 2L]
-  [u'B', 2L, None, 2L, 2L]
-  [u'C', 1L, 1L, None, 1L]
-  [u'D', 2L, 1L, 2L, None]
-
-== Voting on closed polls ==
-
-This is not allowed, and apart from not linking to the +vote page and not
-even displaying its content for a closed poll, we also have some lower
-level checks.
-
-    >>> request = TestRequest(form={'changevote': 'Change Vote'})
-    >>> request.method = 'POST'
-    >>> voting_page = getMultiAdapter((poll, request), name="+vote")
-    >>> form_processed = False
-    >>> def form_processing():
-    ...     form_processed = True
-    >>> voting_page.processCondorcetVotingForm = form_processing
-    >>> voting_page.initialize()
-
-    >>> form_processed
-    False
-    >>> voting_page.feedback
-    'This poll is not open.'

=== modified file 'lib/lp/registry/browser/tests/test_breadcrumbs.py'
--- lib/lp/registry/browser/tests/test_breadcrumbs.py	2010-11-30 13:41:48 +0000
+++ lib/lp/registry/browser/tests/test_breadcrumbs.py	2010-12-15 22:26:18 +0000
@@ -105,26 +105,6 @@
         self.assertEqual(self.milestone.name, last_crumb.text)
 
 
-class TestPollBreadcrumb(BaseBreadcrumbTestCase):
-    """Test breadcrumbs for an `IPoll`."""
-
-    def setUp(self):
-        super(TestPollBreadcrumb, self).setUp()
-        self.team = self.factory.makeTeam(displayname="Poll Team")
-        name = "pollo-poll"
-        title = "Marco Pollo"
-        proposition = "Be mine"
-        self.poll = self.factory.makePoll(
-            team=self.team,
-            name=name,
-            title=title,
-            proposition=proposition)
-
-    def test_poll(self):
-        crumbs = self.getBreadcrumbsForObject(self.poll)
-        last_crumb = crumbs[-1]
-        self.assertEqual(self.poll.title, last_crumb.text)
-
 from lp.registry.interfaces.nameblacklist import INameBlacklistSet
 
 

=== removed file 'lib/lp/registry/browser/tests/test_poll.py'
--- lib/lp/registry/browser/tests/test_poll.py	2010-10-11 17:44:05 +0000
+++ lib/lp/registry/browser/tests/test_poll.py	1970-01-01 00:00:00 +0000
@@ -1,38 +0,0 @@
-# Copyright 2010 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Tests for IPoll views."""
-
-__metaclass__ = type
-
-import os
-from canonical.testing.layers import DatabaseFunctionalLayer
-from lp.registry.interfaces.poll import PollAlgorithm
-from lp.testing import TestCaseWithFactory
-from lp.testing.views import create_view
-
-
-class TestPollVoteView(TestCaseWithFactory):
-
-    layer = DatabaseFunctionalLayer
-
-    def setUp(self):
-        super(TestPollVoteView, self).setUp()
-        self.team = self.factory.makeTeam()
-
-    def test_simple_poll_template(self):
-        poll = self.factory.makePoll(
-            self.team, 'name', 'title', 'proposition',
-            poll_type=PollAlgorithm.SIMPLE)
-        view = create_view(poll, name='+vote')
-        self.assertEqual(
-            'poll-vote-simple.pt', os.path.basename(view.template.filename))
-
-    def test_condorcet_poll_template(self):
-        poll = self.factory.makePoll(
-            self.team, 'name', 'title', 'proposition',
-            poll_type=PollAlgorithm.CONDORCET)
-        view = create_view(poll, name='+vote')
-        self.assertEqual(
-            'poll-vote-condorcet.pt',
-            os.path.basename(view.template.filename))

=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml	2010-12-06 17:33:19 +0000
+++ lib/lp/registry/configure.zcml	2010-12-15 22:26:18 +0000
@@ -689,109 +689,6 @@
                 interface="lp.registry.interfaces.karma.IKarmaActionSet"/>
         </securedutility>
     </facet>
-    <facet
-        facet="overview">
-
-        <!-- Poll -->
-
-        <class
-            class="lp.registry.model.poll.Poll">
-            <allow
-                interface="lp.registry.interfaces.poll.IPoll"/>
-            <require
-                permission="launchpad.Edit"
-                set_schema="lp.registry.interfaces.poll.IPoll"/>
-        </class>
-
-        <adapter
-            provides="canonical.launchpad.webapp.interfaces.IBreadcrumb"
-            for="lp.registry.interfaces.poll.IPoll"
-            factory="lp.registry.browser.poll.PollBreadcrumb"
-            permission="zope.Public"/>
-
-        <!-- PollOption -->
-
-        <class
-            class="lp.registry.model.poll.PollOption">
-            <allow
-                interface="lp.registry.interfaces.poll.IPollOption"/>
-            <require
-                permission="launchpad.Edit"
-                set_schema="lp.registry.interfaces.poll.IPollOption"/>
-        </class>
-
-        <!-- Vote -->
-
-
-        <!-- Can't require launchpad.Edit to set_attributes because in most cases
-                the vote won't be associated with a person, and thus we can't check it
-                against the logged in user. -->
-
-        <class
-            class="lp.registry.model.poll.Vote">
-            <allow
-                interface="lp.registry.interfaces.poll.IVote"/>
-            <require
-                permission="zope.Public"
-                set_attributes="option preference"/>
-        </class>
-
-        <!-- VoteCast -->
-
-        <class
-            class="lp.registry.model.poll.VoteCast">
-            <allow
-                interface="lp.registry.interfaces.poll.IVoteCast"/>
-        </class>
-
-        <!-- PollSet -->
-
-        <class
-            class="lp.registry.model.poll.PollSet">
-            <allow
-                interface="lp.registry.interfaces.poll.IPollSet"/>
-        </class>
-        <securedutility
-            class="lp.registry.model.poll.PollSet"
-            provides="lp.registry.interfaces.poll.IPollSet">
-            <allow
-                interface="lp.registry.interfaces.poll.IPollSet"/>
-        </securedutility>
-
-        <!-- PollSubset -->
-
-        <adapter
-            for="lp.registry.interfaces.person.ITeam"
-            provides="lp.registry.interfaces.poll.IPollSubset"
-            factory="lp.registry.adapters.PollSubset"
-            permission="zope.Public"/>
-
-        <!-- PollOptionSet -->
-
-        <class
-            class="lp.registry.model.poll.PollOptionSet">
-            <allow
-                interface="lp.registry.interfaces.poll.IPollOptionSet"/>
-        </class>
-        <securedutility
-            class="lp.registry.model.poll.PollOptionSet"
-            provides="lp.registry.interfaces.poll.IPollOptionSet">
-            <allow
-                interface="lp.registry.interfaces.poll.IPollOptionSet"/>
-        </securedutility>
-        <securedutility
-            class="lp.registry.model.poll.VoteSet"
-            provides="lp.registry.interfaces.poll.IVoteSet">
-            <allow
-                interface="lp.registry.interfaces.poll.IVoteSet"/>
-        </securedutility>
-        <securedutility
-            class="lp.registry.model.poll.VoteCastSet"
-            provides="lp.registry.interfaces.poll.IVoteCastSet">
-            <allow
-                interface="lp.registry.interfaces.poll.IVoteCastSet"/>
-        </securedutility>
-    </facet>
 
     <!-- Announcement -->
 

=== modified file 'lib/lp/registry/doc/person-merge.txt'
--- lib/lp/registry/doc/person-merge.txt	2010-12-01 23:39:05 +0000
+++ lib/lp/registry/doc/person-merge.txt	2010-12-15 22:26:18 +0000
@@ -1,4 +1,5 @@
-= Merging =
+Merging
+=======
 
 For many reasons (i.e. a gina run) we could have duplicated accounts in
 Launchpad. Once a duplicated account is identified, we need to allow the user
@@ -19,7 +20,8 @@
     >>> marilize = personset.getByName('marilize')
 
 
-== Sanity checks ==
+Sanity checks
+-------------
 
 We can't merge an account that still has email addresses attached to it
 
@@ -29,7 +31,8 @@
     AssertionError: ...
 
 
-== Preparing test person for the merge ==
+Preparing test person for the merge
+-----------------------------------
 
 Merging people involves updating the merged person relationships. Let's
 put the person we will merge into some of those.
@@ -57,10 +60,11 @@
     marilize
     >>> sampleperson_old_karma = sample.karma
 
-Branches whose owner is being merged are uniquified by appending '-N' where N
-is a unique integer. We create "peoplemerge" and "peoplemerge-1" branches owned
-by marilize, and a "peoplemerge" and "peoplemerge-1" branches owned by 'Sample
-Person' to test that branch name uniquifying works.
+Branches whose owner is being merged are uniquified by appending '-N'
+where N is a unique integer. We create "peoplemerge" and
+"peoplemerge-1" branches owned by marilize, and a "peoplemerge" and
+"peoplemerge-1" branches owned by 'Sample Person' to test that branch
+name uniquifying works.
 
 Branches with smaller IDs will be processed first, so we create "peoplemerge"
 first, and it will be renamed "peoplemerge-2". The extant "peoplemerge-1"
@@ -81,9 +85,9 @@
     >>> peoplemerge11 = factory.makePersonalBranch(
     ...     name='peoplemerge-1', owner=marilize)
 
-'Sample Person' is a deactivated member of the 'Ubuntu Translators' team,
-while marilize is an active member. After the merge, 'Sample Person' will be an
-active member of that team.
+'Sample Person' is a deactivated member of the 'Ubuntu Translators'
+team, while marilize is an active member. After the merge, 'Sample
+Person' will be an active member of that team.
 
     >>> sample in ubuntu_translators.inactivemembers
     True
@@ -102,7 +106,8 @@
     u'Marilize Coetzee'
 
 
-== Do the merge! ==
+Do the merge!
+-------------
 
     # Now we remove the only email address marilize had, so that we can merge
     # it.  First we need to change its status, though, because we can't delete
@@ -119,7 +124,8 @@
     >>> personset.merge(marilize, sample)
 
 
-== Merge results ==
+Merge results
+-------------
 
 Check that 'Sample Person' has indeed become an active member of 'Ubuntu
 Translators'
@@ -336,37 +342,30 @@
     loser, winner,
 
 
-== Merging teams ==
+Merging teams
+-------------
 
 Merging of teams is also possible and uses the same API used for merging
-people.  Note, though, that when merging teams, its polls will not be
-carried over to the remaining team.  Team memberships, on the other hand,
-are carried over just like when merging people.
+people.  Team memberships are carried over just like when merging people.
 
     >>> from datetime import datetime, timedelta
     >>> import pytz
-    >>> from lp.registry.interfaces.poll import IPollSubset, PollSecrecy
     >>> test_team = personset.newTeam(sample, 'test-team', 'Test team')
     >>> launchpad_devs = personset.getByName('launchpad')
     >>> ignored = launchpad_devs.addMember(
     ...     test_team, reviewer=launchpad_devs.teamowner, force_team_add=True)
-    >>> today = datetime.now(pytz.timezone('UTC'))
+    >>> today = datetime.now(pytz.UTC)
     >>> tomorrow = today + timedelta(days=1)
-    >>> poll = IPollSubset(test_team).new(
-    ...     'test-poll', 'Title', 'Proposition', today, tomorrow,
-    ...     PollSecrecy.OPEN, allowspoilt=True)
 
-    # test_team has a superteam, one active member and a poll.
+    # test_team has a superteam and one active member.
     >>> [team.name for team in test_team.super_teams]
     [u'launchpad']
     >>> test_team.teamowner.name
     u'name12'
     >>> [member.name for member in test_team.allmembers]
     [u'name12']
-    >>> list(IPollSubset(test_team).getAll())
-    [<Poll at ...]
 
-    # Landscape-developers has no super teams, two members and no polls.
+    # Landscape-developers has no super teams and two members.
     >>> landscape = personset.getByName('landscape-developers')
     >>> [team.name for team in landscape.super_teams]
     []
@@ -374,8 +373,6 @@
     u'name12'
     >>> [member.name for member in landscape.allmembers]
     [u'salgado', u'name12']
-    >>> list(IPollSubset(landscape).getAll())
-    []
 
 Now we try to merge them, but since test_team has active members it can't be
 merged.
@@ -427,14 +424,11 @@
     ...     test_team.retractTeamMembership(team, test_team.teamowner)
     >>> personset.merge(test_team, landscape)
 
-    # The resulting Landscape-developers no new super teams, has
-    # no polls and its members are still the same two from before the
-    # merge.
+    # The resulting Landscape-developers no new super teams and its
+    # members are still the same two from before the merge.
     >>> landscape.teamowner.name
     u'name12'
     >>> [member.name for member in landscape.allmembers]
     [u'salgado', u'name12']
     >>> [team.name for team in landscape.super_teams]
     []
-    >>> list(IPollSubset(landscape).getAll())
-    []

=== removed file 'lib/lp/registry/doc/poll-preconditions.txt'
--- lib/lp/registry/doc/poll-preconditions.txt	2010-10-18 22:24:59 +0000
+++ lib/lp/registry/doc/poll-preconditions.txt	1970-01-01 00:00:00 +0000
@@ -1,74 +0,0 @@
-Poll preconditions
-==================
-
-There's some preconditions that we need to meet to vote in polls and remove
-options from them, Not meeting these preconditions is a programming error and
-should be threated as so.
-
-  >>> from zope.component import getUtility
-  >>> from canonical.database.sqlbase import flush_database_updates
-  >>> from canonical.launchpad.ftests import login
-  >>> from datetime import timedelta
-  >>> from lp.registry.interfaces.person import IPersonSet
-  >>> from lp.registry.interfaces.poll import IPollSet
-
-  >>> ubuntu_team = getUtility(IPersonSet).get(17)
-  >>> ubuntu_team_member = getUtility(IPersonSet).get(1)
-  >>> ubuntu_team_nonmember = getUtility(IPersonSet).get(12)
-
-  >>> pollset = getUtility(IPollSet)
-  >>> director_election = pollset.getByTeamAndName(ubuntu_team,
-  ...                                              'director-2004')
-  >>> director_options = director_election.getActiveOptions()
-  >>> leader_election = pollset.getByTeamAndName(ubuntu_team, 'leader-2004')
-  >>> leader_options = leader_election.getActiveOptions()
-  >>> opendate = leader_election.dateopens
-  >>> onesec = timedelta(seconds=1)
-
-
-If the poll is already opened, it's impossible to remove an option.
-
-  >>> leader_election.removeOption(leader_options[0], when=opendate)
-  Traceback (most recent call last):
-  ...
-  AssertionError
-
-
-Trying to vote two times is a programming error.
-  
-  >>> votes = leader_election.storeSimpleVote(
-  ...     ubuntu_team_member, leader_options[0], when=opendate)
-
-  >>> votes = leader_election.storeSimpleVote(
-  ...     ubuntu_team_member, leader_options[0], when=opendate)
-  Traceback (most recent call last):
-  ...
-  AssertionError: Can't vote twice in the same poll
-
-
-It's not possible for a non-member to vote, neither to vote when the poll is
-not open.
-
-  >>> votes = leader_election.storeSimpleVote(
-  ...     ubuntu_team_nonmember, leader_options[0], when=opendate)
-  Traceback (most recent call last):
-  ...
-  AssertionError: Person ... is not a member of this poll's team.
-
-  >>> votes = leader_election.storeSimpleVote(
-  ...     ubuntu_team_member, leader_options[0], when=opendate - onesec)
-  Traceback (most recent call last):
-  ...
-  AssertionError: This poll is not open
-
-
-It's not possible to vote on an option that doesn't belong to the poll you're
-voting in.
-
-  >>> options = {leader_options[0]: 1}
-  >>> votes = director_election.storeCondorcetVote(
-  ...     ubuntu_team_member, options, when=opendate)
-  Traceback (most recent call last):
-  ...
-  AssertionError: The option ... doesn't belong to this poll
-

=== removed file 'lib/lp/registry/doc/poll.txt'
--- lib/lp/registry/doc/poll.txt	2010-10-19 18:44:31 +0000
+++ lib/lp/registry/doc/poll.txt	1970-01-01 00:00:00 +0000
@@ -1,140 +0,0 @@
-Polls
-=====
-
-In Launchpad, we have teams as a way to group free software
-developers/contributors usually based on the free software
-product/project/distribution they're involved in. This is the case with teams
-like the 'Gnome Team' and the 'Ubuntu Team'. These teams often have leaders
-whose ellection depends on the vote of all members, and this is one of the
-reasons why we teams can have polls attached to them.
-
-  >>> import pytz
-  >>> from datetime import datetime, timedelta
-  >>> from zope.component import getUtility
-  >>> from canonical.database.sqlbase import flush_database_updates
-  >>> from canonical.launchpad.ftests import login
-  >>> from lp.registry.interfaces.person import IPersonSet
-  >>> from lp.registry.interfaces.poll import (
-  ...     IPollSubset,
-  ...     PollAlgorithm,
-  ...     PollSecrecy,
-  ...     )
-
-  >>> team = getUtility(IPersonSet).getByName('ubuntu-team')
-  >>> member = getUtility(IPersonSet).getByName('stevea')
-  >>> member2 = getUtility(IPersonSet).getByName('jdub')
-  >>> member3 = getUtility(IPersonSet).getByName('kamion')
-  >>> member4 = getUtility(IPersonSet).getByName('name16')
-  >>> member5 = getUtility(IPersonSet).getByName('limi')
-  >>> nonmember = getUtility(IPersonSet).getByName('justdave')
-  >>> now = datetime.now(pytz.timezone('UTC'))
-  >>> onesec = timedelta(seconds=1)
-
-We need to login with one of the administrators of the team named 
-'ubuntu-team' to be able to create/edit polls.
-  >>> login('colin.watson@xxxxxxxxxxxxxxx')
-
-First we get an object implementing IPollSubset, which is the set of polls for
-a given team (in our case, the 'Ubuntu Team')
-  >>> pollsubset = IPollSubset(team)
-
-Now we create a new poll on this team.
-  >>> opendate = datetime(2005, 01, 01, tzinfo=pytz.timezone('UTC'))
-  >>> closedate = opendate + timedelta(weeks=2)
-  >>> title = "2005 Leader's Elections"
-  >>> proposition = "Who's going to be the next leader?"
-  >>> type = PollAlgorithm.SIMPLE
-  >>> secrecy = PollSecrecy.SECRET
-  >>> allowspoilt = True
-  >>> poll = pollsubset.new("leader-election", title, proposition, opendate,
-  ...                       closedate, secrecy, allowspoilt, type)
-
-Now we test the if the poll is open or closed in some specific dates.
-  >>> poll.isOpen(when=opendate)
-  True
-  >>> poll.isOpen(when=opendate - onesec)
-  False
-  >>> poll.isOpen(when=closedate)
-  True
-  >>> poll.isOpen(when=closedate + onesec)
-  False
-
-To know what polls are open/closed/not-yet-opened in a team, you can use the
-methods of PollSubset.
-Here we'll query using three different dates:
-
-Query for open polls in the exact second the poll is opening.
-  >>> [p.name for p in pollsubset.getOpenPolls(when=opendate)]
-  [u'leader-election', u'never-closes', u'never-closes2', u'never-closes3',
-   u'never-closes4']
-
-Query for closed polls, one second after the poll closes.
-  >>> [p.name for p in pollsubset.getClosedPolls(when=closedate + onesec)]
-  [u'director-2004', u'leader-2004', u'leader-election']
-
-Query for not-yet-opened polls, one second before the poll opens.
-  >>> [p.name for p in pollsubset.getNotYetOpenedPolls(when=opendate - onesec)]
-  [u'leader-election', u'not-yet-opened']
-
-All polls must have a set of options for people to choose, and they'll always
-start with zero options. We're responsible for adding new ones.
-  >>> poll.getAllOptions().count()
-  0
-
-Let's add some options to this poll, so people can start voting. :)
-  >>> will = poll.newOption('wgraham', 'Will Graham')
-  >>> jack = poll.newOption('jcrawford', 'Jack Crawford')
-  >>> francis = poll.newOption('fd', 'Francis Dolarhyde')
-  >>> [o.title for o in poll.getActiveOptions()]
-  [u'Francis Dolarhyde', u'Jack Crawford', u'Will Graham']
-
-Now, what happens if the poll is already open and, let's say, Francis Dolarhyde
-is convicted and thus becomes ineligible? We'll have to mark that option as
-inactive, so people can't vote on it.
-  >>> francis.active = False
-  >>> flush_database_updates()
-  >>> [o.title for o in poll.getActiveOptions()]
-  [u'Jack Crawford', u'Will Graham']
-
-If the poll is not yet opened, it's possible to simply remove a given option.
-  >>> poll.removeOption(will, when=opendate - onesec)
-  >>> [o.title for o in poll.getAllOptions()]
-  [u'Francis Dolarhyde', u'Jack Crawford']
-
-Any member of the team this poll refers to is eligible to vote, if the poll is
-still open.
-
-  >>> vote1 = poll.storeSimpleVote(member, jack, when=opendate)
-  >>> vote2 = poll.storeSimpleVote(member2, None, when=opendate)
-
-
-Now we create a Condorcet poll on this team and add some options to it, so
-people can start voting.
-
-  >>> title = "2005 Director's Elections"
-  >>> proposition = "Who's going to be the next director?"
-  >>> type = PollAlgorithm.CONDORCET
-  >>> secrecy = PollSecrecy.SECRET
-  >>> allowspoilt = True
-  >>> poll2 = pollsubset.new("director-election", title, proposition, opendate,
-  ...                        closedate, secrecy, allowspoilt, type)
-  >>> a = poll2.newOption('A', 'Option A')
-  >>> b = poll2.newOption('B', 'Option B')
-  >>> c = poll2.newOption('C', 'Option C')
-  >>> d = poll2.newOption('D', 'Option D')
-
-  >>> options = {b: 1, d: 2, c: 3}
-  >>> votes = poll2.storeCondorcetVote(member, options, when=opendate)
-  >>> options = {d: 1, b: 2}
-  >>> votes = poll2.storeCondorcetVote(member2, options, when=opendate)
-  >>> options = {a: 1, c: 2, b: 3}
-  >>> votes = poll2.storeCondorcetVote(member3, options, when=opendate)
-  >>> options = {a: 1}
-  >>> votes = poll2.storeCondorcetVote(member4, options, when=opendate)
-  >>> for row in poll2.getPairwiseMatrix():
-  ...     print row
-  [None, 2L, 2L, 2L]
-  [2L, None, 2L, 2L]
-  [1L, 1L, None, 1L]
-  [2L, 1L, 2L, None]
-

=== removed file 'lib/lp/registry/interfaces/poll.py'
--- lib/lp/registry/interfaces/poll.py	2010-08-20 20:31:18 +0000
+++ lib/lp/registry/interfaces/poll.py	1970-01-01 00:00:00 +0000
@@ -1,500 +0,0 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-# pylint: disable-msg=E0211,E0213
-
-__all__ = [
-    'IPoll',
-    'IPollSet',
-    'IPollSubset',
-    'IPollOption',
-    'IPollOptionSet',
-    'IVote',
-    'IVoteCast',
-    'PollAlgorithm',
-    'PollSecrecy',
-    'PollStatus',
-    'IVoteSet',
-    'IVoteCastSet',
-    'OptionIsNotFromSimplePoll'
-    ]
-
-from datetime import (
-    datetime,
-    timedelta,
-    )
-
-from lazr.enum import (
-    DBEnumeratedType,
-    DBItem,
-    )
-import pytz
-from zope.component import getUtility
-from zope.interface import (
-    Attribute,
-    Interface,
-    )
-from zope.interface.exceptions import Invalid
-from zope.interface.interface import invariant
-from zope.schema import (
-    Bool,
-    Choice,
-    Datetime,
-    Int,
-    Text,
-    TextLine,
-    )
-
-from canonical.launchpad import _
-from canonical.launchpad.validators.name import name_validator
-from lp.registry.interfaces.person import ITeam
-from lp.services.fields import ContentNameField
-
-
-class PollNameField(ContentNameField):
-
-    errormessage = _("%s is already in use by another poll in this team.")
-
-    @property
-    def _content_iface(self):
-        return IPoll
-
-    def _getByName(self, name):
-        team = ITeam(self.context, None)
-        if team is None:
-            team = self.context.team
-        return getUtility(IPollSet).getByTeamAndName(team, name)
-
-
-class PollAlgorithm(DBEnumeratedType):
-    """The algorithm used to accept and calculate the results."""
-
-    SIMPLE = DBItem(1, """
-        Simple Voting
-
-        The most simple method for voting; you just choose a single option.
-        """)
-
-    CONDORCET = DBItem(2, """
-        Condorcet Voting
-
-        One of various methods used for calculating preferential votes. See
-        http://www.electionmethods.org/CondorcetEx.htm for more information.
-        """)
-
-
-class PollSecrecy(DBEnumeratedType):
-    """The secrecy of a given Poll."""
-
-    OPEN = DBItem(1, """
-        Public Votes (Anyone can see a person's vote)
-
-        Everyone who wants will be able to see a person's vote.
-        """)
-
-    ADMIN = DBItem(2, """
-        Semi-secret Votes (Only team administrators can see a person's vote)
-
-        All team owners and administrators will be able to see a person's vote.
-        """)
-
-    SECRET = DBItem(3, """
-        Secret Votes (It's impossible to track a person's vote)
-
-        We don't store the option a person voted in our database,
-        """)
-
-
-class PollStatus:
-    """This class stores the constants used when searching for polls."""
-
-    OPEN = 'open'
-    CLOSED = 'closed'
-    NOT_YET_OPENED = 'not-yet-opened'
-    ALL = frozenset([OPEN, CLOSED, NOT_YET_OPENED])
-
-
-class IPoll(Interface):
-    """A poll for a given proposition in a team."""
-
-    id = Int(title=_('The unique ID'), required=True, readonly=True)
-
-    team = Int(
-        title=_('The team that this poll refers to.'), required=True,
-        readonly=True)
-
-    name = PollNameField(
-        title=_('The unique name of this poll'),
-        description=_('A short unique name, beginning with a lower-case '
-                      'letter or number, and containing only letters, '
-                      'numbers, dots, hyphens, or plus signs.'),
-        required=True, readonly=False, constraint=name_validator)
-
-    title = TextLine(
-        title=_('The title of this poll'), required=True, readonly=False)
-
-    dateopens = Datetime(
-        title=_('The date and time when this poll opens'), required=True,
-        readonly=False)
-
-    datecloses = Datetime(
-        title=_('The date and time when this poll closes'), required=True,
-        readonly=False)
-
-    proposition = Text(
-        title=_('The proposition that is going to be voted'), required=True,
-        readonly=False)
-
-    type = Choice(
-        title=_('The type of this poll'), required=True,
-        readonly=False, vocabulary=PollAlgorithm,
-        default=PollAlgorithm.CONDORCET)
-
-    allowspoilt = Bool(
-        title=_('Users can spoil their votes?'),
-        description=_(
-            'Allow users to leave the ballot blank (i.e. cast a vote for '
-            '"None of the above")'),
-        required=True, readonly=False, default=True)
-
-    secrecy = Choice(
-        title=_('The secrecy of the Poll'), required=True,
-        readonly=False, vocabulary=PollSecrecy,
-        default=PollSecrecy.SECRET)
-
-    @invariant
-    def saneDates(poll):
-        """Ensure the poll's dates are sane.
-
-        A poll's end date must be after its start date and its start date must
-        be at least 12h from now.
-        """
-        if poll.dateopens >= poll.datecloses:
-            raise Invalid(
-                "A poll cannot close at the time (or before) it opens.")
-        now = datetime.now(pytz.UTC)
-        twelve_hours_ahead = now + timedelta(hours=12)
-        start_date = poll.dateopens.astimezone(pytz.UTC)
-        if start_date < twelve_hours_ahead:
-            raise Invalid(
-                "A poll cannot open less than 12 hours after it's created.")
-
-    def isOpen(when=None):
-        """Return True if this Poll is still open.
-
-        The optional :when argument is used only by our tests, to test if the
-        poll is/was/will be open at a specific date.
-        """
-
-    def isClosed(when=None):
-        """Return True if this Poll is already closed.
-
-        The optional :when argument is used only by our tests, to test if the
-        poll is/was/will be closed at a specific date.
-        """
-
-    def isNotYetOpened(when=None):
-        """Return True if this Poll is not yet opened.
-
-        The optional :when argument is used only by our tests, to test if the
-        poll is/was/will be not-yet-opened at a specific date.
-        """
-
-    def closesIn():
-        """Return a timedelta object of the interval between now and the date
-        when this poll closes."""
-
-    def opensIn():
-        """Return a timedelta object of the interval between now and the date
-        when this poll opens."""
-
-    def newOption(name, title=None, active=True):
-        """Create a new PollOption for this poll.
-
-        If title is None it'll be the same as name.
-        """
-
-    def getActiveOptions():
-        """Return all PollOptions of this poll that are active."""
-
-    def getAllOptions():
-        """Return all Options of this poll."""
-
-    def personVoted(person):
-        """Return True if :person has already voted in this poll."""
-
-    def getVotesByPerson(person):
-        """Return the votes of the given person in this poll.
-
-        The return value will always be a list of Vote objects. That's for
-        consistency because on simple polls there'll be always a single vote,
-        but for condorcet poll, there'll always be a list.
-        """
-
-    def getTotalVotes():
-        """Return the total number of votes this poll had.
-
-        This must be used only on closed polls.
-        """
-
-    def getWinners():
-        """Return the options which won this poll.
-
-        This should be used only on closed polls.
-        """
-
-    def removeOption(option, when=None):
-        """Remove the given option from this poll.
-
-        A ValueError is raised if the given option doesn't belong to this poll.
-        This method can be used only on polls that are not yet opened.
-        The optional :when argument is used only by our tests, to test if the
-        poll is/was/will be not-yet-opened at a specific date.
-        """
-
-    def getOptionByName(name):
-        """Return the PollOption by the given name."""
-
-    def storeSimpleVote(person, option, when=None):
-        """Store and return the vote of a given person in a this poll.
-
-        This method can be used only if this poll is still open and if this is
-        a Simple-style poll.
-
-        :option: The choosen option.
-
-        :when: Optional argument used only by our tests, to test if the poll
-               is/was/will be open at a specific date.
-        """
-
-    def storeCondorcetVote(person, options, when=None):
-        """Store and return the votes of a given person in this poll.
-
-        This method can be used only if this poll is still open and if this is
-        a Condorcet-style poll.
-
-        :options: A dictionary, where the options are the keys and the
-                  preferences of each option are the values.
-
-        :when: Optional argument used only by our tests, to test if the poll
-               is/was/will be open at a specific date.
-        """
-
-    def getPairwiseMatrix():
-        """Return the pairwise matrix for this poll.
-
-        This method is only available for condorcet-style polls.
-        See http://www.electionmethods.org/CondorcetEx.htm for an example of a
-        pairwise matrix.
-        """
-
-
-class IPollSet(Interface):
-    """The set of Poll objects."""
-
-    def new(team, name, title, proposition, dateopens, datecloses,
-            secrecy, allowspoilt, poll_type=PollAlgorithm.SIMPLE):
-        """Create a new Poll for the given team."""
-
-    def selectByTeam(team, status=PollStatus.ALL, orderBy=None, when=None):
-        """Return all Polls for the given team, filtered by status.
-
-        :status: is a sequence containing as many values as you want from
-        PollStatus.
-
-        :orderBy: can be either a string with the column name you want to sort
-        or a list of column names as strings.
-        If no orderBy is specified the results will be ordered using the
-        default ordering specified in Poll._defaultOrder.
-
-        The optional :when argument is used only by our tests, to test if the
-        poll is/was/will-be open at a specific date.
-        """
-
-    def getByTeamAndName(team, name, default=None):
-        """Return the Poll for the given team with the given name.
-
-        Return :default if there's no Poll with this name for that team.
-        """
-
-
-class IPollSubset(Interface):
-    """The set of Poll objects for a given team."""
-
-    team = Attribute(_("The team of these polls."))
-
-    title = Attribute('Polls Page Title')
-
-    def new(name, title, proposition, dateopens, datecloses, secrecy,
-            allowspoilt, poll_type=PollAlgorithm.SIMPLE):
-        """Create a new Poll for this team."""
-
-    def getAll():
-        """Return all Polls of this team."""
-
-    def getOpenPolls(when=None):
-        """Return all Open Polls for this team ordered by the date they'll
-        close.
-
-        The optional :when argument is used only by our tests, to test if the
-        poll is/was/will be open at a specific date.
-        """
-
-    def getNotYetOpenedPolls(when=None):
-        """Return all Not-Yet-Opened Polls for this team ordered by the date
-        they'll open.
-
-        The optional :when argument is used only by our tests, to test if the
-        poll is/was/will be open at a specific date.
-        """
-
-    def getClosedPolls(when=None):
-        """Return all Closed Polls for this team ordered by the date they
-        closed.
-
-        The optional :when argument is used only by our tests, to test if the
-        poll is/was/will be open at a specific date.
-        """
-
-
-class PollOptionNameField(ContentNameField):
-
-    errormessage = _("%s is already in use by another option in this poll.")
-
-    @property
-    def _content_iface(self):
-        return IPollOption
-
-    def _getByName(self, name):
-        if IPollOption.providedBy(self.context):
-            poll = self.context.poll
-        else:
-            poll = self.context
-        return poll.getOptionByName(name)
-
-
-class IPollOption(Interface):
-    """An option to be voted in a given Poll."""
-
-    id = Int(title=_('The unique ID'), required=True, readonly=True)
-
-    poll = Int(
-        title=_('The Poll to which this option refers to.'), required=True,
-        readonly=True)
-
-    name = PollOptionNameField(
-        title=_('Name'), required=True, readonly=False)
-
-    title = TextLine(
-        title=_('Title'),
-        description=_(
-            'The title of this option. A single brief sentence that '
-            'summarises the outcome for which people are voting if '
-            'they select this option.'),
-        required=True, readonly=False)
-
-    active = Bool(
-        title=_('Is this option active?'), required=True, readonly=False,
-        default=True)
-
-    def destroySelf():
-        """Remove this option from the database."""
-
-
-class IPollOptionSet(Interface):
-    """The set of PollOption objects."""
-
-    def new(poll, name, title, active=True):
-        """Create a new PollOption."""
-
-    def selectByPoll(poll, only_active=False):
-        """Return all PollOptions of the given poll.
-
-        If :only_active is True, then return only the active polls.
-        """
-
-    def getByPollAndId(poll, id, default=None):
-        """Return the PollOption with the given id.
-
-        Return :default if there's no PollOption with the given id or if that
-        PollOption is not in the given poll.
-        """
-
-
-class IVoteCast(Interface):
-    """Here we store who voted in a Poll, but not their votes."""
-
-    id = Int(title=_('The unique ID'), required=True, readonly=True)
-
-    person = Int(
-        title=_('The Person that voted.'), required=False, readonly=True)
-
-    poll = Int(
-        title=_('The Poll in which the person voted.'), required=True,
-        readonly=True)
-
-
-class IVoteCastSet(Interface):
-    """The set of all VoteCast objects."""
-
-    def new(poll, person):
-        """Create a new VoteCast."""
-
-
-class IVote(Interface):
-    """Here we store the vote itself, linked to a special token.
-
-    This token is given to the user when he votes, so he can change his vote
-    later.
-    """
-
-    id = Int(
-        title=_('The unique ID'), required=True, readonly=True)
-
-    person = Int(
-        title=_('The Person that voted.'), required=False, readonly=True)
-
-    poll = Int(
-        title=_('The Poll in which the person voted.'), required=True,
-        readonly=True)
-
-    option = Int(
-        title=_('The PollOption choosen.'), required=True, readonly=False)
-
-    preference = Int(
-        title=_('The preference of the choosen PollOption'), required=True,
-        readonly=False)
-
-    token = Text(
-        title=_('The token we give to the user.'),
-        required=True, readonly=True)
-
-
-class OptionIsNotFromSimplePoll(Exception):
-    """Someone tried use an option from a non-SIMPLE poll as if it was from a
-    SIMPLE one."""
-
-
-class IVoteSet(Interface):
-    """The set of all Vote objects."""
-
-    def newToken():
-        """Return a token that was never used in the Vote table."""
-
-    def new(poll, option, preference, token, person):
-        """Create a new Vote."""
-
-    def getByToken(token):
-        """Return the list of votes with the given token.
-
-        For polls whose type is SIMPLE, this list will contain a single vote,
-        because in SIMPLE poll only one option can be choosen.
-        """
-
-    def getVotesByOption(option):
-        """Return the number of votes the given option received.
-
-        Raises a TypeError if the given option doesn't belong to a
-        simple-style poll.
-        """
-

=== modified file 'lib/lp/registry/model/person.py'
--- lib/lp/registry/model/person.py	2010-12-10 14:58:31 +0000
+++ lib/lp/registry/model/person.py	2010-12-15 22:26:18 +0000
@@ -3871,20 +3871,10 @@
             ('personlanguage', 'person'),
             ('person', 'merged'),
             ('emailaddress', 'person'),
-            # Polls are not carried over when merging teams.
-            ('poll', 'team'),
             # We can safely ignore the mailinglist table as there's a sanity
             # check above which prevents teams with associated mailing lists
             # from being merged.
             ('mailinglist', 'team'),
-            # I don't think we need to worry about the votecast and vote
-            # tables, because a real human should never have two profiles
-            # in Launchpad that are active members of a given team and voted
-            # in a given poll. -- GuilhermeSalgado 2005-07-07
-            # We also can't afford to change poll results after they are
-            # closed -- StuartBishop 20060602
-            ('votecast', 'person'),
-            ('vote', 'person'),
             ('translationrelicensingagreement', 'person'),
             ]
 

=== removed file 'lib/lp/registry/model/poll.py'
--- lib/lp/registry/model/poll.py	2010-08-20 20:31:18 +0000
+++ lib/lp/registry/model/poll.py	1970-01-01 00:00:00 +0000
@@ -1,440 +0,0 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-# pylint: disable-msg=E0611,W0212
-
-__metaclass__ = type
-__all__ = [
-    'Poll',
-    'PollOption',
-    'PollOptionSet',
-    'PollSet',
-    'VoteCast',
-    'Vote',
-    'VoteSet',
-    'VoteCastSet',
-    ]
-
-from datetime import datetime
-import random
-
-import pytz
-from sqlobject import (
-    AND,
-    BoolCol,
-    ForeignKey,
-    IntCol,
-    OR,
-    SQLObjectNotFound,
-    StringCol,
-    )
-from storm.store import Store
-from zope.component import getUtility
-from zope.interface import implements
-
-from canonical.database.datetimecol import UtcDateTimeCol
-from canonical.database.enumcol import EnumCol
-from canonical.database.sqlbase import (
-    SQLBase,
-    sqlvalues,
-    )
-from lp.registry.interfaces.person import validate_public_person
-from lp.registry.interfaces.poll import (
-    IPoll,
-    IPollOption,
-    IPollOptionSet,
-    IPollSet,
-    IVote,
-    IVoteCast,
-    IVoteCastSet,
-    IVoteSet,
-    OptionIsNotFromSimplePoll,
-    PollAlgorithm,
-    PollSecrecy,
-    PollStatus,
-    )
-
-
-class Poll(SQLBase):
-    """See IPoll."""
-
-    implements(IPoll)
-    _table = 'Poll'
-    sortingColumns = ['title', 'id']
-    _defaultOrder = sortingColumns
-
-    team = ForeignKey(
-        dbName='team', foreignKey='Person',
-        storm_validator=validate_public_person, notNull=True)
-
-    name = StringCol(dbName='name', notNull=True)
-
-    title = StringCol(dbName='title', notNull=True, unique=True)
-
-    dateopens = UtcDateTimeCol(dbName='dateopens', notNull=True)
-
-    datecloses = UtcDateTimeCol(dbName='datecloses', notNull=True)
-
-    proposition = StringCol(dbName='proposition',  notNull=True)
-
-    type = EnumCol(dbName='type', enum=PollAlgorithm,
-                   default=PollAlgorithm.SIMPLE)
-
-    allowspoilt = BoolCol(dbName='allowspoilt', default=True, notNull=True)
-
-    secrecy = EnumCol(dbName='secrecy', enum=PollSecrecy,
-                      default=PollSecrecy.SECRET)
-
-    def newOption(self, name, title, active=True):
-        """See IPoll."""
-        return getUtility(IPollOptionSet).new(self, name, title, active)
-
-    def isOpen(self, when=None):
-        """See IPoll."""
-        if when is None:
-            when = datetime.now(pytz.timezone('UTC'))
-        return (self.datecloses >= when and self.dateopens <= when)
-
-    @property
-    def closesIn(self):
-        """See IPoll."""
-        return self.datecloses - datetime.now(pytz.timezone('UTC'))
-
-    @property
-    def opensIn(self):
-        """See IPoll."""
-        return self.dateopens - datetime.now(pytz.timezone('UTC'))
-
-    def isClosed(self, when=None):
-        """See IPoll."""
-        if when is None:
-            when = datetime.now(pytz.timezone('UTC'))
-        return self.datecloses <= when
-
-    def isNotYetOpened(self, when=None):
-        """See IPoll."""
-        if when is None:
-            when = datetime.now(pytz.timezone('UTC'))
-        return self.dateopens > when
-
-    def getAllOptions(self):
-        """See IPoll."""
-        return getUtility(IPollOptionSet).selectByPoll(self)
-
-    def getActiveOptions(self):
-        """See IPoll."""
-        return getUtility(IPollOptionSet).selectByPoll(self, only_active=True)
-
-    def getVotesByPerson(self, person):
-        """See IPoll."""
-        return Vote.selectBy(person=person, poll=self)
-
-    def personVoted(self, person):
-        """See IPoll."""
-        results = VoteCast.selectBy(person=person, poll=self)
-        return bool(results.count())
-
-    def removeOption(self, option, when=None):
-        """See IPoll."""
-        assert self.isNotYetOpened(when=when)
-        if option.poll != self:
-            raise ValueError(
-                "Can't remove an option that doesn't belong to this poll")
-        option.destroySelf()
-
-    def getOptionByName(self, name):
-        """See IPoll."""
-        return PollOption.selectOneBy(poll=self, name=name)
-
-    def _assertEverythingOkAndGetVoter(self, person, when=None):
-        """Use assertions to Make sure all pre-conditions for a person to vote
-        are met.
-
-        Return the person if this is not a secret poll or None if it's a
-        secret one.
-        """
-        assert self.isOpen(when=when), "This poll is not open"
-        assert not self.personVoted(person), "Can't vote twice in the same poll"
-        assert person.inTeam(self.team), (
-            "Person %r is not a member of this poll's team." % person)
-
-        # We only associate the option with the person if the poll is not a
-        # SECRET one.
-        if self.secrecy == PollSecrecy.SECRET:
-            voter = None
-        else:
-            voter = person
-        return voter
-
-    def storeCondorcetVote(self, person, options, when=None):
-        """See IPoll."""
-        voter = self._assertEverythingOkAndGetVoter(person, when=when)
-        assert self.type == PollAlgorithm.CONDORCET
-        voteset = getUtility(IVoteSet)
-
-        token = voteset.newToken()
-        votes = []
-        activeoptions = self.getActiveOptions()
-        for option, preference in options.items():
-            assert option.poll == self, (
-                "The option %r doesn't belong to this poll" % option)
-            assert option.active, "Option %r is not active" % option
-            votes.append(voteset.new(self, option, preference, token, voter))
-
-        # Store a vote with preference = None for each active option of this
-        # poll that wasn't in the options argument.
-        for option in activeoptions:
-            if option not in options:
-                votes.append(voteset.new(self, option, None, token, voter))
-
-        getUtility(IVoteCastSet).new(self, person)
-        return votes
-
-    def storeSimpleVote(self, person, option, when=None):
-        """See IPoll."""
-        voter = self._assertEverythingOkAndGetVoter(person, when=when)
-        assert self.type == PollAlgorithm.SIMPLE
-        voteset = getUtility(IVoteSet)
-
-        if option is None and not self.allowspoilt:
-            raise ValueError("This poll doesn't allow spoilt votes.")
-        elif option is not None:
-            assert option.poll == self, (
-                "The option %r doesn't belong to this poll" % option)
-            assert option.active, "Option %r is not active" % option
-        token = voteset.newToken()
-        # This is a simple-style poll, so you can vote only on a single option
-        # and this option's preference must be 1
-        preference = 1
-        vote = voteset.new(self, option, preference, token, voter)
-        getUtility(IVoteCastSet).new(self, person)
-        return vote
-
-    def getTotalVotes(self):
-        """See IPoll."""
-        assert self.isClosed()
-        return Vote.selectBy(poll=self).count()
-
-    def getWinners(self):
-        """See IPoll."""
-        assert self.isClosed()
-        # XXX: GuilhermeSalgado 2005-08-24:
-        # For now, this method works only for SIMPLE-style polls. This is
-        # not a problem as CONDORCET-style polls are disabled.
-        assert self.type == PollAlgorithm.SIMPLE
-        query = """
-            SELECT option
-            FROM Vote
-            WHERE poll = %d AND option IS NOT NULL
-            GROUP BY option
-            HAVING COUNT(*) = (
-                SELECT COUNT(*)
-                FROM Vote
-                WHERE poll = %d
-                GROUP BY option
-                ORDER BY COUNT(*) DESC LIMIT 1
-                )
-            """ % (self.id, self.id)
-        results = Store.of(self).execute(query).get_all()
-        if not results:
-            return None
-        return [PollOption.get(id) for (id,) in results]
-
-    def getPairwiseMatrix(self):
-        """See IPoll."""
-        assert self.type == PollAlgorithm.CONDORCET
-        options = list(self.getAllOptions())
-        pairwise_matrix = []
-        for option1 in options:
-            pairwise_row = []
-            for option2 in options:
-                points_query = """
-                    SELECT COUNT(*) FROM Vote as v1, Vote as v2 WHERE
-                        v1.token = v2.token AND
-                        v1.option = %s AND v2.option = %s AND
-                        (
-                         (
-                          v1.preference IS NOT NULL AND
-                          v2.preference IS NOT NULL AND
-                          v1.preference < v2.preference
-                         )
-                          OR
-                         (
-                          v1.preference IS NOT NULL AND
-                          v2.preference IS NULL
-                         )
-                        )
-                    """ % sqlvalues(option1.id, option2.id)
-                if option1 == option2:
-                    pairwise_row.append(None)
-                else:
-                    points = Store.of(self).execute(points_query).get_one()[0]
-                    pairwise_row.append(points)
-            pairwise_matrix.append(pairwise_row)
-        return pairwise_matrix
-
-
-class PollSet:
-    """See IPollSet."""
-
-    implements(IPollSet)
-
-    def new(self, team, name, title, proposition, dateopens, datecloses,
-            secrecy, allowspoilt, poll_type=PollAlgorithm.SIMPLE):
-        """See IPollSet."""
-        return Poll(team=team, name=name, title=title,
-                proposition=proposition, dateopens=dateopens,
-                datecloses=datecloses, secrecy=secrecy,
-                allowspoilt=allowspoilt, type=poll_type)
-
-    def selectByTeam(self, team, status=PollStatus.ALL, orderBy=None, when=None):
-        """See IPollSet."""
-        if when is None:
-            when = datetime.now(pytz.timezone('UTC'))
-
-        if orderBy is None:
-            orderBy = Poll.sortingColumns
-
-
-        status = set(status)
-        status_clauses = []
-        if PollStatus.OPEN in status:
-            status_clauses.append(AND(Poll.q.dateopens <= when,
-                                    Poll.q.datecloses > when))
-        if PollStatus.CLOSED in status:
-            status_clauses.append(Poll.q.datecloses <= when)
-        if PollStatus.NOT_YET_OPENED in status:
-            status_clauses.append(Poll.q.dateopens > when)
-
-        assert len(status_clauses) > 0, "No poll statuses were selected"
-
-        results = Poll.select(AND(Poll.q.teamID == team.id,
-                                  OR(*status_clauses)))
-
-        return results.orderBy(orderBy)
-
-    def getByTeamAndName(self, team, name, default=None):
-        """See IPollSet."""
-        query = AND(Poll.q.teamID == team.id, Poll.q.name == name)
-        try:
-            return Poll.selectOne(query)
-        except SQLObjectNotFound:
-            return default
-
-
-class PollOption(SQLBase):
-    """See IPollOption."""
-
-    implements(IPollOption)
-    _table = 'PollOption'
-    _defaultOrder = ['title', 'id']
-
-    poll = ForeignKey(dbName='poll', foreignKey='Poll', notNull=True)
-
-    name = StringCol(notNull=True)
-
-    title = StringCol(notNull=True)
-
-    active = BoolCol(notNull=True, default=False)
-
-
-class PollOptionSet:
-    """See IPollOptionSet."""
-
-    implements(IPollOptionSet)
-
-    def new(self, poll, name, title, active=True):
-        """See IPollOptionSet."""
-        return PollOption(poll=poll, name=name, title=title, active=active)
-
-    def selectByPoll(self, poll, only_active=False):
-        """See IPollOptionSet."""
-        query = PollOption.q.pollID == poll.id
-        if only_active:
-            query = AND(query, PollOption.q.active == True)
-        return PollOption.select(query)
-
-    def getByPollAndId(self, poll, option_id, default=None):
-        """See IPollOptionSet."""
-        query = AND(PollOption.q.pollID == poll.id,
-                    PollOption.q.id == option_id)
-        try:
-            return PollOption.selectOne(query)
-        except SQLObjectNotFound:
-            return default
-
-
-class VoteCast(SQLBase):
-    """See IVoteCast."""
-
-    implements(IVoteCast)
-    _table = 'VoteCast'
-    _defaultOrder = 'id'
-
-    person = ForeignKey(
-        dbName='person', foreignKey='Person',
-        storm_validator=validate_public_person, notNull=True)
-
-    poll = ForeignKey(dbName='poll', foreignKey='Poll', notNull=True)
-
-
-class VoteCastSet:
-    """See IVoteCastSet."""
-
-    implements(IVoteCastSet)
-
-    def new(self, poll, person):
-        """See IVoteCastSet."""
-        return VoteCast(poll=poll, person=person)
-
-
-class Vote(SQLBase):
-    """See IVote."""
-
-    implements(IVote)
-    _table = 'Vote'
-    _defaultOrder = ['preference', 'id']
-
-    person = ForeignKey(
-        dbName='person', foreignKey='Person',
-        storm_validator=validate_public_person)
-
-    poll = ForeignKey(dbName='poll', foreignKey='Poll', notNull=True)
-
-    option = ForeignKey(dbName='option', foreignKey='PollOption')
-
-    preference = IntCol(dbName='preference')
-
-    token = StringCol(dbName='token', notNull=True, unique=True)
-
-
-class VoteSet:
-    """See IVoteSet."""
-
-    implements(IVoteSet)
-
-    def newToken(self):
-        """See IVoteSet."""
-        chars = '23456789bcdfghjkmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZ'
-        length = 10
-        token = ''.join([random.choice(chars) for c in range(length)])
-        while self.getByToken(token):
-            token = ''.join([random.choice(chars) for c in range(length)])
-        return token
-
-    def new(self, poll, option, preference, token, person):
-        """See IVoteSet."""
-        return Vote(poll=poll, option=option, preference=preference,
-                    token=token, person=person)
-
-    def getByToken(self, token):
-        """See IVoteSet."""
-        return Vote.selectBy(token=token)
-
-    def getVotesByOption(self, option):
-        """See IVoteSet."""
-        if option.poll.type != PollAlgorithm.SIMPLE:
-            raise OptionIsNotFromSimplePoll(
-                '%r is not an option of a simple-style poll.' % option)
-        return Vote.selectBy(option=option).count()
-

=== removed directory 'lib/lp/registry/stories/team-polls'
=== removed file 'lib/lp/registry/stories/team-polls/create-poll-options.txt'
--- lib/lp/registry/stories/team-polls/create-poll-options.txt	2009-08-19 19:48:09 +0000
+++ lib/lp/registry/stories/team-polls/create-poll-options.txt	1970-01-01 00:00:00 +0000
@@ -1,85 +0,0 @@
-= Poll options =
-
-A poll can have any number of options, but these must be created
-before the poll has opened.
-
-First we create a new poll to use throughout this test.
-
-    >>> login('jeff.waugh@xxxxxxxxxxxxxxx')
-    >>> from zope.component import getUtility
-    >>> from lp.registry.interfaces.person import IPersonSet
-    >>> factory.makePoll(getUtility(IPersonSet).getByName('ubuntu-team'),
-    ...                  'dpl-2080', 'dpl-2080', 'dpl-2080')
-    <Poll...
-    >>> logout()
-
-Our poll is not yet open, so new options can be added to it.
-
-    >>> team_admin_browser = setupBrowser(
-    ...     auth='Basic jeff.waugh@xxxxxxxxxxxxxxx:jdub')
-    >>> team_admin_browser.open(
-    ...     'http://launchpad.dev/~ubuntu-team/+poll/dpl-2080')
-    >>> team_admin_browser.getLink('Add new option').click()
-    >>> team_admin_browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/dpl-2080/+newoption'
-
-    >>> bill_name = (
-    ...     'bill-amazingly-huge-middle-name-almost-impossible-to-read-graham')
-    >>> team_admin_browser.getControl('Name').value = bill_name
-    >>> team_admin_browser.getControl('Title').value = 'Bill Graham'
-    >>> team_admin_browser.getControl('Create').click()
-
-After adding an options we're taken back to the poll's home page.
-
-    >>> team_admin_browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/dpl-2080'
-
-And here we see the option listed as one of the active options for this
-poll.
-
-    >>> print extract_text(
-    ...     find_tag_by_id(team_admin_browser.contents, 'options'))
-    Name        Title           Active
-    bill...     Bill Graham     Yes
-
-If we try to add a new option without providing a title, we'll get an error
-message because the title is required.
-
-    >>> team_admin_browser.getLink('Add new option').click()
-    >>> team_admin_browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/dpl-2080/+newoption'
-
-    >>> will_name = (
-    ...     'will-amazingly-huge-middle-name-almost-impossible-to-read-graham')
-    >>> team_admin_browser.getControl('Name').value = will_name
-    >>> team_admin_browser.getControl('Title').value = ''
-    >>> team_admin_browser.getControl('Create').click()
-
-    >>> print "\n".join(get_feedback_messages(team_admin_browser.contents))
-    There is 1 error.
-    Required input is missing.
-
-If we try to add a new option with the same name of a existing option, we
-should get a nice error message
-
-    >>> team_admin_browser.getControl('Name').value = bill_name
-    >>> team_admin_browser.getControl('Title').value = 'Bill Again'
-    >>> team_admin_browser.getControl('Create').click()
-
-    >>> print "\n".join(get_feedback_messages(team_admin_browser.contents))
-    There is 1 error.
-    ...is already in use by another option in this poll.
-
-It's not possible to add/edit a poll option after a poll is open or closed.
-That's only possible when the poll is not yet open.
-
-    >>> team_admin_browser.open(
-    ...     'http://launchpad.dev/~ubuntu-team/+poll/director-2004/+newoption')
-
-    >>> "\n".join(get_feedback_messages(team_admin_browser.contents))
-    u'You can&#8217;t add new options because the poll is already closed.'
-
-    >>> team_admin_browser.open(
-    ...     'http://launchpad.dev/~ubuntu-team/+poll/never-closes/+newoption')
-    >>> "\n".join(get_feedback_messages(team_admin_browser.contents))
-    u'You can&#8217;t add new options because the poll is already open.'

=== removed file 'lib/lp/registry/stories/team-polls/create-polls.txt'
--- lib/lp/registry/stories/team-polls/create-polls.txt	2010-05-19 05:47:50 +0000
+++ lib/lp/registry/stories/team-polls/create-polls.txt	1970-01-01 00:00:00 +0000
@@ -1,163 +0,0 @@
-Let's first setup some objects that we'll need.
-
-    >>> no_priv_browser = setupBrowser(
-    ...     auth='Basic no-priv@xxxxxxxxxxxxx:test')
-    >>> team_admin_browser = setupBrowser(
-    ...    'Basic jeff.waugh@xxxxxxxxxxxxxxx:jdub')
-
-If you're not logged in and go to the +polls page of the "Ubuntu Team"
-you'll see a link to login as a team administrator.
-
-    >>> anon_browser.open('http://launchpad.dev/~ubuntu-team')
-    >>> anon_browser.getLink('Show polls').click()
-    >>> anon_browser.url
-    'http://launchpad.dev/~ubuntu-team/+polls'
-    >>> anon_browser.getLink('Log in as an admin to set up a new poll').url
-    'http://launchpad.dev/~ubuntu-team/+login'
-
-Try to create a new poll logged in as 'no-priv', which is not a team
-administrator. There's no link leading to the +newpoll page, but the user can
-easily guess it.
-
-    >>> no_priv_browser.open('http://launchpad.dev/~ubuntu-team/+newpoll')
-    Traceback (most recent call last):
-    ...
-    Unauthorized:...
-
-Now we're logged in as Jeff Waugh which is a team administrator and thus can
-create a new poll.
-
-    >>> team_admin_browser.open('http://launchpad.dev/~ubuntu-team')
-    >>> team_admin_browser.getLink('Show polls').click()
-    >>> team_admin_browser.getLink('Set up a new poll').click()
-    >>> team_admin_browser.url
-    'http://launchpad.dev/~ubuntu-team/+newpoll'
-
-    >>> team_admin_browser.title
-    'New poll for team Ubuntu Team...
-
-First we try to create a poll with a invalid name to
-test the name field validator.
-
-    >>> team_admin_browser.getControl(
-    ...     'The unique name of this poll').value = 'election_2100'
-    >>> team_admin_browser.getControl(
-    ...     'The title of this poll').value = 'Presidential Election 2100'
-    >>> proposition = 'Who is going to be the next president?'
-    >>> team_admin_browser.getControl(
-    ...     'The proposition that is going to be voted').value = proposition
-    >>> team_admin_browser.getControl(
-    ...     'Users can spoil their votes?').selected = True
-    >>> team_admin_browser.getControl(
-    ...     name='field.dateopens').value = '2100-06-04 02:00:00+00:00'
-    >>> team_admin_browser.getControl(
-    ...     name='field.datecloses').value = '2100-07-04 02:00:00+00:00'
-    >>> team_admin_browser.getControl('Continue').click()
-
-    >>> print "\n".join(get_feedback_messages(team_admin_browser.contents))
-    There is 1 error.
-    Invalid name 'election_2100'. Names must be at least two characters ...
-
-We fix the name, but swap the dates. Again a nice error message.
-
-    >>> team_admin_browser.getControl(
-    ...     'The unique name of this poll').value = 'election-2100'
-    >>> team_admin_browser.getControl(
-    ...     name='field.dateopens').value = '2100-07-04 02:00:00+00:00'
-    >>> team_admin_browser.getControl(
-    ...     name='field.datecloses').value = '2100-06-04 02:00:00+00:00'
-    >>> team_admin_browser.getControl('Continue').click()
-
-    >>> print "\n".join(get_feedback_messages(team_admin_browser.contents))
-    There is 1 error.
-    A poll cannot close at the time (or before) it opens.
-
-Now we get it right.
-
-    >>> team_admin_browser.getControl(
-    ...     name='field.dateopens').value = '2100-06-04 02:00:00+00:00'
-    >>> team_admin_browser.getControl(
-    ...     name='field.datecloses').value = '2100-07-04 02:00:00+00:00'
-    >>> team_admin_browser.getControl('Continue').click()
-
-We're redirected to the newly created poll page.
-
-    >>> team_admin_browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/election-2100'
-
-Create a new poll that starts in 2025-06-04 and will last until 2035.
-
-    >>> team_admin_browser.open(
-    ...     'http://launchpad.dev/~ubuntu-team/+newpoll')
-    >>> team_admin_browser.getControl(
-    ...     'The unique name of this poll').value = 'dpl-2080'
-    >>> team_admin_browser.getControl(
-    ...     'The title of this poll').value = 'Debian Project Leader Election 2080'
-    >>> proposition = 'The next debian project leader'
-    >>> team_admin_browser.getControl(
-    ...     'The proposition that is going to be voted').value = proposition
-    >>> team_admin_browser.getControl(
-    ...     'Users can spoil their votes?').selected = True
-    >>> team_admin_browser.getControl(
-    ...     name='field.dateopens').value = '2025-06-04 02:00:00+00:00'
-    >>> team_admin_browser.getControl(
-    ...     name='field.datecloses').value = '2035-06-04 02:00:00+00:00'
-    >>> team_admin_browser.getControl('Continue').click()
-
-We're redirected to the newly created poll
-
-    >>> team_admin_browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/dpl-2080'
-    >>> team_admin_browser.title
-    'Debian Project Leader Election 2080 : \xe2\x80\x9cUbuntu Team\xe2\x80\x9d team'
-    >>> print_location(team_admin_browser.contents)
-    Hierarchy:  ?Ubuntu Team? team > Debian Project Leader Election 2080
-    Tabs:
-    * Overview (selected) - http://launchpad.dev/~ubuntu-team
-    * Code - http://code.launchpad.dev/~ubuntu-team
-    * Bugs - http://bugs.launchpad.dev/~ubuntu-team
-    * Blueprints - http://blueprints.launchpad.dev/~ubuntu-team
-    * Translations - http://translations.launchpad.dev/~ubuntu-team
-    * Answers - http://answers.launchpad.dev/~ubuntu-team
-    Main heading: Debian Project Leader Election 2080
-    >>> team_admin_browser.getLink('add an option').url
-    'http://launchpad.dev/%7Eubuntu-team/+poll/dpl-2080/+newoption'
-
-Now lets try to insert a poll with the name of a existing one.
-
-# XXX matsubara 2006-07-17 bug=53302:
-# There's no link to get back to +polls.
-
-    >>> team_admin_browser.open(
-    ...     'http://launchpad.dev/~ubuntu-team/+newpoll')
-    >>> team_admin_browser.getControl(
-    ...     'The unique name of this poll').value = 'dpl-2080'
-    >>> team_admin_browser.getControl(
-    ...     'The title of this poll').value = 'Debian Project Leader Election 2080'
-    >>> proposition = 'The next debian project leader'
-    >>> team_admin_browser.getControl(
-    ...     'The proposition that is going to be voted').value = proposition
-    >>> team_admin_browser.getControl(
-    ...     'Users can spoil their votes?').selected = True
-    >>> team_admin_browser.getControl(
-    ...     name='field.dateopens').value = '2025-06-04 02:00:00+00:00'
-    >>> team_admin_browser.getControl(
-    ...     name='field.datecloses').value = '2035-06-04 02:00:00+00:00'
-    >>> team_admin_browser.getControl('Continue').click()
-
-    >>> print "\n".join(get_feedback_messages(team_admin_browser.contents))
-    There is 1 error.
-    dpl-2080 is already in use by another poll in this team.
-
-When creating a new poll, its start date must be at least 12 hours from
-now, so that the user creating it has a chance to add some options before
-the poll opens -- at that point new options cannot be added.
-
-    >>> team_admin_browser.getControl('The unique name').value = 'today'
-    >>> from datetime import datetime
-    >>> today = datetime.today().strftime('%Y-%m-%d')
-    >>> team_admin_browser.getControl(name='field.dateopens').value = today
-    >>> team_admin_browser.getControl('Continue').click()
-    >>> print "\n".join(get_feedback_messages(team_admin_browser.contents))
-    There is 1 error.
-    A poll cannot open less than 12 hours after it's created.

=== removed file 'lib/lp/registry/stories/team-polls/edit-options.txt'
--- lib/lp/registry/stories/team-polls/edit-options.txt	2009-08-19 19:48:09 +0000
+++ lib/lp/registry/stories/team-polls/edit-options.txt	1970-01-01 00:00:00 +0000
@@ -1,59 +0,0 @@
-= Editing poll options =
-
-Changing the poll options detail is not possible if you are not one of the
-team's administrators:
-
-    >>> user_browser.open('http://launchpad.dev/~ubuntu-team/+polls')
-    >>> user_browser.getLink('A public poll that never closes').click()
-    >>> user_browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/never-closes4'
-    >>> print extract_text(find_tag_by_id(user_browser.contents, 'options'))
-    Name        Title       Active
-    OptionA     OptionA     Yes
-    ...
-    >>> user_browser.getLink('[Edit]')
-    Traceback (most recent call last):
-    ...
-    LinkNotFoundError
-
-And when the poll already started, administrators cannot change the options
-either:
-
-    # Need to craft the URL manually because there's no link to it -- the
-    # option can't be changed, after all.
-    >>> browser = setupBrowser(
-    ...     auth='Basic jeff.waugh@xxxxxxxxxxxxxxx:jdub')
-    >>> browser.open('http://launchpad.dev/~ubuntu-team/+poll/never-closes4/'
-    ...              '+option/20')
-    >>> print "\n".join(get_feedback_messages(browser.contents))
-    You can&#8217;t edit any options because the poll is already open.
-
-Since Jeff is an administrator of ubuntu-team and we have a poll that hasn't
-been opened yet, he should be able to edit its options.
-
-    >>> browser.open('http://launchpad.dev/~ubuntu-team/+polls')
-    >>> browser.getLink('A public poll that has not opened yet').click()
-    >>> browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/not-yet-opened'
-
-    >>> browser.getLink('[Edit]').click()
-    >>> browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/not-yet-opened/+option/...'
-
-    >>> browser.getControl('Name').value
-    'OptionX'
-    >>> browser.getControl('Title').value
-    'OptionX'
-    >>> browser.getControl('Name').value = 'option-z'
-    >>> browser.getControl('Title').value = 'Option Z'
-    >>> browser.getControl('Save').click()
-
-    >>> browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/not-yet-opened'
-    >>> print find_portlet(browser.contents, 'Voting options').renderContents()
-    <BLANKLINE>
-    <h2>Voting options</h2>
-    ...
-    ...option-z...
-    ...
-

=== removed file 'lib/lp/registry/stories/team-polls/edit-poll.txt'
--- lib/lp/registry/stories/team-polls/edit-poll.txt	2010-10-11 17:36:14 +0000
+++ lib/lp/registry/stories/team-polls/edit-poll.txt	1970-01-01 00:00:00 +0000
@@ -1,97 +0,0 @@
-= Editing a poll =
-
-All attributes of a poll can be changed as long as the poll has not opened
-yet.
-
-First we create a new poll to use throughout this test.
-
-    >>> login('jeff.waugh@xxxxxxxxxxxxxxx')
-    >>> from zope.component import getUtility
-    >>> from lp.registry.interfaces.person import IPersonSet
-    >>> factory.makePoll(getUtility(IPersonSet).getByName('ubuntu-team'),
-    ...                  'dpl-2080', 'dpl-2080', 'dpl-2080')
-    <Poll...
-    >>> logout()
-
-Now we'll try to change its name to something that is already in use.
-
-    >>> team_admin_browser = setupBrowser(
-    ...     auth='Basic jeff.waugh@xxxxxxxxxxxxxxx:jdub')
-    >>> team_admin_browser.open(
-    ...     'http://launchpad.dev/~ubuntu-team/+poll/dpl-2080')
-    >>> team_admin_browser.getLink('Change details').click()
-
-    >>> team_admin_browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/dpl-2080/+edit'
-
-    >>> team_admin_browser.getControl(
-    ...     'The unique name of this poll').value = 'never-closes'
-    >>> team_admin_browser.getControl('Save').click()
-
-    >>> print "\n".join(get_feedback_messages(team_admin_browser.contents))
-    There is 1 error.
-    ...never-closes is already in use by another poll in this team.
-
-Entering an end date that precedes the start date returns a nice error
-message.
-
-    >>> team_admin_browser.getControl(
-    ...     'The unique name of this poll').value = 'dpl-2080'
-    >>> team_admin_browser.getControl(
-    ...     name='field.dateopens').value = '3000-11-01 00:00:00+00:00'
-    >>> team_admin_browser.getControl(
-    ...     name='field.datecloses').value = '3000-01-01 00:00:00+00:00'
-    >>> team_admin_browser.getControl('Save').click()
-
-    >>> print "\n".join(get_feedback_messages(team_admin_browser.contents))
-    There is 1 error.
-    A poll cannot close at the time (or before) it opens.
-
-We successfully change the polls name
-
-    >>> team_admin_browser.getControl(
-    ...     'The unique name of this poll').value = 'election-3000'
-    >>> team_admin_browser.getControl(
-    ...     name='field.dateopens').value = '3000-01-01 00:00:00+00:00'
-    >>> team_admin_browser.getControl(
-    ...     name='field.datecloses').value = '3000-11-01 00:00:00+00:00'
-    >>> team_admin_browser.getControl('Save').click()
-
-    >>> team_admin_browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/election-3000'
-
-Trying to edit a poll that's already open isn't possible.
-
-    >>> team_admin_browser.open('http://launchpad.dev/~ubuntu-team/')
-    >>> team_admin_browser.getLink('Show polls').click()
-    >>> team_admin_browser.url
-    'http://launchpad.dev/~ubuntu-team/+polls'
-
-    >>> team_admin_browser.getLink('A random poll that never closes').click()
-    >>> team_admin_browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/never-closes/+vote'
-
-    >>> team_admin_browser.open(
-    ...     'http://launchpad.dev/~ubuntu-team/+poll/never-closes/+edit')
-    >>> print extract_text(
-    ...     find_tag_by_id(team_admin_browser.contents, 'not-editable'))
-    This poll can't be edited...
-
-It's also not possible to edit a poll that's already closed.
-
-    >>> team_admin_browser.open('http://launchpad.dev/~ubuntu-team/')
-    >>> team_admin_browser.getLink('Show polls').click()
-    >>> team_admin_browser.url
-    'http://launchpad.dev/~ubuntu-team/+polls'
-
-    >>> team_admin_browser.getLink("2004 Director's Elections").click()
-    >>> team_admin_browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/director-2004'
-
-    >>> 'Voting has closed' in team_admin_browser.contents
-    True
-
-    >>> team_admin_browser.getLink('Change details').click()
-    >>> print extract_text(
-    ...     find_tag_by_id(team_admin_browser.contents, 'not-editable'))
-    This poll can't be edited...

=== removed file 'lib/lp/registry/stories/team-polls/vote-poll.txt'
--- lib/lp/registry/stories/team-polls/vote-poll.txt	2010-10-11 17:36:14 +0000
+++ lib/lp/registry/stories/team-polls/vote-poll.txt	1970-01-01 00:00:00 +0000
@@ -1,167 +0,0 @@
-= Voting on polls =
-
-Foo Bar (a member of the ubuntu-team) wants to vote on the 'never-closes'
-poll, which is a poll with secret votes, which means he'll get a token that he
-must use to see/change his vote afterwards.
-
-    >>> browser = setupBrowser(auth='Basic foo.bar@xxxxxxxxxxxxx:test')
-    >>> browser.open('http://launchpad.dev/~ubuntu-team/+polls')
-    >>> browser.getLink('A random poll that never closes').click()
-    >>> browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/never-closes/+vote'
-
-    >>> print find_tag_by_id(browser.contents, 'your-vote').renderContents()
-    <BLANKLINE>
-    ...
-    <h2>Your current vote</h2>
-    ...You have not yet voted in this poll...
-    <h2>Vote now</h2>
-    ...
-
-    >>> browser.getControl('None of these options').selected = True
-    >>> browser.getControl('Continue').click()
-
-    >>> browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/never-closes/+vote'
-
-    >>> tags = find_tags_by_class(browser.contents, "informational message")
-    >>> for tag in tags:
-    ...     print tag.renderContents()
-    Your vote has been recorded. If you want to view or change it later you
-    must write down this key: ...
-
-    >>> print find_tag_by_id(browser.contents, 'your-vote').renderContents()
-    <BLANKLINE>
-    ...
-    <h2>Your current vote</h2>
-    ...Your current vote is for <b> none of the options. </b>...
-    ...
-
-Foo Bar will now vote on a poll with public votes.
-
-    >>> browser.open('http://launchpad.dev/~ubuntu-team/+polls')
-    >>> browser.getLink('A public poll that never closes').click()
-    >>> browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/never-closes4/+vote'
-
-    >>> print find_tag_by_id(browser.contents, 'your-vote').renderContents()
-    <BLANKLINE>
-    ...
-    <h2>Your current vote</h2>
-    ...You have not yet voted in this poll...
-    <h2>Vote now</h2>
-    ...
-
-    >>> browser.getControl('OptionB').selected = True
-    >>> browser.getControl('Continue').click()
-
-    >>> browser.url
-    'http://launchpad.dev/~ubuntu-team/+poll/never-closes4/+vote'
-
-    >>> tags = find_tags_by_class(browser.contents, "informational message")
-    >>> for tag in tags:
-    ...     print tag.renderContents()
-    Your vote was stored successfully. You can come back to this page at any
-    time before this poll closes to view or change your vote, if you want.
-
-    >>> print find_tag_by_id(browser.contents, 'your-vote').renderContents()
-    <BLANKLINE>
-    ...
-    <h2>Your current vote</h2>
-    ...Your current vote is for <b>OptionB</b>...
-    ...
-
-
-For convenience we provide an option for when the user doesn't want to vote
-yet.
-
-    >>> team_admin_browser = setupBrowser(
-    ...     auth='Basic jeff.waugh@xxxxxxxxxxxxxxx:jdub')
-    >>> team_admin_browser.open(
-    ...   'http://launchpad.dev/~ubuntu-team/+poll/never-closes/+vote')
-    >>> not_yet_voted_message = 'You have not yet voted in this poll.'
-    >>> not_yet_voted_message in team_admin_browser.contents
-    True
-
-    >>> team_admin_browser.getControl(name='newoption').value = ["donotvote"]
-    >>> team_admin_browser.getControl(name='continue').click()
-
-    >>> contents = team_admin_browser.contents
-    >>> for tag in find_tags_by_class(contents, "informational message"):
-    ...     print tag.renderContents()
-    You chose not to vote yet.
-
-    >>> print find_tag_by_id(contents, 'your-vote').renderContents()
-    <BLANKLINE>
-    ...
-    <h2>Your current vote</h2>
-    ...You have not yet voted in this poll...
-    ...
-
-
-== No permission to vote ==
-
-Only members of a given team can vote on that team's polls. Other users can't,
-even if they guess the URL for the voting page.
-
-    >>> non_member_browser = setupBrowser(
-    ...     auth='Basic test@xxxxxxxxxxxxx:test')
-    >>> non_member_browser.open(
-    ...     'http://launchpad.dev/~ubuntu-team/+poll/never-closes/+vote')
-    >>> for tag in find_tags_by_class(
-    ...     non_member_browser.contents, "informational message"):
-    ...     print tag.renderContents()
-    You can&#8217;t vote in this poll because you&#8217;re not a member
-    of Ubuntu Team.
-
-
-== Closed polls ==
-
-It's not possible to vote on closed polls, even if we manually craft the URL.
-
-    >>> team_admin_browser.open(
-    ...     'http://launchpad.dev/~ubuntu-team/+poll/leader-2004')
-    >>> print find_tag_by_id(
-    ...     team_admin_browser.contents, 'maincontent').renderContents()
-    <BLANKLINE>
-    ...
-    <h2>Voting has closed</h2>
-    ...
-
-    >>> team_admin_browser.open(
-    ...     'http://launchpad.dev/~ubuntu-team/+poll/leader-2004/+vote')
-    >>> print find_tag_by_id(
-    ...     team_admin_browser.contents, 'maincontent').renderContents()
-    <BLANKLINE>
-    ...
-    <p class="informational message">
-          This poll is already closed.
-        </p>
-    ...
-
-    >>> team_admin_browser.getControl(name='continue')
-    Traceback (most recent call last):
-    ...
-    LookupError: name 'continue'
-
-The same is true for condorcet polls too.
-
-    >>> team_admin_browser.open(
-    ...     'http://launchpad.dev/~ubuntu-team/+poll/director-2004')
-    >>> print find_tag_by_id(
-    ...     team_admin_browser.contents, 'maincontent').renderContents()
-    <BLANKLINE>
-    ...
-    <h2>Voting has closed</h2>
-    ...
-
-    >>> team_admin_browser.getControl(name='continue')
-    Traceback (most recent call last):
-    ...
-    LookupError: name 'continue'
-
-    >>> team_admin_browser.open(
-    ...     'http://launchpad.dev/~ubuntu-team/+poll/director-2004/+vote')
-    >>> for message in get_feedback_messages(team_admin_browser.contents):
-    ...     print message
-    This poll is already closed.

=== removed file 'lib/lp/registry/stories/team-polls/xx-poll-condorcet-voting.txt'
--- lib/lp/registry/stories/team-polls/xx-poll-condorcet-voting.txt	2010-10-11 17:36:14 +0000
+++ lib/lp/registry/stories/team-polls/xx-poll-condorcet-voting.txt	1970-01-01 00:00:00 +0000
@@ -1,229 +0,0 @@
-# XXX Guilherme Salgado, 2006-01-19:
-# Merge this test with team-polls/xx-votepoll.txt
-
-  Go to a condorcet-style poll (which is still open) and check that apart
-  from seeing our vote we can also change it.
-
-  >>> print http(r"""
-  ... GET /~ubuntu-team/+poll/never-closes2 HTTP/1.1
-  ... Accept-Language: en-us,en;q=0.5
-  ... Authorization: Basic foo.bar@xxxxxxxxxxxxx:test
-  ... """)
-  HTTP/1.1 303 See Other
-  ...
-  Location: http://localhost/~ubuntu-team/+poll/never-closes2/+vote
-  ...
-
-  >>> print http(r"""
-  ... GET /~ubuntu-team/+poll/never-closes2/+vote HTTP/1.1
-  ... Authorization: Basic foo.bar@xxxxxxxxxxxxx:test
-  ... """)
-  HTTP/1.1 200 Ok
-  ...
-  ...You must enter your vote key...
-  ...This is a secret poll...
-  ...your vote is identified only by the key you...
-  ...were given when you voted. To view or change your vote you must enter...
-  ...your key:...
-  ...
-
-
-  If a non-member (Sample Person) guesses the voting URL and tries to vote,
-  he won't be allowed.
-
-  >>> print http(r"""
-  ... GET /~ubuntu-team/+poll/never-closes2/+vote HTTP/1.1
-  ... Authorization: Basic dGVzdEBjYW5vbmljYWwuY29tOnRlc3Q=
-  ... """)
-  HTTP/1.1 200 Ok
-  ...You can&#8217;t vote in this poll because you&#8217;re not...
-  ...a member of Ubuntu Team...
-
-
-  By providing the token we will be able to see our current vote.
-
-  >>> print http(r"""
-  ... POST /~ubuntu-team/+poll/never-closes2/+vote HTTP/1.1
-  ... Authorization: Basic foo.bar@xxxxxxxxxxxxx:test
-  ... Content-Type: application/x-www-form-urlencoded
-  ...
-  ... token=xn9FDCTp4m&showvote=Show+My+Vote&option_12=&option_13=&option_14=&option_15=""")
-  HTTP/1.1 200 Ok
-  ...
-                  <p>Your current vote is as follows:</p>
-                  <p>
-  <BLANKLINE>
-                  </p>
-                  <p>
-  <BLANKLINE>
-                      <b>1</b>.
-                      Option 1
-  <BLANKLINE>
-                  </p>
-                  <p>
-  <BLANKLINE>
-                      <b>2</b>.
-                      Option 2
-  <BLANKLINE>
-                  </p>
-                  <p>
-  <BLANKLINE>
-                      <b>3</b>.
-                      Option 4
-  <BLANKLINE>
-                  </p>
-  ...
-
-
-  It's also possible to change the vote, if wanted.
-
-  >>> print http(r"""
-  ... POST /~ubuntu-team/+poll/never-closes2/+vote HTTP/1.1
-  ... Authorization: Basic foo.bar@xxxxxxxxxxxxx:test
-  ... Content-Type: application/x-www-form-urlencoded
-  ...
-  ... token=xn9FDCTp4m&option_12=2&option_13=3&option_14=4&option_15=1&changevote=Change+Vote""")
-  HTTP/1.1 200 Ok
-  ...
-  ...Your vote was changed successfully.</p>
-  ...
-                  <p>Your current vote is as follows:</p>
-                  <p>
-  <BLANKLINE>
-                      <b>1</b>.
-                      Option 4
-  <BLANKLINE>
-                  </p>
-                  <p>
-  <BLANKLINE>
-                      <b>2</b>.
-                      Option 1
-  <BLANKLINE>
-                  </p>
-                  <p>
-  <BLANKLINE>
-                      <b>3</b>.
-                      Option 2
-  <BLANKLINE>
-                  </p>
-                  <p>
-  <BLANKLINE>
-                      <b>4</b>.
-                      Option 3
-  <BLANKLINE>
-                  </p>
-  ...
-
-
-  Now we go to another poll in which name16 voted. But this time it's a public
-  one, so there's no need to provide the token to see the current vote.
-
-  >>> print http(r"""
-  ... GET /~ubuntu-team/+poll/never-closes3 HTTP/1.1
-  ... Authorization: Basic foo.bar@xxxxxxxxxxxxx:test
-  ... """)
-  HTTP/1.1 303 See Other
-  ...
-  Location: http://localhost/~ubuntu-team/+poll/never-closes3/+vote
-  ...
-
-  >>> print http(r"""
-  ... GET /~ubuntu-team/+poll/never-closes3/+vote HTTP/1.1
-  ... Authorization: Basic foo.bar@xxxxxxxxxxxxx:test
-  ... """)
-  HTTP/1.1 200 Ok
-  ...
-                  <p>Your current vote is as follows:</p>
-                  <p>
-  <BLANKLINE>
-                      <b>1</b>.
-                      Option 1
-  <BLANKLINE>
-                  </p>
-                  <p>
-  <BLANKLINE>
-                      <b>2</b>.
-                      Option 2
-  <BLANKLINE>
-                  </p>
-                  <p>
-  <BLANKLINE>
-                      <b>3</b>.
-                      Option 3
-  <BLANKLINE>
-                  </p>
-                  <p>
-  <BLANKLINE>
-                      <b>4</b>.
-                      Option 4
-  <BLANKLINE>
-                  </p>
-  ...
-
-
-  Now we change the vote and we see the new vote displayed as our current
-  vote.
-
-  >>> print http(r"""
-  ... POST /~ubuntu-team/+poll/never-closes3/+vote HTTP/1.1
-  ... Authorization: Basic foo.bar@xxxxxxxxxxxxx:test
-  ... Content-Type: application/x-www-form-urlencoded
-  ...
-  ... option_16=4&option_17=2&option_18=1&option_19=3&changevote=Change+Vote""")
-  HTTP/1.1 200 Ok
-  ...
-                  <p>Your current vote is as follows:</p>
-                  <p>
-  <BLANKLINE>
-                      <b>1</b>.
-                      Option 3
-  <BLANKLINE>
-                  </p>
-                  <p>
-  <BLANKLINE>
-                      <b>2</b>.
-                      Option 2
-  <BLANKLINE>
-                  </p>
-                  <p>
-  <BLANKLINE>
-                      <b>3</b>.
-                      Option 4
-  <BLANKLINE>
-                  </p>
-                  <p>
-  <BLANKLINE>
-                      <b>4</b>.
-                      Option 1
-  <BLANKLINE>
-                  </p>
-  ...
-
-
-  Logged in as mark@xxxxxxxxxxx (which is a member of ubuntu-team), go to a public
-  condorcet-style poll that's still open and get redirected to a page where
-  it's possible to vote (and see the current vote).
-
-  >>> print http(r"""
-  ... GET /~ubuntu-team/+poll/never-closes3 HTTP/1.1
-  ... Authorization: Basic mark@xxxxxxxxxxx:test
-  ... """)
-  HTTP/1.1 303 See Other
-  ...
-  Location: http://localhost/~ubuntu-team/+poll/never-closes3/+vote
-  ...
-
-
-  And here we'll see the form which says you haven't voted yet and allows you
-  to vote.
-
-  >>> print http(r"""
-  ... GET /~ubuntu-team/+poll/never-closes3/+vote HTTP/1.1
-  ... Authorization: Basic mark@xxxxxxxxxxx:test
-  ... """)
-  HTTP/1.1 200 Ok
-  ...
-  ...Your current vote...
-  ...You have not yet voted in this poll...
-  ...Rank options in order...
-  ...

=== removed file 'lib/lp/registry/stories/team-polls/xx-poll-confirm-vote.txt'
--- lib/lp/registry/stories/team-polls/xx-poll-confirm-vote.txt	2009-08-21 18:46:34 +0000
+++ lib/lp/registry/stories/team-polls/xx-poll-confirm-vote.txt	1970-01-01 00:00:00 +0000
@@ -1,89 +0,0 @@
-  Logged in as 'jdub' (which voted in the director-2004 poll), let's see the
-  results of the director-2004 poll.
-
-  >>> print http(r"""
-  ... GET /~ubuntu-team/+poll/director-2004 HTTP/1.1
-  ... Authorization: Basic amVmZi53YXVnaEB1YnVudHVsaW51eC5jb206amR1Yg==
-  ... """)
-  HTTP/1.1 200 Ok
-  ...
-  ...2004 Director's Elections...
-  ...
-  ...This was a secret poll: your vote is identified only by the key...
-  ...you were given when you voted. To view your vote you must enter...
-  ...your key:...
-  ...Results...
-  ...This is the pairwise matrix for this poll...
-  ...
-
-
-  Now let's see if jdub's vote was stored correctly, by entering the token he
-  got when voting.
-
-  >>> print http(r"""
-  ... POST /~ubuntu-team/+poll/director-2004 HTTP/1.1
-  ... Authorization: Basic amVmZi53YXVnaEB1YnVudHVsaW51eC5jb206amR1Yg==
-  ... Content-Type: application/x-www-form-urlencoded
-  ... 
-  ... token=9WjxQq2V9p&showvote=Show+My+Vote""")
-  HTTP/1.1 200 Ok
-  ...
-                <p>Your vote was as follows:</p>
-                <p>
-  <BLANKLINE>
-                    <b>1</b>. 
-                    D
-  <BLANKLINE>
-                </p>
-                <p>
-  <BLANKLINE>
-                    <b>2</b>. 
-                    B
-  <BLANKLINE>
-                </p>
-                <p>
-  <BLANKLINE>
-                    <b>3</b>. 
-                    A
-  <BLANKLINE>
-                </p>
-                <p>
-  <BLANKLINE>
-                    <b>3</b>. 
-                    C
-  <BLANKLINE>
-                </p>
-  ...
-
-
-  Now we'll see the results of the leader-2004 poll, in which jdub also
-  voted.
-
-  >>> print http(r"""
-  ... GET /~ubuntu-team/+poll/leader-2004 HTTP/1.1
-  ... Authorization: Basic amVmZi53YXVnaEB1YnVudHVsaW51eC5jb206amR1Yg==
-  ... """)
-  HTTP/1.1 200 Ok
-  ...
-  ...2004 Leader's Elections...
-  ...
-  ...This was a secret poll: your vote is identified only by the key...
-  ...you were given when you voted. To view your vote you must enter...
-  ...your key:...
-  ...
-
-
-  And now we confirm his vote on this poll too.
-
-  >>> print http(r"""
-  ... POST /~ubuntu-team/+poll/leader-2004 HTTP/1.1
-  ... Authorization: Basic amVmZi53YXVnaEB1YnVudHVsaW51eC5jb206amR1Yg==
-  ... Content-Type: application/x-www-form-urlencoded
-  ... 
-  ... token=W7gR5mjNrX&showvote=Show+My+Vote""")
-  HTTP/1.1 200 Ok
-  ...
-              <p>Your vote was for
-  <BLANKLINE>
-                <b>Jack Crawford</b></p>
-  ...

=== removed file 'lib/lp/registry/stories/team-polls/xx-poll-results.txt'
--- lib/lp/registry/stories/team-polls/xx-poll-results.txt	2009-11-15 18:21:10 +0000
+++ lib/lp/registry/stories/team-polls/xx-poll-results.txt	1970-01-01 00:00:00 +0000
@@ -1,69 +0,0 @@
-First we check all polls of 'ubuntu-team'.
-
-  >>> anon_browser.open("http://launchpad.dev/~ubuntu-team";)
-  >>> anon_browser.getLink('Show polls').click()
-  >>> print find_main_content(anon_browser.contents)
-  <...
-  ...Current polls...
-  ...A random poll that never closes...
-  ...A second random poll that never closes...
-  ...A third random poll that never closes...
-  ...Closed polls...
-  ...2004 Director's Elections...
-  ...2004 Leader's Elections...
-
-
-  Check the results of a closed simple-style poll.
-
-  >>> anon_browser.open("http://launchpad.dev/~ubuntu-team/+poll/leader-2004";)
-  >>> print find_main_content(anon_browser.contents)
-  <...
-  ...Who's going to be the next leader?...
-  ...Results...
-  ...
-              <td>
-                Francis Dolarhyde
-  <BLANKLINE>
-              </td>
-              <td>1</td>
-  ...
-              <td>
-                Jack Crawford
-  <BLANKLINE>
-              </td>
-              <td>1</td>
-  ...
-              <td>
-                Will Graham
-  <BLANKLINE>
-              </td>
-              <td>2</td>
-  ...
-
-
-  Check the results of a closed condorcet-style poll.
-
-  >>> anon_browser.open("http://launchpad.dev/~ubuntu-team/+poll/director-2004";)
-  >>> print find_main_content(anon_browser.contents)
-  <...
-  ...Who's going to be the next director?...
-  ...Results...
-  ...
-  ...A...
-  ...2...
-  ...2...
-  ...2...
-  ...B...
-  ...2...
-  ...2...
-  ...2...
-  ...C...
-  ...1...
-  ...1...
-  ...1...
-  ...D...
-  ...2...
-  ...1...
-  ...2...
-  ...
-

=== modified file 'lib/lp/registry/stories/team/xx-team-home.txt'
--- lib/lp/registry/stories/team/xx-team-home.txt	2010-04-22 17:18:29 +0000
+++ lib/lp/registry/stories/team/xx-team-home.txt	2010-12-15 22:26:18 +0000
@@ -1,4 +1,5 @@
-= A team's home page =
+A team's home page
+==================
 
 The home page of a public team is visible to everyone.
 
@@ -59,17 +60,6 @@
     Languages:
     English
 
-The polls portlet is only shown if current polls exist.
-
-    >>> print extract_text(find_tag_by_id(browser.contents, 'polls'))
-    Polls
-    A random poll that never closes...
-    Show polls
-
-    >>> browser.open('http://launchpad.dev/~launchpad')
-    >>> print find_tag_by_id(browser.contents, 'polls')
-    None
-
 The subteam-of portlet is not shown if the team is not a subteam.
 
     >>> browser.open('http://launchpad.dev/~ubuntu-team')
@@ -190,7 +180,8 @@
     ...
 
 
-== Team admins ==
+Team admins
+-----------
 
 Team owners and admins can see a link to approve and decline applicants.
 
@@ -207,7 +198,8 @@
     <Link text='Approve or decline members' url='.../+editproposedmembers'>
 
 
-== Non members ==
+Non members
+-----------
 
 No Privileges Person is not a member of the Ubuntu team.
 
@@ -220,7 +212,8 @@
 He can see the contact address, and the link explains the email
 will actually go to the team's administrators.
 
-    >>> print extract_text(find_tag_by_id(user_browser.contents, 'contact-email'))
+    >>> print extract_text(
+    ...     find_tag_by_id(user_browser.contents, 'contact-email'))
     Email:
     support@xxxxxxxxxx
     >>> content = find_tag_by_id(user_browser.contents, 'contact-user')

=== modified file 'lib/lp/registry/templates/team-index.pt'
--- lib/lp/registry/templates/team-index.pt	2010-10-10 21:54:16 +0000
+++ lib/lp/registry/templates/team-index.pt	2010-12-15 22:26:18 +0000
@@ -35,7 +35,6 @@
   </metal:contact>
 
   <tal:menu replace="structure view/@@+global-actions" />
-  <tal:polls replace="structure context/@@+portlet-polls" />
 
 </div>
 

=== modified file 'lib/lp/registry/templates/team-polls.pt'
--- lib/lp/registry/templates/team-polls.pt	2009-11-20 05:40:25 +0000
+++ lib/lp/registry/templates/team-polls.pt	2010-12-15 22:26:18 +0000
@@ -8,81 +8,17 @@
 >
 <body>
 
-  <metal:heading fill-slot="heading">
-    <h1>Polls for <span tal:replace="context/displayname" /></h1>
-  </metal:heading>
-
   <div metal:fill-slot="main">
 
-    <h2>Current polls</h2>
+    <h1>Polls no longer supported</h1>
 
-    <p tal:condition="not: view/has_current_polls">
-      This team has no open polls nor polls that are not yet opened.
+    <p>
+    Conducting polls is no longer a feature in Launchpad.  We have archived the
+    data from all previously conducted polls, which can be found as a comma-separated values file at
+    <a href="http://dev.launchpad.net/PollFeatureRemoved";>http://dev.launchpad.net/PollFeatureRemoved</a>.
     </p>
 
-    <ul tal:condition="view/has_current_polls">
-      <li tal:repeat="poll view/openpolls">
-        <a tal:attributes="href poll/fmt:url">
-          <span tal:replace="poll/title" />
-        </a> - closes
-        <span
-          tal:attributes="title poll/datecloses/fmt:datetime"
-          tal:content="poll/datecloses/fmt:displaydate" />.
-
-        <tal:block define="user request/lp:person" condition="user">
-          <tal:block condition="python: poll.personVoted(user)">
-            You have
-            <span tal:replace="poll/closesIn/fmt:approximateduration" /> 
-            to change your vote if you wish.
-          </tal:block>
-
-          <tal:block condition="python: not poll.personVoted(user)">
-            You have
-            <span tal:replace="poll/closesIn/fmt:approximateduration" />
-            left to vote in this poll.
-          </tal:block>
-        </tal:block>
-
-      </li>
-
-      <li tal:repeat="poll view/notyetopenedpolls">
-        <a tal:attributes="href poll/fmt:url">
-          <span tal:replace="poll/title" />
-        </a> - opens
-        <span
-          tal:attributes="title poll/dateopens/fmt:datetime"
-          tal:content="poll/dateopens/fmt:displaydate" />
-      </li>
-    </ul>
-
-    <tal:block condition="view/closedpolls" >
-      <h2>Closed polls</h2>
-
-      <ul>
-        <li tal:repeat="poll view/closedpolls">
-          <a tal:attributes="href poll/fmt:url">
-            <span tal:replace="poll/title" />
-          </a> - closed
-          <span
-            tal:attributes="title poll/datecloses/fmt:datetime"
-            tal:content="poll/datecloses/fmt:displaydate" />
-        </li>
-      </ul>
-    </tal:block>
-
-    <br />
-    <tal:block tal:condition="request/lp:person">
-      <ul tal:condition="context/required:launchpad.Edit">
-        <li><a class="sprite add" href="+newpoll">Set up a new poll</a></li>
-      </ul>
-    </tal:block>
-
-    <tal:block tal:condition="not: request/lp:person">
-      <a href="+login">Log in as an admin to set up a new poll</a>
-    </tal:block>
-
   </div>
 
 </body>
 </html>
-

=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py	2010-12-14 05:43:47 +0000
+++ lib/lp/testing/factory.py	2010-12-15 22:26:18 +0000
@@ -207,11 +207,6 @@
     TeamSubscriptionPolicy,
     )
 from lp.registry.interfaces.pocket import PackagePublishingPocket
-from lp.registry.interfaces.poll import (
-    IPollSet,
-    PollAlgorithm,
-    PollSecrecy,
-    )
 from lp.registry.interfaces.product import (
     IProductSet,
     License,
@@ -729,16 +724,6 @@
                 naked_team.addMember(member, owner)
         return team
 
-    def makePoll(self, team, name, title, proposition,
-                 poll_type=PollAlgorithm.SIMPLE):
-        """Create a new poll which starts tomorrow and lasts for a week."""
-        dateopens = datetime.now(pytz.UTC) + timedelta(days=1)
-        datecloses = dateopens + timedelta(days=7)
-        return getUtility(IPollSet).new(
-            team, name, title, proposition, dateopens, datecloses,
-            PollSecrecy.SECRET, allowspoilt=True,
-            poll_type=poll_type)
-
     def makeTranslationGroup(self, owner=None, name=None, title=None,
                              summary=None, url=None):
         """Create a new, arbitrary `TranslationGroup`."""