summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Warsaw2012-04-22 16:34:15 -0400
committerBarry Warsaw2012-04-22 16:34:15 -0400
commitaa12d1c5a4544e7005a6a93e2fff6e130b30e8b6 (patch)
tree133091548bacfb926f179845c17350c3c8aa1104
parentc95c06c080eded049e2f7516d61f579661dfb1c0 (diff)
downloadmailman-aa12d1c5a4544e7005a6a93e2fff6e130b30e8b6.tar.gz
mailman-aa12d1c5a4544e7005a6a93e2fff6e130b30e8b6.tar.zst
mailman-aa12d1c5a4544e7005a6a93e2fff6e130b30e8b6.zip
-rw-r--r--src/mailman/app/subscriptions.py14
-rw-r--r--src/mailman/model/autorespond.py21
-rw-r--r--src/mailman/model/bans.py37
-rw-r--r--src/mailman/model/bounce.py20
-rw-r--r--src/mailman/model/domain.py40
-rw-r--r--src/mailman/model/listmanager.py49
-rw-r--r--src/mailman/model/member.py11
-rw-r--r--src/mailman/model/message.py10
-rw-r--r--src/mailman/model/messagestore.py33
-rw-r--r--src/mailman/model/pending.py18
-rw-r--r--src/mailman/model/requests.py43
-rw-r--r--src/mailman/model/roster.py46
-rw-r--r--src/mailman/model/uid.py18
-rw-r--r--src/mailman/model/user.py21
-rw-r--r--src/mailman/model/usermanager.py51
15 files changed, 245 insertions, 187 deletions
diff --git a/src/mailman/app/subscriptions.py b/src/mailman/app/subscriptions.py
index 60f8cdebe..5852a7483 100644
--- a/src/mailman/app/subscriptions.py
+++ b/src/mailman/app/subscriptions.py
@@ -17,7 +17,7 @@
"""Module stuff."""
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -36,6 +36,7 @@ from zope.interface import implements
from mailman.app.membership import add_member, delete_member
from mailman.config import config
from mailman.core.constants import system_preferences
+from mailman.database.transaction import dbconnection
from mailman.interfaces.address import IEmailValidator
from mailman.interfaces.listmanager import (
IListManager, ListDeletedEvent, NoSuchListError)
@@ -90,9 +91,10 @@ class SubscriptionService:
sorted(by_role.get('member', []), key=address_of_member))
return all_members
- def get_member(self, member_id):
+ @dbconnection
+ def get_member(self, store, member_id):
"""See `ISubscriptionService`."""
- members = config.db.store.find(
+ members = store.find(
Member,
Member._member_id == member_id)
if members.count() == 0:
@@ -101,7 +103,9 @@ class SubscriptionService:
assert members.count() == 1, 'Too many matching members'
return members[0]
- def find_members(self, subscriber=None, fqdn_listname=None, role=None):
+ @dbconnection
+ def find_members(self, store,
+ subscriber=None, fqdn_listname=None, role=None):
"""See `ISubscriptionService`."""
# If `subscriber` is a user id, then we'll search for all addresses
# which are controlled by the user, otherwise we'll just search for
@@ -137,7 +141,7 @@ class SubscriptionService:
query.append(Member.mailing_list == fqdn_listname)
if role is not None:
query.append(Member.role == role)
- results = config.db.store.find(Member, And(*query))
+ results = store.find(Member, And(*query))
return sorted(results, key=_membership_sort_key)
def __iter__(self):
diff --git a/src/mailman/model/autorespond.py b/src/mailman/model/autorespond.py
index 7b42205b4..9e0fbd042 100644
--- a/src/mailman/model/autorespond.py
+++ b/src/mailman/model/autorespond.py
@@ -17,7 +17,7 @@
"""Module stuff."""
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -29,8 +29,8 @@ __all__ = [
from storm.locals import And, Date, Desc, Int, Reference
from zope.interface import implements
-from mailman.config import config
from mailman.database.model import Model
+from mailman.database.transaction import dbconnection
from mailman.database.types import Enum
from mailman.interfaces.autorespond import (
IAutoResponseRecord, IAutoResponseSet, Response)
@@ -66,27 +66,30 @@ class AutoResponseSet:
def __init__(self, mailing_list):
self._mailing_list = mailing_list
- def todays_count(self, address, response_type):
+ @dbconnection
+ def todays_count(self, store, address, response_type):
"""See `IAutoResponseSet`."""
- return config.db.store.find(
+ return store.find(
AutoResponseRecord,
And(AutoResponseRecord.address == address,
AutoResponseRecord.mailing_list == self._mailing_list,
AutoResponseRecord.response_type == response_type,
AutoResponseRecord.date_sent == today())).count()
- def response_sent(self, address, response_type):
+ @dbconnection
+ def response_sent(self, store, address, response_type):
"""See `IAutoResponseSet`."""
response = AutoResponseRecord(
self._mailing_list, address, response_type)
- config.db.store.add(response)
+ store.add(response)
- def last_response(self, address, response_type):
+ @dbconnection
+ def last_response(self, store, address, response_type):
"""See `IAutoResponseSet`."""
- results = config.db.store.find(
+ results = store.find(
AutoResponseRecord,
And(AutoResponseRecord.address == address,
AutoResponseRecord.mailing_list == self._mailing_list,
AutoResponseRecord.response_type == response_type)
- ).order_by(Desc(AutoResponseRecord.date_sent))
+ ).order_by(Desc(AutoResponseRecord.date_sent))
return (None if results.count() == 0 else results.first())
diff --git a/src/mailman/model/bans.py b/src/mailman/model/bans.py
index 9dc0c51ba..89addd8c7 100644
--- a/src/mailman/model/bans.py
+++ b/src/mailman/model/bans.py
@@ -17,7 +17,7 @@
"""Ban manager."""
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -30,8 +30,8 @@ import re
from storm.locals import Int, Unicode
from zope.interface import implements
-from mailman.config import config
from mailman.database.model import Model
+from mailman.database.transaction import dbconnection
from mailman.interfaces.bans import IBan, IBanManager
@@ -53,43 +53,43 @@ class Ban(Model):
class BanManager:
implements(IBanManager)
- def ban(self, email, mailing_list=None):
+ @dbconnection
+ def ban(self, store, email, mailing_list=None):
"""See `IBanManager`."""
- bans = config.db.store.find(
- Ban, email=email, mailing_list=mailing_list)
+ bans = store.find(Ban, email=email, mailing_list=mailing_list)
if bans.count() == 0:
ban = Ban(email, mailing_list)
- config.db.store.add(ban)
+ store.add(ban)
- def unban(self, email, mailing_list=None):
+ @dbconnection
+ def unban(self, store, email, mailing_list=None):
"""See `IBanManager`."""
- ban = config.db.store.find(
- Ban, email=email, mailing_list=mailing_list).one()
+ ban = store.find(Ban, email=email, mailing_list=mailing_list).one()
if ban is not None:
- config.db.store.remove(ban)
+ store.remove(ban)
- def is_banned(self, email, mailing_list=None):
+ @dbconnection
+ def is_banned(self, store, email, mailing_list=None):
"""See `IBanManager`."""
# A specific mailing list ban is being checked, however the email
# address could be banned specifically, or globally.
if mailing_list is not None:
# Try specific bans first.
- bans = config.db.store.find(
- Ban, email=email, mailing_list=mailing_list)
+ bans = store.find(Ban, email=email, mailing_list=mailing_list)
if bans.count() > 0:
return True
# Try global bans next.
- bans = config.db.store.find(Ban, email=email, mailing_list=None)
+ bans = store.find(Ban, email=email, mailing_list=None)
if bans.count() > 0:
return True
# Now try specific mailing list bans, but with a pattern.
- bans = config.db.store.find(Ban, mailing_list=mailing_list)
+ bans = store.find(Ban, mailing_list=mailing_list)
for ban in bans:
if (ban.email.startswith('^') and
re.match(ban.email, email, re.IGNORECASE) is not None):
return True
# And now try global pattern bans.
- bans = config.db.store.find(Ban, mailing_list=None)
+ bans = store.find(Ban, mailing_list=None)
for ban in bans:
if (ban.email.startswith('^') and
re.match(ban.email, email, re.IGNORECASE) is not None):
@@ -97,12 +97,11 @@ class BanManager:
else:
# The client is asking for global bans. Look up bans on the
# specific email address first.
- bans = config.db.store.find(
- Ban, email=email, mailing_list=None)
+ bans = store.find(Ban, email=email, mailing_list=None)
if bans.count() > 0:
return True
# And now look for global pattern bans.
- bans = config.db.store.find(Ban, mailing_list=None)
+ bans = store.find(Ban, mailing_list=None)
for ban in bans:
if (ban.email.startswith('^') and
re.match(ban.email, email, re.IGNORECASE) is not None):
diff --git a/src/mailman/model/bounce.py b/src/mailman/model/bounce.py
index 8c55e3d16..b957a2243 100644
--- a/src/mailman/model/bounce.py
+++ b/src/mailman/model/bounce.py
@@ -17,7 +17,7 @@
"""Bounce support."""
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -29,8 +29,8 @@ __all__ = [
from storm.locals import Bool, Int, DateTime, Unicode
from zope.interface import implements
-from mailman.config import config
from mailman.database.model import Model
+from mailman.database.transaction import dbconnection
from mailman.database.types import Enum
from mailman.interfaces.bounce import (
BounceContext, IBounceEvent, IBounceProcessor)
@@ -62,21 +62,23 @@ class BounceEvent(Model):
class BounceProcessor:
implements(IBounceProcessor)
- def register(self, mlist, email, msg, where=None):
+ @dbconnection
+ def register(self, store, mlist, email, msg, where=None):
"""See `IBounceProcessor`."""
event = BounceEvent(mlist.fqdn_listname, email, msg, where)
- config.db.store.add(event)
+ store.add(event)
return event
@property
- def events(self):
+ @dbconnection
+ def events(self, store):
"""See `IBounceProcessor`."""
- for event in config.db.store.find(BounceEvent):
+ for event in store.find(BounceEvent):
yield event
@property
- def unprocessed(self):
+ @dbconnection
+ def unprocessed(self, store):
"""See `IBounceProcessor`."""
- for event in config.db.store.find(BounceEvent,
- BounceEvent.processed == False):
+ for event in store.find(BounceEvent, BounceEvent.processed == False):
yield event
diff --git a/src/mailman/model/domain.py b/src/mailman/model/domain.py
index 49c935740..e93335328 100644
--- a/src/mailman/model/domain.py
+++ b/src/mailman/model/domain.py
@@ -17,7 +17,7 @@
"""Domains."""
-from __future__ import unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -31,8 +31,8 @@ from storm.locals import Int, Unicode
from zope.event import notify
from zope.interface import implements
-from mailman.config import config
from mailman.database.model import Model
+from mailman.database.transaction import dbconnection
from mailman.interfaces.domain import (
BadDomainSpecificationError, DomainCreatedEvent, DomainCreatingEvent,
DomainDeletedEvent, DomainDeletingEvent, IDomain, IDomainManager)
@@ -90,9 +90,10 @@ class Domain(Model):
return urlparse(self.base_url).scheme
@property
- def mailing_lists(self):
+ @dbconnection
+ def mailing_lists(self, store):
"""See `IDomain`."""
- mailing_lists = config.db.store.find(
+ mailing_lists = store.find(
MailingList,
MailingList.mail_host == self.mail_host)
for mlist in mailing_lists:
@@ -119,7 +120,9 @@ class DomainManager:
implements(IDomainManager)
- def add(self, mail_host,
+ @dbconnection
+ def add(self, store,
+ mail_host,
description=None,
base_url=None,
contact_address=None):
@@ -131,20 +134,22 @@ class DomainManager:
'Duplicate email host: %s' % mail_host)
notify(DomainCreatingEvent(mail_host))
domain = Domain(mail_host, description, base_url, contact_address)
- config.db.store.add(domain)
+ store.add(domain)
notify(DomainCreatedEvent(domain))
return domain
- def remove(self, mail_host):
+ @dbconnection
+ def remove(self, store, mail_host):
domain = self[mail_host]
notify(DomainDeletingEvent(domain))
- config.db.store.remove(domain)
+ store.remove(domain)
notify(DomainDeletedEvent(mail_host))
return domain
- def get(self, mail_host, default=None):
+ @dbconnection
+ def get(self, store, mail_host, default=None):
"""See `IDomainManager`."""
- domains = config.db.store.find(Domain, mail_host=mail_host)
+ domains = store.find(Domain, mail_host=mail_host)
if domains.count() < 1:
return default
assert domains.count() == 1, (
@@ -159,14 +164,17 @@ class DomainManager:
raise KeyError(mail_host)
return domain
- def __len__(self):
- return config.db.store.find(Domain).count()
+ @dbconnection
+ def __len__(self, store):
+ return store.find(Domain).count()
- def __iter__(self):
+ @dbconnection
+ def __iter__(self, store):
"""See `IDomainManager`."""
- for domain in config.db.store.find(Domain):
+ for domain in store.find(Domain):
yield domain
- def __contains__(self, mail_host):
+ @dbconnection
+ def __contains__(self, store, mail_host):
"""See `IDomainManager`."""
- return config.db.store.find(Domain, mail_host=mail_host).count() > 0
+ return store.find(Domain, mail_host=mail_host).count() > 0
diff --git a/src/mailman/model/listmanager.py b/src/mailman/model/listmanager.py
index 0ea87a082..8d845b36f 100644
--- a/src/mailman/model/listmanager.py
+++ b/src/mailman/model/listmanager.py
@@ -17,7 +17,7 @@
"""A mailing list manager."""
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -28,7 +28,7 @@ __all__ = [
from zope.event import notify
from zope.interface import implements
-from mailman.config import config
+from mailman.database.transaction import dbconnection
from mailman.interfaces.address import InvalidEmailAddressError
from mailman.interfaces.listmanager import (
IListManager, ListAlreadyExistsError, ListCreatedEvent, ListCreatingEvent,
@@ -43,13 +43,14 @@ class ListManager:
implements(IListManager)
- def create(self, fqdn_listname):
+ @dbconnection
+ def create(self, store, fqdn_listname):
"""See `IListManager`."""
listname, at, hostname = fqdn_listname.partition('@')
if len(hostname) == 0:
raise InvalidEmailAddressError(fqdn_listname)
notify(ListCreatingEvent(fqdn_listname))
- mlist = config.db.store.find(
+ mlist = store.find(
MailingList,
MailingList.list_name == listname,
MailingList.mail_host == hostname).one()
@@ -57,47 +58,53 @@ class ListManager:
raise ListAlreadyExistsError(fqdn_listname)
mlist = MailingList(fqdn_listname)
mlist.created_at = now()
- config.db.store.add(mlist)
+ store.add(mlist)
notify(ListCreatedEvent(mlist))
return mlist
- def get(self, fqdn_listname):
+ @dbconnection
+ def get(self, store, fqdn_listname):
"""See `IListManager`."""
listname, at, hostname = fqdn_listname.partition('@')
- return config.db.store.find(MailingList,
- list_name=listname,
- mail_host=hostname).one()
+ return store.find(MailingList,
+ list_name=listname,
+ mail_host=hostname).one()
- def delete(self, mlist):
+ @dbconnection
+ def delete(self, store, mlist):
"""See `IListManager`."""
fqdn_listname = mlist.fqdn_listname
notify(ListDeletingEvent(mlist))
- config.db.store.remove(mlist)
+ store.remove(mlist)
notify(ListDeletedEvent(fqdn_listname))
@property
- def mailing_lists(self):
+ @dbconnection
+ def mailing_lists(self, store):
"""See `IListManager`."""
- for mlist in config.db.store.find(MailingList):
+ for mlist in store.find(MailingList):
yield mlist
- def __iter__(self):
+ @dbconnection
+ def __iter__(self, store):
"""See `IListManager`."""
- for mlist in config.db.store.find(MailingList):
+ for mlist in store.find(MailingList):
yield mlist
@property
- def names(self):
+ @dbconnection
+ def names(self, store):
"""See `IListManager`."""
- result_set = config.db.store.find(MailingList)
- for mail_host, list_name in result_set.values(MailingList.mail_host,
+ result_set = store.find(MailingList)
+ for mail_host, list_name in result_set.values(MailingList.mail_host,
MailingList.list_name):
yield '{0}@{1}'.format(list_name, mail_host)
@property
- def name_components(self):
+ @dbconnection
+ def name_components(self, store):
"""See `IListManager`."""
- result_set = config.db.store.find(MailingList)
- for mail_host, list_name in result_set.values(MailingList.mail_host,
+ result_set = store.find(MailingList)
+ for mail_host, list_name in result_set.values(MailingList.mail_host,
MailingList.list_name):
yield list_name, mail_host
diff --git a/src/mailman/model/member.py b/src/mailman/model/member.py
index ae83fb388..5a71eb8be 100644
--- a/src/mailman/model/member.py
+++ b/src/mailman/model/member.py
@@ -17,7 +17,7 @@
"""Model for members."""
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -29,9 +29,9 @@ from storm.properties import UUID
from zope.component import getUtility
from zope.interface import implements
-from mailman.config import config
from mailman.core.constants import system_preferences
from mailman.database.model import Model
+from mailman.database.transaction import dbconnection
from mailman.database.types import Enum
from mailman.interfaces.action import Action
from mailman.interfaces.address import IAddress
@@ -176,7 +176,8 @@ class Member(Model):
# XXX Um, this is definitely wrong
return 'http://example.com/' + self.address.email
- def unsubscribe(self):
+ @dbconnection
+ def unsubscribe(self, store):
"""See `IMember`."""
- config.db.store.remove(self.preferences)
- config.db.store.remove(self)
+ store.remove(self.preferences)
+ store.remove(self)
diff --git a/src/mailman/model/message.py b/src/mailman/model/message.py
index 3345c64c9..67c4caf79 100644
--- a/src/mailman/model/message.py
+++ b/src/mailman/model/message.py
@@ -17,8 +17,7 @@
"""Model for messages."""
-
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -28,8 +27,8 @@ __all__ = [
from storm.locals import AutoReload, Int, RawStr, Unicode
from zope.interface import implements
-from mailman.config import config
from mailman.database.model import Model
+from mailman.database.transaction import dbconnection
from mailman.interfaces.messages import IMessage
@@ -45,9 +44,10 @@ class Message(Model):
path = RawStr()
# This is a Messge-ID field representation, not a database row id.
- def __init__(self, message_id, message_id_hash, path):
+ @dbconnection
+ def __init__(self, store, message_id, message_id_hash, path):
super(Message, self).__init__()
self.message_id = message_id
self.message_id_hash = message_id_hash
self.path = path
- config.db.store.add(self)
+ store.add(self)
diff --git a/src/mailman/model/messagestore.py b/src/mailman/model/messagestore.py
index 59490993b..df2205ff8 100644
--- a/src/mailman/model/messagestore.py
+++ b/src/mailman/model/messagestore.py
@@ -17,8 +17,7 @@
"""Model for message stores."""
-
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -34,6 +33,7 @@ import cPickle as pickle
from zope.interface import implements
from mailman.config import config
+from mailman.database.transaction import dbconnection
from mailman.interfaces.messages import IMessageStore
from mailman.model.message import Message
from mailman.utilities.filesystem import makedirs
@@ -49,7 +49,8 @@ EMPTYSTRING = ''
class MessageStore:
implements(IMessageStore)
- def add(self, message):
+ @dbconnection
+ def add(self, store, message):
# Ensure that the message has the requisite headers.
message_ids = message.get_all('message-id', [])
if len(message_ids) <> 1:
@@ -57,8 +58,7 @@ class MessageStore:
# Calculate and insert the X-Message-ID-Hash.
message_id = message_ids[0]
# Complain if the Message-ID already exists in the storage.
- existing = config.db.store.find(Message,
- Message.message_id == message_id).one()
+ existing = store.find(Message, Message.message_id == message_id).one()
if existing is not None:
raise ValueError(
'Message ID already exists in message store: {0}'.format(
@@ -104,34 +104,37 @@ class MessageStore:
with open(path) as fp:
return pickle.load(fp)
- def get_message_by_id(self, message_id):
- row = config.db.store.find(Message, message_id=message_id).one()
+ @dbconnection
+ def get_message_by_id(self, store, message_id):
+ row = store.find(Message, message_id=message_id).one()
if row is None:
return None
return self._get_message(row)
- def get_message_by_hash(self, message_id_hash):
+ @dbconnection
+ def get_message_by_hash(self, store, message_id_hash):
# It's possible the hash came from a message header, in which case it
# will be a Unicode. However when coming from source code, it may be
# an 8-string. Coerce to the latter if necessary; it must be
# US-ASCII.
if isinstance(message_id_hash, unicode):
message_id_hash = message_id_hash.encode('ascii')
- row = config.db.store.find(Message,
- message_id_hash=message_id_hash).one()
+ row = store.find(Message, message_id_hash=message_id_hash).one()
if row is None:
return None
return self._get_message(row)
@property
- def messages(self):
- for row in config.db.store.find(Message):
+ @dbconnection
+ def messages(self, store):
+ for row in store.find(Message):
yield self._get_message(row)
- def delete_message(self, message_id):
- row = config.db.store.find(Message, message_id=message_id).one()
+ @dbconnection
+ def delete_message(self, store, message_id):
+ row = store.find(Message, message_id=message_id).one()
if row is None:
raise LookupError(message_id)
path = os.path.join(config.MESSAGES_DIR, row.path)
os.remove(path)
- config.db.store.remove(row)
+ store.remove(row)
diff --git a/src/mailman/model/pending.py b/src/mailman/model/pending.py
index 557361c6f..39845e0bf 100644
--- a/src/mailman/model/pending.py
+++ b/src/mailman/model/pending.py
@@ -17,7 +17,7 @@
"""Implementations of the IPendable and IPending interfaces."""
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -37,6 +37,7 @@ from zope.interface.verify import verifyObject
from mailman.config import config
from mailman.database.model import Model
+from mailman.database.transaction import dbconnection
from mailman.interfaces.pending import (
IPendable, IPended, IPendedKeyValue, IPendings)
from mailman.utilities.datetime import now
@@ -86,7 +87,8 @@ class Pendings:
implements(IPendings)
- def add(self, pendable, lifetime=None):
+ @dbconnection
+ def add(self, store, pendable, lifetime=None):
verifyObject(IPendable, pendable)
# Calculate the token and the lifetime.
if lifetime is None:
@@ -104,7 +106,7 @@ class Pendings:
token = hashlib.sha1(repr(x)).hexdigest()
# In practice, we'll never get a duplicate, but we'll be anal
# about checking anyway.
- if config.db.store.find(Pended, token=token).count() == 0:
+ if store.find(Pended, token=token).count() == 0:
break
else:
raise AssertionError('Could not find a valid pendings token')
@@ -129,11 +131,11 @@ class Pendings:
'\2'.join(value))
keyval = PendedKeyValue(key=key, value=value)
pending.key_values.add(keyval)
- config.db.store.add(pending)
+ store.add(pending)
return token
- def confirm(self, token, expunge=True):
- store = config.db.store
+ @dbconnection
+ def confirm(self, store, token, expunge=True):
# Token can come in as a unicode, but it's stored in the database as
# bytes. They must be ascii.
pendings = store.find(Pended, token=str(token))
@@ -158,8 +160,8 @@ class Pendings:
store.remove(pending)
return pendable
- def evict(self):
- store = config.db.store
+ @dbconnection
+ def evict(self, store):
right_now = now()
for pending in store.find(Pended):
if pending.expiration_date < right_now:
diff --git a/src/mailman/model/requests.py b/src/mailman/model/requests.py
index 4a3efa67f..030c630b9 100644
--- a/src/mailman/model/requests.py
+++ b/src/mailman/model/requests.py
@@ -17,7 +17,7 @@
"""Implementations of the pending requests interfaces."""
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -29,8 +29,8 @@ from storm.locals import AutoReload, Int, RawStr, Reference, Unicode
from zope.component import getUtility
from zope.interface import implements
-from mailman.config import config
from mailman.database.model import Model
+from mailman.database.transaction import dbconnection
from mailman.database.types import Enum
from mailman.interfaces.pending import IPendable, IPendings
from mailman.interfaces.requests import IListRequests, RequestType
@@ -49,30 +49,33 @@ class ListRequests:
self.mailing_list = mailing_list
@property
- def count(self):
- return config.db.store.find(
- _Request, mailing_list=self.mailing_list).count()
+ @dbconnection
+ def count(self, store):
+ return store.find(_Request, mailing_list=self.mailing_list).count()
- def count_of(self, request_type):
- return config.db.store.find(
+ @dbconnection
+ def count_of(self, store, request_type):
+ return store.find(
_Request,
mailing_list=self.mailing_list, request_type=request_type).count()
@property
- def held_requests(self):
- results = config.db.store.find(
- _Request, mailing_list=self.mailing_list)
+ @dbconnection
+ def held_requests(self, store):
+ results = store.find(_Request, mailing_list=self.mailing_list)
for request in results:
yield request
- def of_type(self, request_type):
- results = config.db.store.find(
+ @dbconnection
+ def of_type(self, store, request_type):
+ results = store.find(
_Request,
mailing_list=self.mailing_list, request_type=request_type)
for request in results:
yield request
- def hold_request(self, request_type, key, data=None):
+ @dbconnection
+ def hold_request(self, store, request_type, key, data=None):
if request_type not in RequestType:
raise TypeError(request_type)
if data is None:
@@ -87,11 +90,12 @@ class ListRequests:
token = getUtility(IPendings).add(pendable, timedelta(days=5000))
data_hash = token
request = _Request(key, request_type, self.mailing_list, data_hash)
- config.db.store.add(request)
+ store.add(request)
return request.id
- def get_request(self, request_id, request_type=None):
- result = config.db.store.get(_Request, request_id)
+ @dbconnection
+ def get_request(self, store, request_id, request_type=None):
+ result = store.get(_Request, request_id)
if result is None:
return None
if request_type is not None and result.request_type != request_type:
@@ -104,13 +108,14 @@ class ListRequests:
data.update(pendable)
return result.key, data
- def delete_request(self, request_id):
- request = config.db.store.get(_Request, request_id)
+ @dbconnection
+ def delete_request(self, store, request_id):
+ request = store.get(_Request, request_id)
if request is None:
raise KeyError(request_id)
# Throw away the pended data.
getUtility(IPendings).confirm(request.data_hash)
- config.db.store.remove(request)
+ store.remove(request)
diff --git a/src/mailman/model/roster.py b/src/mailman/model/roster.py
index 48d434ab1..84ed12930 100644
--- a/src/mailman/model/roster.py
+++ b/src/mailman/model/roster.py
@@ -22,7 +22,7 @@ the ones that fit a particular role. These are used as the member, owner,
moderator, and administrator roster filters.
"""
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -40,7 +40,7 @@ __all__ = [
from storm.expr import And, Or
from zope.interface import implements
-from mailman.config import config
+from mailman.database.transaction import dbconnection
from mailman.interfaces.member import DeliveryMode, MemberRole
from mailman.interfaces.roster import IRoster
from mailman.model.address import Address
@@ -64,8 +64,9 @@ class AbstractRoster:
def __init__(self, mlist):
self._mlist = mlist
- def _query(self):
- return config.db.store.find(
+ @dbconnection
+ def _query(self, store):
+ return store.find(
Member,
mailing_list=self._mlist.fqdn_listname,
role=self.role)
@@ -101,9 +102,10 @@ class AbstractRoster:
for member in self.members:
yield member.address
- def get_member(self, address):
+ @dbconnection
+ def get_member(self, store, address):
"""See `IRoster`."""
- results = config.db.store.find(
+ results = store.find(
Member,
Member.mailing_list == self._mlist.fqdn_listname,
Member.role == self.role,
@@ -157,16 +159,18 @@ class AdministratorRoster(AbstractRoster):
name = 'administrator'
- def _query(self):
- return config.db.store.find(
+ @dbconnection
+ def _query(self, store):
+ return store.find(
Member,
Member.mailing_list == self._mlist.fqdn_listname,
Or(Member.role == MemberRole.owner,
Member.role == MemberRole.moderator))
- def get_member(self, address):
+ @dbconnection
+ def get_member(self, store, address):
"""See `IRoster`."""
- results = config.db.store.find(
+ results = store.find(
Member,
Member.mailing_list == self._mlist.fqdn_listname,
Or(Member.role == MemberRole.moderator,
@@ -194,7 +198,8 @@ class DeliveryMemberRoster(AbstractRoster):
# checking the delivery mode to a query parameter.
return len(tuple(self.members))
- def _get_members(self, *delivery_modes):
+ @dbconnection
+ def _get_members(self, store, *delivery_modes):
"""The set of members for a mailing list, filter by delivery mode.
:param delivery_modes: The modes to filter on.
@@ -202,7 +207,7 @@ class DeliveryMemberRoster(AbstractRoster):
:return: A generator of members.
:rtype: generator
"""
- results = config.db.store.find(
+ results = store.find(
Member,
And(Member.mailing_list == self._mlist.fqdn_listname,
Member.role == MemberRole.member))
@@ -244,10 +249,9 @@ class Subscribers(AbstractRoster):
name = 'subscribers'
- def _query(self):
- return config.db.store.find(
- Member,
- mailing_list=self._mlist.fqdn_listname)
+ @dbconnection
+ def _query(self, store):
+ return store.find(Member, mailing_list=self._mlist.fqdn_listname)
@@ -261,8 +265,9 @@ class Memberships:
def __init__(self, user):
self._user = user
- def _query(self):
- results = config.db.store.find(
+ @dbconnection
+ def _query(self, store):
+ results = store.find(
Member,
Or(Member.user_id == self._user.id,
And(Address.user_id == self._user.id,
@@ -291,9 +296,10 @@ class Memberships:
for address in self._user.addresses:
yield address
- def get_member(self, address):
+ @dbconnection
+ def get_member(self, store, address):
"""See `IRoster`."""
- results = config.db.store.find(
+ results = store.find(
Member,
Member.address_id == Address.id,
Address.user_id == self._user.id)
diff --git a/src/mailman/model/uid.py b/src/mailman/model/uid.py
index c3564aa40..08eae8aff 100644
--- a/src/mailman/model/uid.py
+++ b/src/mailman/model/uid.py
@@ -17,7 +17,7 @@
"""Unique IDs."""
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -28,8 +28,8 @@ __all__ = [
from storm.locals import Int
from storm.properties import UUID
-from mailman.config import config
from mailman.database.model import Model
+from mailman.database.transaction import dbconnection
@@ -48,23 +48,29 @@ class UID(Model):
id = Int(primary=True)
uid = UUID()
- def __init__(self, uid):
+ @dbconnection
+ def __init__(self, store, uid):
super(UID, self).__init__()
self.uid = uid
- config.db.store.add(self)
+ store.add(self)
def __repr__(self):
return '<UID {0} at {1}>'.format(self.uid, id(self))
@staticmethod
- def record(uid):
+ @dbconnection
+ # Note that the parameter order is deliberate reversed here. Normally,
+ # `store` is the first parameter after `self`, but since this is a
+ # staticmethod and there is no self, the decorator will see the uid in
+ # arg[0].
+ def record(uid, store):
"""Record the uid in the database.
:param uid: The unique id.
:type uid: unicode
:raises ValueError: if the id is not unique.
"""
- existing = config.db.store.find(UID, uid=uid)
+ existing = store.find(UID, uid=uid)
if existing.count() != 0:
raise ValueError(uid)
return UID(uid)
diff --git a/src/mailman/model/user.py b/src/mailman/model/user.py
index 9ca9b5aea..15ed9170f 100644
--- a/src/mailman/model/user.py
+++ b/src/mailman/model/user.py
@@ -17,7 +17,7 @@
"""Model for users."""
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -30,8 +30,8 @@ from storm.properties import UUID
from zope.event import notify
from zope.interface import implements
-from mailman.config import config
from mailman.database.model import Model
+from mailman.database.transaction import dbconnection
from mailman.interfaces.address import (
AddressAlreadyLinkedError, AddressNotLinkedError)
from mailman.interfaces.user import (
@@ -64,16 +64,17 @@ class User(Model):
preferences_id = Int()
preferences = Reference(preferences_id, 'Preferences.id')
- def __init__(self, display_name=None, preferences=None):
+ @dbconnection
+ def __init__(self, store, display_name=None, preferences=None):
super(User, self).__init__()
self._created_on = date_factory.now()
user_id = uid_factory.new_uid()
- assert config.db.store.find(User, _user_id=user_id).count() == 0, (
+ assert store.find(User, _user_id=user_id).count() == 0, (
'Duplicate user id {0}'.format(user_id))
self._user_id = user_id
self.display_name = ('' if display_name is None else display_name)
self.preferences = preferences
- config.db.store.add(self)
+ store.add(self)
def __repr__(self):
short_user_id = self.user_id.int
@@ -135,18 +136,20 @@ class User(Model):
"""See `IUser`."""
self._preferred_address = None
- def controls(self, email):
+ @dbconnection
+ def controls(self, store, email):
"""See `IUser`."""
- found = config.db.store.find(Address, email=email)
+ found = store.find(Address, email=email)
if found.count() == 0:
return False
assert found.count() == 1, 'Unexpected count'
return found[0].user is self
- def register(self, email, display_name=None):
+ @dbconnection
+ def register(self, store, email, display_name=None):
"""See `IUser`."""
# First, see if the address already exists
- address = config.db.store.find(Address, email=email).one()
+ address = store.find(Address, email=email).one()
if address is None:
if display_name is None:
display_name = ''
diff --git a/src/mailman/model/usermanager.py b/src/mailman/model/usermanager.py
index c8a5c65a2..2c4158b90 100644
--- a/src/mailman/model/usermanager.py
+++ b/src/mailman/model/usermanager.py
@@ -17,7 +17,7 @@
"""A user manager."""
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
@@ -27,7 +27,7 @@ __all__ = [
from zope.interface import implements
-from mailman.config import config
+from mailman.database.transaction import dbconnection
from mailman.interfaces.address import ExistingAddressError
from mailman.interfaces.usermanager import IUserManager
from mailman.model.address import Address
@@ -48,33 +48,38 @@ class UserManager:
user.link(address)
return user
- def delete_user(self, user):
+ @dbconnection
+ def delete_user(self, store, user):
"""See `IUserManager`."""
- config.db.store.remove(user)
+ store.remove(user)
- def get_user(self, email):
+ @dbconnection
+ def get_user(self, store, email):
"""See `IUserManager`."""
- addresses = config.db.store.find(Address, email=email.lower())
+ addresses = store.find(Address, email=email.lower())
if addresses.count() == 0:
return None
return addresses.one().user
- def get_user_by_id(self, user_id):
+ @dbconnection
+ def get_user_by_id(self, store, user_id):
"""See `IUserManager`."""
- users = config.db.store.find(User, _user_id=user_id)
+ users = store.find(User, _user_id=user_id)
if users.count() == 0:
return None
return users.one()
@property
- def users(self):
+ @dbconnection
+ def users(self, store):
"""See `IUserManager`."""
- for user in config.db.store.find(User):
+ for user in store.find(User):
yield user
- def create_address(self, email, display_name=None):
+ @dbconnection
+ def create_address(self, store, email, display_name=None):
"""See `IUserManager`."""
- addresses = config.db.store.find(Address, email=email.lower())
+ addresses = store.find(Address, email=email.lower())
if addresses.count() == 1:
found = addresses[0]
raise ExistingAddressError(found.original_email)
@@ -85,32 +90,36 @@ class UserManager:
# constructor will do the right thing.
address = Address(email, display_name)
address.preferences = Preferences()
- config.db.store.add(address)
+ store.add(address)
return address
- def delete_address(self, address):
+ @dbconnection
+ def delete_address(self, store, address):
"""See `IUserManager`."""
# If there's a user controlling this address, it has to first be
# unlinked before the address can be deleted.
if address.user:
address.user.unlink(address)
- config.db.store.remove(address)
+ store.remove(address)
- def get_address(self, email):
+ @dbconnection
+ def get_address(self, store, email):
"""See `IUserManager`."""
- addresses = config.db.store.find(Address, email=email.lower())
+ addresses = store.find(Address, email=email.lower())
if addresses.count() == 0:
return None
return addresses.one()
@property
- def addresses(self):
+ @dbconnection
+ def addresses(self, store):
"""See `IUserManager`."""
- for address in config.db.store.find(Address):
+ for address in store.find(Address):
yield address
@property
- def members(self):
+ @dbconnection
+ def members(self, store):
"""See `IUserManager."""
- for member in config.db.store.find(Member):
+ for member in store.find(Member):
yield member