diff options
| -rw-r--r-- | src/mailman/app/subscriptions.py | 14 | ||||
| -rw-r--r-- | src/mailman/model/autorespond.py | 21 | ||||
| -rw-r--r-- | src/mailman/model/bans.py | 37 | ||||
| -rw-r--r-- | src/mailman/model/bounce.py | 20 | ||||
| -rw-r--r-- | src/mailman/model/domain.py | 40 | ||||
| -rw-r--r-- | src/mailman/model/listmanager.py | 49 | ||||
| -rw-r--r-- | src/mailman/model/member.py | 11 | ||||
| -rw-r--r-- | src/mailman/model/message.py | 10 | ||||
| -rw-r--r-- | src/mailman/model/messagestore.py | 33 | ||||
| -rw-r--r-- | src/mailman/model/pending.py | 18 | ||||
| -rw-r--r-- | src/mailman/model/requests.py | 43 | ||||
| -rw-r--r-- | src/mailman/model/roster.py | 46 | ||||
| -rw-r--r-- | src/mailman/model/uid.py | 18 | ||||
| -rw-r--r-- | src/mailman/model/user.py | 21 | ||||
| -rw-r--r-- | src/mailman/model/usermanager.py | 51 |
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 |
