diff options
Diffstat (limited to 'src/mailman/model')
| -rw-r--r-- | src/mailman/model/address.py | 9 | ||||
| -rw-r--r-- | src/mailman/model/autorespond.py | 19 | ||||
| -rw-r--r-- | src/mailman/model/bans.py | 4 | ||||
| -rw-r--r-- | src/mailman/model/bounce.py | 6 | ||||
| -rw-r--r-- | src/mailman/model/digests.py | 2 | ||||
| -rw-r--r-- | src/mailman/model/docs/messagestore.rst | 5 | ||||
| -rw-r--r-- | src/mailman/model/domain.py | 2 | ||||
| -rw-r--r-- | src/mailman/model/language.py | 2 | ||||
| -rw-r--r-- | src/mailman/model/mailinglist.py | 157 | ||||
| -rw-r--r-- | src/mailman/model/member.py | 6 | ||||
| -rw-r--r-- | src/mailman/model/message.py | 3 | ||||
| -rw-r--r-- | src/mailman/model/messagestore.py | 26 | ||||
| -rw-r--r-- | src/mailman/model/mime.py | 4 | ||||
| -rw-r--r-- | src/mailman/model/pending.py | 35 | ||||
| -rw-r--r-- | src/mailman/model/preferences.py | 6 | ||||
| -rw-r--r-- | src/mailman/model/requests.py | 11 | ||||
| -rw-r--r-- | src/mailman/model/roster.py | 4 | ||||
| -rw-r--r-- | src/mailman/model/tests/test_listmanager.py | 7 | ||||
| -rw-r--r-- | src/mailman/model/tests/test_requests.py | 4 | ||||
| -rw-r--r-- | src/mailman/model/uid.py | 3 | ||||
| -rw-r--r-- | src/mailman/model/user.py | 27 | ||||
| -rw-r--r-- | src/mailman/model/version.py | 47 |
22 files changed, 179 insertions, 210 deletions
diff --git a/src/mailman/model/address.py b/src/mailman/model/address.py index 7203a31a5..d078f28d5 100644 --- a/src/mailman/model/address.py +++ b/src/mailman/model/address.py @@ -26,8 +26,8 @@ __all__ = [ from email.utils import formataddr -from sqlalchemy import (Column, Integer, String, Unicode, - ForeignKey, DateTime) +from sqlalchemy import ( + Column, DateTime, ForeignKey, Integer, Unicode) from sqlalchemy.orm import relationship, backref from zope.component import getUtility from zope.event import notify @@ -56,10 +56,11 @@ class Address(Model): user_id = Column(Integer, ForeignKey('user.id')) preferences_id = Column(Integer, ForeignKey('preferences.id')) - preferences = relationship('Preferences', - backref=backref('Address', uselist=False)) + preferences = relationship( + 'Preferences', backref=backref('Address', uselist=False)) def __init__(self, email, display_name): + super(Address, self).__init__() getUtility(IEmailValidator).validate(email) lower_case = email.lower() self.email = lower_case diff --git a/src/mailman/model/autorespond.py b/src/mailman/model/autorespond.py index c3aff174a..c74434f7b 100644 --- a/src/mailman/model/autorespond.py +++ b/src/mailman/model/autorespond.py @@ -26,8 +26,7 @@ __all__ = [ ] -from sqlalchemy import (Column, Integer, String, Unicode, - ForeignKey, Date) +from sqlalchemy import Column, Date, ForeignKey, Integer from sqlalchemy import desc from sqlalchemy.orm import relationship from zope.interface import implementer @@ -55,7 +54,7 @@ class AutoResponseRecord(Model): mailing_list_id = Column(Integer, ForeignKey('mailinglist.id')) mailing_list = relationship('MailingList') - response_type = Column(Enum(enum=Response)) + response_type = Column(Enum(Response)) date_sent = Column(Date) def __init__(self, mailing_list, address, response_type): @@ -77,10 +76,10 @@ class AutoResponseSet: def todays_count(self, store, address, response_type): """See `IAutoResponseSet`.""" return store.query(AutoResponseRecord).filter_by( - address = address, - mailing_list = self._mailing_list, - response_type = response_type, - date_sent = today()).count() + address=address, + mailing_list=self._mailing_list, + response_type=response_type, + date_sent=today()).count() @dbconnection def response_sent(self, store, address, response_type): @@ -93,8 +92,8 @@ class AutoResponseSet: def last_response(self, store, address, response_type): """See `IAutoResponseSet`.""" results = store.query(AutoResponseRecord).filter_by( - address = address, - mailing_list = self._mailing_list, - response_type = response_type + address=address, + mailing_list=self._mailing_list, + response_type=response_type ).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 fbbecaebd..8678fc1e7 100644 --- a/src/mailman/model/bans.py +++ b/src/mailman/model/bans.py @@ -72,8 +72,8 @@ class BanManager: @dbconnection def unban(self, store, email): """See `IBanManager`.""" - ban = store.query(Ban).filter_by(email=email, - list_id=self._list_id).first() + ban = store.query(Ban).filter_by( + email=email, list_id=self._list_id).first() if ban is not None: store.delete(ban) diff --git a/src/mailman/model/bounce.py b/src/mailman/model/bounce.py index 1165fee96..cd658052d 100644 --- a/src/mailman/model/bounce.py +++ b/src/mailman/model/bounce.py @@ -27,7 +27,7 @@ __all__ = [ -from sqlalchemy import Column, Integer, Unicode, DateTime, Boolean +from sqlalchemy import Boolean, Column, DateTime, Integer, Unicode from zope.interface import implementer from mailman.database.model import Model @@ -50,7 +50,7 @@ class BounceEvent(Model): email = Column(Unicode) timestamp = Column(DateTime) message_id = Column(Unicode) - context = Column(Enum(enum=BounceContext)) + context = Column(Enum(BounceContext)) processed = Column(Boolean) def __init__(self, list_id, email, msg, context=None): @@ -85,5 +85,5 @@ class BounceProcessor: @dbconnection def unprocessed(self, store): """See `IBounceProcessor`.""" - for event in store.query(BounceEvent).filter_by(processed = False): + for event in store.query(BounceEvent).filter_by(processed=False): yield event diff --git a/src/mailman/model/digests.py b/src/mailman/model/digests.py index 1b7140824..7bfd512b6 100644 --- a/src/mailman/model/digests.py +++ b/src/mailman/model/digests.py @@ -50,7 +50,7 @@ class OneLastDigest(Model): address_id = Column(Integer, ForeignKey('address.id')) address = relationship('Address') - delivery_mode = Column(Enum(enum=DeliveryMode)) + delivery_mode = Column(Enum(DeliveryMode)) def __init__(self, mailing_list, address, delivery_mode): self.mailing_list = mailing_list diff --git a/src/mailman/model/docs/messagestore.rst b/src/mailman/model/docs/messagestore.rst index 4ddce7606..f2f2ca9d2 100644 --- a/src/mailman/model/docs/messagestore.rst +++ b/src/mailman/model/docs/messagestore.rst @@ -28,8 +28,9 @@ header, you will get an exception. However, if the message has a ``Message-ID`` header, it can be stored. >>> msg['Message-ID'] = '<87myycy5eh.fsf@uwakimon.sk.tsukuba.ac.jp>' - >>> message_store.add(msg) - 'AGDWSNXXKCWEILKKNYTBOHRDQGOX3Y35' + >>> x_message_id_hash = message_store.add(msg) + >>> print(x_message_id_hash) + AGDWSNXXKCWEILKKNYTBOHRDQGOX3Y35 >>> print(msg.as_string()) Subject: An important message Message-ID: <87myycy5eh.fsf@uwakimon.sk.tsukuba.ac.jp> diff --git a/src/mailman/model/domain.py b/src/mailman/model/domain.py index 585eccf3d..083e1cf51 100644 --- a/src/mailman/model/domain.py +++ b/src/mailman/model/domain.py @@ -26,8 +26,8 @@ __all__ = [ ] +from sqlalchemy import Column, Integer, Unicode from urlparse import urljoin, urlparse -from sqlalchemy import Column, Unicode, Integer from zope.event import notify from zope.interface import implementer diff --git a/src/mailman/model/language.py b/src/mailman/model/language.py index 7b611b6d8..15450c936 100644 --- a/src/mailman/model/language.py +++ b/src/mailman/model/language.py @@ -25,8 +25,8 @@ __all__ = [ ] +from sqlalchemy import Column, Integer, Unicode from zope.interface import implementer -from sqlalchemy import Column, Unicode, Integer from mailman.database import Model from mailman.interfaces import ILanguage diff --git a/src/mailman/model/mailinglist.py b/src/mailman/model/mailinglist.py index 385262f28..d00cf3d31 100644 --- a/src/mailman/model/mailinglist.py +++ b/src/mailman/model/mailinglist.py @@ -27,10 +27,11 @@ __all__ = [ import os -from sqlalchemy import (Column, Boolean, DateTime, Float, Integer, Unicode, - PickleType, Interval, ForeignKey, LargeBinary) -from sqlalchemy import event -from sqlalchemy.orm import relationship, sessionmaker +from sqlalchemy import ( + Boolean, Column, DateTime, Float, ForeignKey, Integer, Interval, + LargeBinary, PickleType, Unicode) +from sqlalchemy.event import listen +from sqlalchemy.orm import relationship from urlparse import urljoin from zope.component import getUtility from zope.event import notify @@ -38,6 +39,7 @@ from zope.interface import implementer 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.action import Action, FilterAction from mailman.interfaces.address import IAddress @@ -68,7 +70,6 @@ from mailman.utilities.string import expand SPACE = ' ' UNDERSCORE = '_' -Session = sessionmaker() @implementer(IMailingList) @@ -100,9 +101,6 @@ class MailingList(Model): digest_last_sent_at = Column(DateTime) volume = Column(Integer) last_post_at = Column(DateTime) - # Implicit destination. - # acceptable_aliases_id = Column(Integer, ForeignKey('acceptablealias.id')) - # acceptable_alias = relationship('AcceptableAlias', backref='mailing_list') # Attributes which are directly modifiable via the web u/i. The more # complicated attributes are currently stored as pickles, though that # will change as the schema and implementation is developed. @@ -110,17 +108,17 @@ class MailingList(Model): admin_immed_notify = Column(Boolean) admin_notify_mchanges = Column(Boolean) administrivia = Column(Boolean) - archive_policy = Column(Enum(enum=ArchivePolicy)) + archive_policy = Column(Enum(ArchivePolicy)) # Automatic responses. autoresponse_grace_period = Column(Interval) - autorespond_owner = Column(Enum(enum=ResponseAction)) + autorespond_owner = Column(Enum(ResponseAction)) autoresponse_owner_text = Column(Unicode) - autorespond_postings = Column(Enum(enum=ResponseAction)) + autorespond_postings = Column(Enum(ResponseAction)) autoresponse_postings_text = Column(Unicode) - autorespond_requests = Column(Enum(enum=ResponseAction)) + autorespond_requests = Column(Enum(ResponseAction)) autoresponse_request_text = Column(Unicode) # Content filters. - filter_action = Column(Enum(enum=FilterAction)) + filter_action = Column(Enum(FilterAction)) filter_content = Column(Boolean) collapse_alternatives = Column(Boolean) convert_html_to_plaintext = Column(Boolean) @@ -132,18 +130,19 @@ class MailingList(Model): bounce_score_threshold = Column(Integer) # XXX bounce_you_are_disabled_warnings = Column(Integer) # XXX bounce_you_are_disabled_warnings_interval = Column(Interval) # XXX - forward_unrecognized_bounces_to = Column(Enum(enum=UnrecognizedBounceDisposition)) + forward_unrecognized_bounces_to = Column( + Enum(UnrecognizedBounceDisposition)) process_bounces = Column(Boolean) # Miscellaneous - default_member_action = Column(Enum(enum=Action)) - default_nonmember_action = Column(Enum(enum=Action)) + default_member_action = Column(Enum(Action)) + default_nonmember_action = Column(Enum(Action)) description = Column(Unicode) digest_footer_uri = Column(Unicode) digest_header_uri = Column(Unicode) digest_is_default = Column(Boolean) digest_send_periodic = Column(Boolean) digest_size_threshold = Column(Float) - digest_volume_frequency = Column(Enum(enum=DigestFrequency)) + digest_volume_frequency = Column(Enum(DigestFrequency)) digestable = Column(Boolean) discard_these_nonmembers = Column(PickleType) emergency = Column(Boolean) @@ -166,21 +165,21 @@ class MailingList(Model): mime_is_default_digest = Column(Boolean) # FIXME: There should be no moderator_password moderator_password = Column(LargeBinary) # TODO : was RawStr() - newsgroup_moderation = Column(Enum(enum=NewsgroupModeration)) + newsgroup_moderation = Column(Enum(NewsgroupModeration)) nntp_prefix_subject_too = Column(Boolean) nondigestable = Column(Boolean) nonmember_rejection_notice = Column(Unicode) obscure_addresses = Column(Boolean) owner_chain = Column(Unicode) owner_pipeline = Column(Unicode) - personalize = Column(Enum(enum=Personalization)) + personalize = Column(Enum(Personalization)) post_id = Column(Integer) posting_chain = Column(Unicode) posting_pipeline = Column(Unicode) _preferred_language = Column('preferred_language', Unicode) display_name = Column(Unicode) reject_these_nonmembers = Column(PickleType) - reply_goes_to_list = Column(Enum(enum=ReplyToMunging)) + reply_goes_to_list = Column(Enum(ReplyToMunging)) reply_to_address = Column(Unicode) require_explicit_destination = Column(Boolean) respond_to_post_requests = Column(Boolean) @@ -194,6 +193,7 @@ class MailingList(Model): welcome_message_uri = Column(Unicode) def __init__(self, fqdn_listname): + super(MailingList, self).__init__() listname, at, hostname = fqdn_listname.partition('@') assert hostname, 'Bad list name: {0}'.format(fqdn_listname) self.list_name = listname @@ -201,15 +201,15 @@ class MailingList(Model): self._list_id = '{0}.{1}'.format(listname, hostname) # For the pending database self.next_request_id = 1 - # We need to set up the rosters. Normally, this method will get - # called when the MailingList object is loaded from the database, but - # that's not the case when the constructor is called. So, set up the - # rosters explicitly. + # We need to set up the rosters. Normally, this method will get called + # when the MailingList object is loaded from the database, but when the + # constructor is called, SQLAlchemy's `load` event isn't triggered. + # Thus we need to set up the rosters explicitly. self._post_load() makedirs(self.data_path) - def _post_load(self, *args): + # This hooks up to SQLAlchemy's `load` event. self.owners = roster.OwnerRoster(self) self.moderators = roster.ModeratorRoster(self) self.administrators = roster.AdministratorRoster(self) @@ -221,7 +221,10 @@ class MailingList(Model): @classmethod def __declare_last__(cls): - event.listen(cls, 'load', cls._post_load) + # SQLAlchemy special directive hook called after mappings are assumed + # to be complete. Use this to connect the roster instance creation + # method with the SA `load` event. + listen(cls, 'load', cls._post_load) def __repr__(self): return '<mailing list "{0}" at {1:#x}>'.format( @@ -331,15 +334,17 @@ class MailingList(Model): except AttributeError: self._preferred_language = language - def send_one_last_digest_to(self, address, delivery_mode): + @dbconnection + def send_one_last_digest_to(self, store, address, delivery_mode): """See `IMailingList`.""" digest = OneLastDigest(self, address, delivery_mode) - Session.object_session(self).add(digest) + store.add(digest) @property - def last_digest_recipients(self): + @dbconnection + def last_digest_recipients(self, store): """See `IMailingList`.""" - results = Session.object_session(self).query(OneLastDigest).filter( + results = store.query(OneLastDigest).filter( OneLastDigest.mailing_list == self) recipients = [(digest.address, digest.delivery_mode) for digest in results] @@ -347,19 +352,20 @@ class MailingList(Model): return recipients @property - def filter_types(self): + @dbconnection + def filter_types(self, store): """See `IMailingList`.""" - results = Session.object_session(self).query(ContentFilter).filter( + results = store.query(ContentFilter).filter( ContentFilter.mailing_list == self, ContentFilter.filter_type == FilterType.filter_mime) for content_filter in results: yield content_filter.filter_pattern @filter_types.setter - def filter_types(self, sequence): + @dbconnection + def filter_types(self, store, sequence): """See `IMailingList`.""" # First, delete all existing MIME type filter patterns. - store = Session.object_session(self) results = store.query(ContentFilter).filter( ContentFilter.mailing_list == self, ContentFilter.filter_type == FilterType.filter_mime) @@ -371,19 +377,20 @@ class MailingList(Model): store.add(content_filter) @property - def pass_types(self): + @dbconnection + def pass_types(self, store): """See `IMailingList`.""" - results = Session.object_session(self).query(ContentFilter).filter( + results = store.query(ContentFilter).filter( ContentFilter.mailing_list == self, ContentFilter.filter_type == FilterType.pass_mime) for content_filter in results: yield content_filter.filter_pattern @pass_types.setter - def pass_types(self, sequence): + @dbconnection + def pass_types(self, store, sequence): """See `IMailingList`.""" # First, delete all existing MIME type pass patterns. - store = Session.object_session(self) results = store.query(ContentFilter).filter( ContentFilter.mailing_list == self, ContentFilter.filter_type == FilterType.pass_mime) @@ -395,19 +402,20 @@ class MailingList(Model): store.add(content_filter) @property - def filter_extensions(self): + @dbconnection + def filter_extensions(self, store): """See `IMailingList`.""" - results = Session.object_session(self).query(ContentFilter).filter( + results = store.query(ContentFilter).filter( ContentFilter.mailing_list == self, ContentFilter.filter_type == FilterType.filter_extension) for content_filter in results: yield content_filter.filter_pattern @filter_extensions.setter - def filter_extensions(self, sequence): + @dbconnection + def filter_extensions(self, store, sequence): """See `IMailingList`.""" # First, delete all existing file extensions filter patterns. - store = Session.object_session(self) results = store.query(ContentFilter).filter( ContentFilter.mailing_list == self, ContentFilter.filter_type == FilterType.filter_extension) @@ -419,19 +427,20 @@ class MailingList(Model): store.add(content_filter) @property - def pass_extensions(self): + @dbconnection + def pass_extensions(self, store): """See `IMailingList`.""" - results = Session.object_session(self).query(ContentFilter).filter( + results = store.query(ContentFilter).filter( ContentFilter.mailing_list == self, ContentFilter.filter_type == FilterType.pass_extension) for content_filter in results: yield content_filter.pass_pattern @pass_extensions.setter - def pass_extensions(self, sequence): + @dbconnection + def pass_extensions(self, store, sequence): """See `IMailingList`.""" # First, delete all existing file extensions pass patterns. - store = Session.object_session(self) results = store.query(ContentFilter).filter( ContentFilter.mailing_list == self, ContentFilter.filter_type == FilterType.pass_extension) @@ -454,9 +463,9 @@ class MailingList(Model): raise TypeError( 'Undefined MemberRole: {0}'.format(role)) - def subscribe(self, subscriber, role=MemberRole.member): + @dbconnection + def subscribe(self, store, subscriber, role=MemberRole.member): """See `IMailingList`.""" - store = Session.object_session(self) if IAddress.providedBy(subscriber): member = store.query(Member).filter( Member.role == role, @@ -512,29 +521,30 @@ class AcceptableAliasSet: def __init__(self, mailing_list): self._mailing_list = mailing_list - def clear(self): + @dbconnection + def clear(self, store): """See `IAcceptableAliasSet`.""" - Session.object_session(self._mailing_list).query( - AcceptableAlias).filter( - AcceptableAlias.mailing_list == self._mailing_list).delete() + store.query(AcceptableAlias).filter( + AcceptableAlias.mailing_list == self._mailing_list).delete() - def add(self, alias): + @dbconnection + def add(self, store, alias): if not (alias.startswith('^') or '@' in alias): raise ValueError(alias) alias = AcceptableAlias(self._mailing_list, alias.lower()) - Session.object_session(self._mailing_list).add(alias) + store.add(alias) - def remove(self, alias): - Session.object_session(self._mailing_list).query( - AcceptableAlias).filter( - AcceptableAlias.mailing_list == self._mailing_list, - AcceptableAlias.alias == alias.lower()).delete() + @dbconnection + def remove(self, store, alias): + store.query(AcceptableAlias).filter( + AcceptableAlias.mailing_list == self._mailing_list, + AcceptableAlias.alias == alias.lower()).delete() @property - def aliases(self): - aliases = Session.object_session(self._mailing_list).query( - AcceptableAlias).filter( - AcceptableAlias.mailing_list_id == self._mailing_list.id) + @dbconnection + def aliases(self, store): + aliases = store.query(AcceptableAlias).filter( + AcceptableAlias.mailing_list_id == self._mailing_list.id) for alias in aliases: yield alias.alias @@ -576,14 +586,14 @@ class ListArchiver(Model): @implementer(IListArchiverSet) class ListArchiverSet: - def __init__(self, mailing_list): + @dbconnection + def __init__(self, store, mailing_list): self._mailing_list = mailing_list system_archivers = {} for archiver in config.archivers: system_archivers[archiver.name] = archiver # Add any system enabled archivers which aren't already associated # with the mailing list. - store = Session.object_session(self._mailing_list) for archiver_name in system_archivers: exists = store.query(ListArchiver).filter( ListArchiver.mailing_list == mailing_list, @@ -593,14 +603,15 @@ class ListArchiverSet: system_archivers[archiver_name])) @property - def archivers(self): - entries = Session.object_session(self._mailing_list).query( - ListArchiver).filter(ListArchiver.mailing_list == self._mailing_list) + @dbconnection + def archivers(self, store): + entries = store.query(ListArchiver).filter( + ListArchiver.mailing_list == self._mailing_list) for entry in entries: yield entry - def get(self, archiver_name): - return Session.object_session(self._mailing_list).query( - ListArchiver).filter( - ListArchiver.mailing_list == self._mailing_list, - ListArchiver.name == archiver_name).first() + @dbconnection + def get(self, store, archiver_name): + return store.query(ListArchiver).filter( + ListArchiver.mailing_list == self._mailing_list, + ListArchiver.name == archiver_name).first() diff --git a/src/mailman/model/member.py b/src/mailman/model/member.py index f1007c311..9da9d5d0d 100644 --- a/src/mailman/model/member.py +++ b/src/mailman/model/member.py @@ -24,7 +24,7 @@ __all__ = [ 'Member', ] -from sqlalchemy import Integer, Unicode, ForeignKey, Column +from sqlalchemy import Column, ForeignKey, Integer, Unicode from sqlalchemy.orm import relationship from zope.component import getUtility from zope.event import notify @@ -56,9 +56,9 @@ class Member(Model): id = Column(Integer, primary_key=True) _member_id = Column(UUID) - role = Column(Enum(enum=MemberRole)) + role = Column(Enum(MemberRole)) list_id = Column(Unicode) - moderation_action = Column(Enum(enum=Action)) + moderation_action = Column(Enum(Action)) address_id = Column(Integer, ForeignKey('address.id')) _address = relationship('Address') diff --git a/src/mailman/model/message.py b/src/mailman/model/message.py index 39f33aa89..74a76ac30 100644 --- a/src/mailman/model/message.py +++ b/src/mailman/model/message.py @@ -24,7 +24,7 @@ __all__ = [ 'Message', ] -from sqlalchemy import Column, Integer, Unicode, LargeBinary +from sqlalchemy import Column, Integer, LargeBinary, Unicode from zope.interface import implementer from mailman.database.model import Model @@ -47,6 +47,7 @@ class Message(Model): @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 diff --git a/src/mailman/model/messagestore.py b/src/mailman/model/messagestore.py index f9f224dd6..225d3d1ce 100644 --- a/src/mailman/model/messagestore.py +++ b/src/mailman/model/messagestore.py @@ -54,18 +54,19 @@ class MessageStore: 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: + if len(message_ids) != 1: raise ValueError('Exactly one Message-ID header required') # Calculate and insert the X-Message-ID-Hash. message_id = message_ids[0] # Complain if the Message-ID already exists in the storage. - existing = store.query(Message).filter(Message.message_id == message_id).first() + existing = store.query(Message).filter( + Message.message_id == message_id).first() if existing is not None: raise ValueError( 'Message ID already exists in message store: {0}'.format( message_id)) shaobj = hashlib.sha1(message_id) - hash32 = base64.b32encode(shaobj.digest()) + hash32 = base64.b32encode(shaobj.digest()).decode('ascii') del message['X-Message-ID-Hash'] message['X-Message-ID-Hash'] = hash32 # Calculate the path on disk where we're going to store this message @@ -80,9 +81,9 @@ class MessageStore: # providing a unique serial number, but to get this information, we # have to use a straight insert instead of relying on Elixir to create # the object. - row = Message(message_id=message_id, - message_id_hash=hash32, - path=relpath) + Message(message_id=message_id, + message_id_hash=hash32, + path=relpath) # Now calculate the full file system path. path = os.path.join(config.MESSAGES_DIR, relpath) # Write the file to the path, but catch the appropriate exception in @@ -95,7 +96,7 @@ class MessageStore: pickle.dump(message, fp, -1) break except IOError as error: - if error.errno <> errno.ENOENT: + if error.errno != errno.ENOENT: raise makedirs(os.path.dirname(path)) return hash32 @@ -114,13 +115,10 @@ class MessageStore: @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 = store.query(Message).filter_by(message_id_hash=message_id_hash).first() + if isinstance(message_id_hash, bytes): + message_id_hash = message_id_hash.decode('utf-8') + row = store.query(Message).filter_by( + message_id_hash=message_id_hash).first() if row is None: return None return self._get_message(row) diff --git a/src/mailman/model/mime.py b/src/mailman/model/mime.py index 3eac4f07b..906af91ea 100644 --- a/src/mailman/model/mime.py +++ b/src/mailman/model/mime.py @@ -25,7 +25,7 @@ __all__ = [ ] -from sqlalchemy import Column, Integer, Unicode, ForeignKey +from sqlalchemy import Column, ForeignKey, Integer, Unicode from sqlalchemy.orm import relationship from zope.interface import implementer @@ -46,7 +46,7 @@ class ContentFilter(Model): mailing_list_id = Column(Integer, ForeignKey('mailinglist.id')) mailing_list = relationship('MailingList') - filter_type = Column(Enum(enum=FilterType)) + filter_type = Column(Enum(FilterType)) filter_pattern = Column(Unicode) def __init__(self, mailing_list, filter_pattern, filter_type): diff --git a/src/mailman/model/pending.py b/src/mailman/model/pending.py index 97d394721..68a8cd63e 100644 --- a/src/mailman/model/pending.py +++ b/src/mailman/model/pending.py @@ -32,7 +32,7 @@ import hashlib from lazr.config import as_timedelta from sqlalchemy import ( - Column, Integer, Unicode, ForeignKey, DateTime, LargeBinary) + Column, DateTime, ForeignKey, Integer, LargeBinary, Unicode) from sqlalchemy.orm import relationship from zope.interface import implementer from zope.interface.verify import verifyObject @@ -53,15 +53,15 @@ class PendedKeyValue(Model): __tablename__ = 'pendedkeyvalue' - def __init__(self, key, value): - self.key = key - self.value = value - id = Column(Integer, primary_key=True) key = Column(Unicode) value = Column(Unicode) pended_id = Column(Integer, ForeignKey('pended.id')) + def __init__(self, key, value): + self.key = key + self.value = value + @implementer(IPended) @@ -70,15 +70,17 @@ class Pended(Model): __tablename__ = 'pended' - def __init__(self, token, expiration_date): - self.token = token - self.expiration_date = expiration_date - id = Column(Integer, primary_key=True) token = Column(LargeBinary) # TODO : was RawStr() expiration_date = Column(DateTime) key_values = relationship('PendedKeyValue') + def __init__(self, token, expiration_date): + super(Pended, self).__init__() + self.token = token + self.expiration_date = expiration_date + + @implementer(IPendable) class UnpendedPendable(dict): @@ -118,10 +120,10 @@ class Pendings: token=token, expiration_date=now() + lifetime) for key, value in pendable.items(): - if isinstance(key, str): - key = unicode(key, 'utf-8') - if isinstance(value, str): - value = unicode(value, 'utf-8') + if isinstance(key, bytes): + key = key.decode('utf-8') + if isinstance(value, bytes): + value = value.decode('utf-8') elif type(value) is int: value = '__builtin__.int\1%s' % value elif type(value) is float: @@ -150,8 +152,9 @@ class Pendings: pendable = UnpendedPendable() # Find all PendedKeyValue entries that are associated with the pending # object's ID. Watch out for type conversions. - for keyvalue in store.query(PendedKeyValue).filter( - PendedKeyValue.pended_id == pending.id): + entries = store.query(PendedKeyValue).filter( + PendedKeyValue.pended_id == pending.id) + for keyvalue in entries: if keyvalue.value is not None and '\1' in keyvalue.value: type_name, value = keyvalue.value.split('\1', 1) pendable[keyvalue.key] = call_name(type_name, value) @@ -171,7 +174,7 @@ class Pendings: # Find all PendedKeyValue entries that are associated with the # pending object's ID. q = store.query(PendedKeyValue).filter( - PendedKeyValue.pended_id == pending.id) + PendedKeyValue.pended_id == pending.id) for keyvalue in q: store.delete(keyvalue) store.delete(pending) diff --git a/src/mailman/model/preferences.py b/src/mailman/model/preferences.py index d74b17e30..1278f80b7 100644 --- a/src/mailman/model/preferences.py +++ b/src/mailman/model/preferences.py @@ -25,7 +25,7 @@ __all__ = [ ] -from sqlalchemy import Column, Integer, Unicode, Boolean +from sqlalchemy import Boolean, Column, Integer, Unicode from zope.component import getUtility from zope.interface import implementer @@ -49,8 +49,8 @@ class Preferences(Model): _preferred_language = Column('preferred_language', Unicode) receive_list_copy = Column(Boolean) receive_own_postings = Column(Boolean) - delivery_mode = Column(Enum(enum=DeliveryMode)) - delivery_status = Column(Enum(enum=DeliveryStatus)) + delivery_mode = Column(Enum(DeliveryMode)) + delivery_status = Column(Enum(DeliveryStatus)) def __repr__(self): return '<Preferences object at {0:#x}>'.format(id(self)) diff --git a/src/mailman/model/requests.py b/src/mailman/model/requests.py index 3d15ddea9..335e1e002 100644 --- a/src/mailman/model/requests.py +++ b/src/mailman/model/requests.py @@ -26,7 +26,7 @@ __all__ = [ from cPickle import dumps, loads from datetime import timedelta -from sqlalchemy import Column, Unicode, Integer, ForeignKey, LargeBinary +from sqlalchemy import Column, ForeignKey, Integer, LargeBinary, Unicode from sqlalchemy.orm import relationship from zope.component import getUtility from zope.interface import implementer @@ -69,7 +69,8 @@ class ListRequests: @property @dbconnection def count(self, store): - return store.query(_Request).filter_by(mailing_list=self.mailing_list).count() + return store.query(_Request).filter_by( + mailing_list=self.mailing_list).count() @dbconnection def count_of(self, store, request_type): @@ -79,7 +80,8 @@ class ListRequests: @property @dbconnection def held_requests(self, store): - results = store.query(_Request).filter_by(mailing_list=self.mailing_list) + results = store.query(_Request).filter_by( + mailing_list=self.mailing_list) for request in results: yield request @@ -148,13 +150,14 @@ class _Request(Model): id = Column(Integer, primary_key=True)# TODO: ???, default=AutoReload) key = Column(Unicode) - request_type = Column(Enum(enum=RequestType)) + request_type = Column(Enum(RequestType)) data_hash = Column(LargeBinary) mailing_list_id = Column(Integer, ForeignKey('mailinglist.id')) mailing_list = relationship('MailingList') def __init__(self, key, request_type, mailing_list, data_hash): + super(_Request, self).__init__() self.key = key self.request_type = request_type self.mailing_list = mailing_list diff --git a/src/mailman/model/roster.py b/src/mailman/model/roster.py index a9a396523..a6cbeb104 100644 --- a/src/mailman/model/roster.py +++ b/src/mailman/model/roster.py @@ -161,7 +161,7 @@ class AdministratorRoster(AbstractRoster): return store.query(Member).filter( Member.list_id == self._mlist.list_id, or_(Member.role == MemberRole.owner, - Member.role == MemberRole.moderator)) + Member.role == MemberRole.moderator)) @dbconnection def get_member(self, store, address): @@ -169,7 +169,7 @@ class AdministratorRoster(AbstractRoster): results = store.query(Member).filter( Member.list_id == self._mlist.list_id, or_(Member.role == MemberRole.moderator, - Member.role == MemberRole.owner), + Member.role == MemberRole.owner), Address.email == address, Member.address_id == Address.id) if results.count() == 0: diff --git a/src/mailman/model/tests/test_listmanager.py b/src/mailman/model/tests/test_listmanager.py index 3951e8250..b290138f3 100644 --- a/src/mailman/model/tests/test_listmanager.py +++ b/src/mailman/model/tests/test_listmanager.py @@ -29,11 +29,11 @@ __all__ = [ import unittest -from sqlalchemy.orm import sessionmaker from zope.component import getUtility from mailman.app.lifecycle import create_list from mailman.app.moderator import hold_message +from mailman.config import config from mailman.interfaces.listmanager import ( IListManager, ListCreatedEvent, ListCreatingEvent, ListDeletedEvent, ListDeletingEvent) @@ -148,9 +148,8 @@ Message-ID: <argon> for name in filter_names: setattr(self._ant, name, ['test-filter-1', 'test-filter-2']) getUtility(IListManager).delete(self._ant) - Session = sessionmaker() - store = Session.object_session(self._ant) - filters = store.query(ContentFilter).filter_by(mailing_list = self._ant) + filters = config.db.store.query(ContentFilter).filter_by( + mailing_list = self._ant) self.assertEqual(filters.count(), 0) diff --git a/src/mailman/model/tests/test_requests.py b/src/mailman/model/tests/test_requests.py index dc1b9b849..419c6077f 100644 --- a/src/mailman/model/tests/test_requests.py +++ b/src/mailman/model/tests/test_requests.py @@ -70,10 +70,10 @@ Something else. # Calling hold_request() with a bogus request type is an error. with self.assertRaises(TypeError) as cm: self._requests_db.hold_request(5, 'foo') - self.assertEqual(cm.exception.message, 5) + self.assertEqual(cm.exception.args[0], 5) def test_delete_missing_request(self): # Trying to delete a missing request is an error. with self.assertRaises(KeyError) as cm: self._requests_db.delete_request(801) - self.assertEqual(cm.exception.message, 801) + self.assertEqual(cm.exception.args[0], 801) diff --git a/src/mailman/model/uid.py b/src/mailman/model/uid.py index 77f1b59bb..29d8e7021 100644 --- a/src/mailman/model/uid.py +++ b/src/mailman/model/uid.py @@ -29,8 +29,8 @@ __all__ = [ from sqlalchemy import Column, Integer from mailman.database.model import Model -from mailman.database.types import UUID from mailman.database.transaction import dbconnection +from mailman.database.types import UUID @@ -54,6 +54,7 @@ class UID(Model): @dbconnection def __init__(self, store, uid): + super(UID, self).__init__() self.uid = uid store.add(self) diff --git a/src/mailman/model/user.py b/src/mailman/model/user.py index cd47a5dac..576015dbe 100644 --- a/src/mailman/model/user.py +++ b/src/mailman/model/user.py @@ -25,7 +25,7 @@ __all__ = [ ] from sqlalchemy import ( - Column, Unicode, Integer, DateTime, ForeignKey, LargeBinary) + Column, DateTime, ForeignKey, Integer, LargeBinary, Unicode) from sqlalchemy.orm import relationship, backref from zope.event import notify from zope.interface import implementer @@ -60,25 +60,24 @@ class User(Model): _user_id = Column(UUID) _created_on = Column(DateTime) - addresses = relationship('Address', - backref='user', - primaryjoin= - id==Address.user_id) + addresses = relationship( + 'Address', backref='user', + primaryjoin=(id==Address.user_id)) - _preferred_address_id = Column(Integer, ForeignKey('address.id', - use_alter=True, - name='_preferred_address')) - _preferred_address = relationship('Address', - primaryjoin= - _preferred_address_id==Address.id, - post_update=True) + _preferred_address_id = Column( + Integer, + ForeignKey('address.id', use_alter=True, name='_preferred_address')) + _preferred_address = relationship( + 'Address', primaryjoin=(_preferred_address_id==Address.id), + post_update=True) preferences_id = Column(Integer, ForeignKey('preferences.id')) - preferences = relationship('Preferences', - backref=backref('user', uselist=False)) + preferences = relationship( + 'Preferences', backref=backref('user', uselist=False)) @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 store.query(User).filter_by(_user_id=user_id).count() == 0, ( diff --git a/src/mailman/model/version.py b/src/mailman/model/version.py deleted file mode 100644 index 95cf03dac..000000000 --- a/src/mailman/model/version.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (C) 2007-2014 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -"""Model class for version numbers.""" - -from __future__ import absolute_import, print_function, unicode_literals - -__metaclass__ = type -__all__ = [ - 'Version', - ] - -from sqlalchemy import Column, Unicode, Integer - -from mailman.database.model import Model - - - -class Version(Model): - - __tablename__ = 'version' - - id = Column(Integer, primary_key=True) - component = Column(Unicode) - version = Column(Unicode) - - # The testing machinery will generally reset all tables, however because - # this table tracks schema migrations, we do not want to reset it. - PRESERVE = True - - def __init__(self, component, version): - self.component = component - self.version = version |
