summaryrefslogtreecommitdiff
path: root/Mailman/interfaces
diff options
context:
space:
mode:
authorBarry Warsaw2007-08-01 16:11:08 -0400
committerBarry Warsaw2007-08-01 16:11:08 -0400
commitf8a6c46455a409125dcc0fcace7d7116898b0319 (patch)
tree4d1c942d92e4b63eb8f000e25477079c14bb5346 /Mailman/interfaces
parentd72336c1e5932158f6e1f80e5ea9e90d264b7c52 (diff)
parent7a7826e112a1d3f1999cb7a11e6df98cfcb712c9 (diff)
downloadmailman-f8a6c46455a409125dcc0fcace7d7116898b0319.tar.gz
mailman-f8a6c46455a409125dcc0fcace7d7116898b0319.tar.zst
mailman-f8a6c46455a409125dcc0fcace7d7116898b0319.zip
Move the pending database into the SQLAlchemy/Elixir layer. The old
Pending.py module is removed. Added an interface to this functionality such that any IPendable (essentially a key/value mapping) can be associated with a token, and that token can be confirmed and has a lifetime. Any keys and values can be stored, as long as both are unicodes. Added a doctest. Modified initialization of the database layer to support pluggability via setuptools. No longer is this layer initialized from a module, but now it's instantiated from a class that implements IDatabase. The StockDatabase class implements the SQLAchemy/Elixir layer, but this can be overridden in a setup.py. Bye bye MANAGERS_INIT_FUNCTION, we hardly knew ye. Added a package Mailman.app which will contain certain application specific functionality. Right now, the only there there is an IRegistar implementation, which didn't seem to fit anywhere else. Speaking of which, the IRegistrar interface implements all the logic related to registration and verification of email addresses. Think the equivalent of MailList.AddMember() except generalized out of a mailing list context. This latter will eventually go away. The IRegistrar sends the confirmation email. Added an IDomain interface, though the only implementation of this so far lives in the registration.txt doctest. This defines the context necessary for domain-level things, like address confirmation. A bunch of other cleanups in modules that are necessary due to the refactoring of Pending, but don't affect anything that's actually tested yet, so I won't vouch for them (except that they don't throw errors on import!). Clean up Defaults.py; also turn the functions seconds(), minutes(), hours() and days() into their datetime.timedelta equivalents. Consolidated the bogus email address exceptions. In some places where appropriate, use email 4.0 module names instead of the older brand. Switch from Mailman.Utils.unique_message_id() to email.utils.make_msgid() everywhere. This is because we need to allow sending not in the context of a mailing list (i.e. domain-wide address confirmation message). So we can't use a Message-ID generator that requires a mailing list. OTOH, this breaks Message-ID collision detection in the mail->news gateway. I'll fix that eventually. Remove the 'verified' row on the Address table. Now verification is checked by Address.verified_on not being None.
Diffstat (limited to 'Mailman/interfaces')
-rw-r--r--Mailman/interfaces/address.py2
-rw-r--r--Mailman/interfaces/database.py51
-rw-r--r--Mailman/interfaces/domain.py53
-rw-r--r--Mailman/interfaces/pending.py66
-rw-r--r--Mailman/interfaces/registrar.py75
5 files changed, 246 insertions, 1 deletions
diff --git a/Mailman/interfaces/address.py b/Mailman/interfaces/address.py
index 8a6e42c60..6b00d7915 100644
--- a/Mailman/interfaces/address.py
+++ b/Mailman/interfaces/address.py
@@ -51,7 +51,7 @@ class IAddress(Interface):
been implicitly registered, e.g. by showing up in a non-member
posting.""")
- validated_on = Attribute(
+ verified_on = Attribute(
"""The date and time at which this email address was validated, or
None if the email address has not yet been validated. The specific
method of validation is not defined here.""")
diff --git a/Mailman/interfaces/database.py b/Mailman/interfaces/database.py
new file mode 100644
index 000000000..86bd54ce6
--- /dev/null
+++ b/Mailman/interfaces/database.py
@@ -0,0 +1,51 @@
+# Copyright (C) 2007 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Interfaces for database interaction.
+
+By providing an object with this interface and declaring it in a package
+setup.py file as an entry point in the 'mailman.database' group with the name
+'initializer', you can distribute entirely different database layers for
+Mailman's back end.
+"""
+
+from zope.interface import Interface, Attribute
+
+
+
+class IDatabase(Interface):
+ """Database layer interface."""
+
+ def initialize():
+ """Initialize the database layer, using whatever means necessary."""
+
+ def flush():
+ """Flush current database changes."""
+
+ # XXX Eventually we probably need to support a transaction manager
+ # interface, e.g. begin(), commit(), abort(). We will probably also need
+ # to support a shutdown() method for cleanly disconnecting from the
+ # database.sy
+
+ list_manager = Attribute(
+ """The IListManager instance provided by the database layer.""")
+
+ user_manager = Attribute(
+ """The IUserManager instance provided by the database layer.""")
+
+ message_store = Attribute(
+ """The IMessageStore instance provided by the database layer.""")
diff --git a/Mailman/interfaces/domain.py b/Mailman/interfaces/domain.py
new file mode 100644
index 000000000..db72e95db
--- /dev/null
+++ b/Mailman/interfaces/domain.py
@@ -0,0 +1,53 @@
+# Copyright (C) 2007 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Interface representing domains."""
+
+from zope.interface import Interface, Attribute
+
+
+
+class IDomain(Interface):
+ """Interface representing domains."""
+
+ domain_name = Attribute(
+ """The domain's name, e.g. python.org.""")
+
+ description = Attribute(
+ """The human readable description of the domain name.
+
+ E.g. Python Dot Org or mail.python.org.
+ """)
+
+ contact_address = Attribute(
+ """The contact address for the human at this domain.
+
+ E.g. postmaster@python.org.
+ """)
+
+ base_url = Attribute(
+ """The base url for the Mailman server at this domain.
+
+ E.g. https://mail.python.org
+ """)
+
+ def confirm_address(token=''):
+ """The address used for various forms of email confirmation."""
+
+ def confirm_url(token=''):
+ """The url used for various forms of confirmation."""
+
diff --git a/Mailman/interfaces/pending.py b/Mailman/interfaces/pending.py
new file mode 100644
index 000000000..5e26fbf6e
--- /dev/null
+++ b/Mailman/interfaces/pending.py
@@ -0,0 +1,66 @@
+# Copyright (C) 2007 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Interfaces for the pending database."""
+
+from munepy import Enum
+from zope.interface import Interface, Attribute
+
+
+
+class IPendable(Interface):
+ """A pendable object."""
+
+ def keys():
+ """The keys of the pending event data, all of which are strings."""
+
+ def values():
+ """The values of the pending event data, all of which are strings."""
+
+ def items():
+ """The key/value pairs of the pending event data.
+
+ Both the keys and values must be strings.
+ """
+
+
+
+class IPending(Interface):
+ """Interface to pending database."""
+
+ def add(pendable, lifetime=None):
+ """Create a new entry in the pending database, returning a token.
+
+ :param pendable: The IPendable instance to add.
+ :param lifetime: The amount of time, as a `datetime.timedelta` that
+ the pended item should remain in the database. When None is
+ given, a system default maximum lifetime is used.
+ :return: A token string for inclusion in urls and email confirmations.
+ """
+
+ def confirm(token, expunge=True):
+ """Return the IPendable matching the token.
+
+ :param token: The token string for the IPendable given by the `.add()`
+ method.
+ :param expunge: A flag indicating whether the pendable record should
+ also be removed from the database or not.
+ :return: The matching IPendable or None if no match was found.
+ """
+
+ def evict():
+ """Remove all pended items whose lifetime has expired."""
diff --git a/Mailman/interfaces/registrar.py b/Mailman/interfaces/registrar.py
new file mode 100644
index 000000000..b86764cdd
--- /dev/null
+++ b/Mailman/interfaces/registrar.py
@@ -0,0 +1,75 @@
+# Copyright (C) 2007 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Interface describing a user registration service.
+
+This is a higher level interface to user registration, address confirmation,
+etc. than the IUserManager. The latter does no validation, syntax checking,
+or confirmation, while this interface does.
+"""
+
+from zope.interface import Interface, Attribute
+
+
+
+class IRegistrar(Interface):
+ """Interface for registering and verifying addresses and users.
+
+ This is a higher level interface to user registration, address
+ confirmation, etc. than the IUserManager. The latter does no validation,
+ syntax checking, or confirmation, while this interface does.
+ """
+
+ def register(address, real_name=None):
+ """Register the email address, requesting verification.
+
+ No IAddress or IUser is created during this step, but after successful
+ confirmation, it is guaranteed that an IAddress with a linked IUser
+ will exist. When a verified IAddress matching address already exists,
+ this method will do nothing, except link a new IUser to the IAddress
+ if one is not yet associated with the address.
+
+ In all cases, the email address is sanity checked for validity first.
+
+ :param address: The textual email address to register.
+ :param real_name: The optional real name of the user.
+ :return: The confirmation token string.
+ :raises InvalidEmailAddress: if the address is not allowed.
+ """
+
+ def confirm(token):
+ """Confirm the pending registration matched to the given `token`.
+
+ Confirmation ensures that the IAddress exists and is linked to an
+ IUser, with the latter being created and linked if necessary.
+
+ :param token: A token matching a pending event with a type of
+ 'registration'.
+ :return: Boolean indicating whether the confirmation succeeded or
+ not. It may fail if the token is no longer in the database, or if
+ the token did not match a registration event.
+ """
+
+ def discard(token):
+ """Discard the pending registration matched to the given `token`.
+
+ The event record is discarded and the IAddress is not verified. No
+ IUser is created.
+
+ :param token: A token matching a pending event with a type of
+ 'registration'.
+ """