diff options
Diffstat (limited to 'src')
25 files changed, 84 insertions, 159 deletions
diff --git a/src/mailman/app/subscriptions.py b/src/mailman/app/subscriptions.py index b2560beb5..d24a9a545 100644 --- a/src/mailman/app/subscriptions.py +++ b/src/mailman/app/subscriptions.py @@ -28,7 +28,7 @@ __all__ = [ from operator import attrgetter from passlib.utils import generate_password as generate -from storm.expr import And, Or +#from storm.expr import And, Or from uuid import UUID from zope.component import getUtility from zope.interface import implementer diff --git a/src/mailman/database/base.py b/src/mailman/database/base.py index 1577c981d..a2392bb3a 100644 --- a/src/mailman/database/base.py +++ b/src/mailman/database/base.py @@ -31,8 +31,6 @@ from lazr.config import as_boolean from pkg_resources import resource_listdir, resource_string from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker -from storm.cache import GenerationalCache -from storm.locals import create_database, Store from zope.interface import implementer from mailman.config import config @@ -54,7 +52,7 @@ class SABaseDatabase: """ TAG='' - def __inti__(self): + def __init__(self): self.url = None self.store = None @@ -70,56 +68,6 @@ class SABaseDatabase: def _prepare(self, url): pass - def initialize(Self, debug=None): - url = expand(config.database.url, config.paths) - log.debug('Database url: %s', url) - self.url = url - self._prepare(url) - engine = create_engine(url) - Session = sessionmaker(bind=engine) - store = Session() - self.store = session() - store.commit() - - -@implementer(IDatabase) -class StormBaseDatabase: - """The database base class for use with the Storm ORM. - - Use this as a base class for your DB-specific derived classes. - """ - - # Tag used to distinguish the database being used. Override this in base - # classes. - TAG = '' - - def __init__(self): - self.url = None - self.store = None - - def begin(self): - """See `IDatabase`.""" - # Storm takes care of this for us. - pass - - def commit(self): - """See `IDatabase`.""" - self.store.commit() - - def abort(self): - """See `IDatabase`.""" - self.store.rollback() - - def _database_exists(self): - """Return True if the database exists and is initialized. - - Return False when Mailman needs to create and initialize the - underlying database schema. - - Base classes *must* override this. - """ - raise NotImplementedError - def _pre_reset(self, store): """Clean up method for testing. @@ -137,41 +85,14 @@ class StormBaseDatabase: database-specific post-removal cleanup. """ pass - - def _prepare(self, url): - """Prepare the database for creation. - - Some database backends need to do so me prep work before letting Storm - create the database. For example, we have to touch the SQLite .db - file first so that it has the proper file modes. - """ - pass - def initialize(self, debug=None): - """See `IDatabase`.""" - # Calculate the engine url. url = expand(config.database.url, config.paths) log.debug('Database url: %s', url) - # XXX By design of SQLite, database file creation does not honor - # umask. See their ticket #1193: - # http://www.sqlite.org/cvstrac/tktview?tn=1193,31 - # - # This sucks for us because the mailman.db file /must/ be group - # writable, however even though we guarantee our umask is 002 here, it - # still gets created without the necessary g+w permission, due to - # SQLite's policy. This should only affect SQLite engines because its - # the only one that creates a little file on the local file system. - # This kludges around their bug by "touch"ing the database file before - # SQLite has any chance to create it, thus honoring the umask and - # ensuring the right permissions. We only try to do this for SQLite - # engines, and yes, we could have chmod'd the file after the fact, but - # half dozen and all... self.url = url self._prepare(url) - database = create_database(url) - store = Store(database, GenerationalCache()) - database.DEBUG = (as_boolean(config.database.debug) - if debug is None else debug) + engine = create_engine(url) + Session = sessionmaker(bind=engine) + store = Session() self.store = store store.commit() @@ -262,6 +183,8 @@ class StormBaseDatabase: # Add a marker that indicates the migration version being applied. store.add(Version(component='schema', version=version)) + + @staticmethod def _make_temporary(): raise NotImplementedError diff --git a/src/mailman/database/factory.py b/src/mailman/database/factory.py index db453ea41..426d283e1 100644 --- a/src/mailman/database/factory.py +++ b/src/mailman/database/factory.py @@ -54,7 +54,7 @@ class DatabaseFactory: database = call_name(database_class) verifyObject(IDatabase, database) database.initialize() - database.load_migrations() + #database.load_migrations() database.commit() return database diff --git a/src/mailman/database/model.py b/src/mailman/database/model.py index 5fbf4005d..4b8478fc6 100644 --- a/src/mailman/database/model.py +++ b/src/mailman/database/model.py @@ -24,26 +24,21 @@ __all__ = [ 'Model', ] - from operator import attrgetter from sqlalchemy.ext.declarative import declarative_base -from storm.properties import PropertyPublisherMeta - -Base = declerative_base() - -class ModelMeta(PropertyPublisherMeta): +class ModelMeta(object): """Do more magic on table classes.""" _class_registry = set() def __init__(self, name, bases, dict): - # Before we let the base class do it's thing, force an __storm_table__ + # Before we let the base class do it's thing, force an __tablename__ # property to enforce our table naming convention. - self.__storm_table__ = name.lower() - super(ModelMeta, self).__init__(name, bases, dict) + self.__tablename__ = name.lower() + # super(ModelMeta, self).__init__(name, bases, dict) # Register the model class so that it can be more easily cleared. # This is required by the test framework so that the corresponding # table can be reset between tests. @@ -60,12 +55,8 @@ class ModelMeta(PropertyPublisherMeta): config.db._pre_reset(store) # Make sure this is deterministic, by sorting on the storm table name. classes = sorted(ModelMeta._class_registry, - key=attrgetter('__storm_table__')) + key=attrgetter('__tablename__')) for model_class in classes: - store.find(model_class).remove() - + store.query(model_class).delete() - -class Model: - """Like Storm's `Storm` subclass, but with a bit extra.""" - __metaclass__ = Base +Model = declarative_base(cls=ModelMeta) diff --git a/src/mailman/database/postgresql.py b/src/mailman/database/postgresql.py index 48c68a937..1ee454074 100644 --- a/src/mailman/database/postgresql.py +++ b/src/mailman/database/postgresql.py @@ -32,12 +32,12 @@ from functools import partial from operator import attrgetter from urlparse import urlsplit, urlunsplit -from mailman.database.base import StormBaseDatabase +from mailman.database.base import SABaseDatabase from mailman.testing.helpers import configuration -class PostgreSQLDatabase(StormBaseDatabase): +class PostgreSQLDatabase(SABaseDatabase): """Database class for PostgreSQL.""" TAG = 'postgres' diff --git a/src/mailman/database/sqlite.py b/src/mailman/database/sqlite.py index 15629615f..ec404b9c3 100644 --- a/src/mailman/database/sqlite.py +++ b/src/mailman/database/sqlite.py @@ -34,12 +34,12 @@ import tempfile from functools import partial from urlparse import urlparse -from mailman.database.base import StormBaseDatabase +from mailman.database.base import SABaseDatabase from mailman.testing.helpers import configuration -class SQLiteDatabase(StormBaseDatabase): +class SQLiteDatabase(SABaseDatabase): """Database class for SQLite.""" TAG = 'sqlite' diff --git a/src/mailman/database/types.py b/src/mailman/database/types.py index 5ffbf3965..045065591 100644 --- a/src/mailman/database/types.py +++ b/src/mailman/database/types.py @@ -23,13 +23,14 @@ from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'Enum', - 'UUID' + 'UUID', ] import uuid +from sqlalchemy import Integer from sqlalchemy.types import TypeDecorator, BINARY, CHAR -from sqlalchemy.dailects import postgresql +from sqlalchemy.dialects import postgresql diff --git a/src/mailman/interfaces/database.py b/src/mailman/interfaces/database.py index 21f2f71d0..d8fde2b93 100644 --- a/src/mailman/interfaces/database.py +++ b/src/mailman/interfaces/database.py @@ -61,7 +61,7 @@ class IDatabase(Interface): """Abort the current transaction.""" store = Attribute( - """The underlying Storm store on which you can do queries.""") + """The underlying SQLAlchemy store on which you can do queries.""") diff --git a/src/mailman/model/address.py b/src/mailman/model/address.py index 88e28b919..59d54aab0 100644 --- a/src/mailman/model/address.py +++ b/src/mailman/model/address.py @@ -27,7 +27,7 @@ __all__ = [ from email.utils import formataddr from sqlalchemy import (Column, Integer, String, Unicode, - ForeignKey, Datetime) + ForeignKey, DateTime) from sqlalchemy.orm import relationship, backref from zope.component import getUtility from zope.event import notify @@ -50,10 +50,11 @@ class Address(Model): email = Column(Unicode) _original = Column(Unicode) display_name = Column(Unicode) - _verified_on = Column('verified_on', Datetime) + _verified_on = Column('verified_on', DateTime) registered_on = Column(DateTime) user_id = Column(Integer, ForeignKey('user.id')) + preferences_id = Column(Integer, ForeignKey('preferences.id')) prefereces = relationship('Preferences', backref=backref('Address', uselist=False)) diff --git a/src/mailman/model/autorespond.py b/src/mailman/model/autorespond.py index 4e1f42cca..92e0b6ebe 100644 --- a/src/mailman/model/autorespond.py +++ b/src/mailman/model/autorespond.py @@ -28,7 +28,7 @@ __all__ = [ from sqlalchemy import (Column, Integer, String, Unicode, ForeignKey, Date) -from storm.locals import And, Date, Desc, Int, Reference +from sqlalchemy.orm import relationship from zope.interface import implementer from mailman.database.model import Model diff --git a/src/mailman/model/bounce.py b/src/mailman/model/bounce.py index a40178837..b3f053cba 100644 --- a/src/mailman/model/bounce.py +++ b/src/mailman/model/bounce.py @@ -45,7 +45,7 @@ class BounceEvent(Model): __tablename__ = 'bounceevent' - id = Unicode(Integer, primary_key=True) + id = Column(Integer, primary_key=True) list_id = Column(Unicode) email = Column(Unicode) timestamp = Column(DateTime) diff --git a/src/mailman/model/digests.py b/src/mailman/model/digests.py index 0794bfb4f..e94bb073e 100644 --- a/src/mailman/model/digests.py +++ b/src/mailman/model/digests.py @@ -47,7 +47,7 @@ class OneLastDigest(Model): mailing_list_id = Column(Integer, ForeignKey('mailinglist.id')) maling_list = relationship('MailingList') - address_id = Columne(Integer, ForeignKey('address.id')) + address_id = Column(Integer, ForeignKey('address.id')) address = relationship('Address') delivery_mode = Column(Enum(enum=DeliveryMode)) diff --git a/src/mailman/model/domain.py b/src/mailman/model/domain.py index 2a5391abc..860107b15 100644 --- a/src/mailman/model/domain.py +++ b/src/mailman/model/domain.py @@ -142,14 +142,14 @@ class DomainManager: def remove(self, store, mail_host): domain = self[mail_host] notify(DomainDeletingEvent(domain)) - store.remove(domain) + store.delete(domain) notify(DomainDeletedEvent(mail_host)) return domain @dbconnection def get(self, store, mail_host, default=None): """See `IDomainManager`.""" - domains = store.find(Domain, mail_host=mail_host) + domains = store.query(Domain).filter_by(mail_host=mail_host) if domains.count() < 1: return default assert domains.count() == 1, ( @@ -166,15 +166,15 @@ class DomainManager: @dbconnection def __len__(self, store): - return store.find(Domain).count() + return store.query(Domain).count() @dbconnection def __iter__(self, store): """See `IDomainManager`.""" - for domain in store.find(Domain): + for domain in store.query(Domain).all(): yield domain @dbconnection def __contains__(self, store, mail_host): """See `IDomainManager`.""" - return store.find(Domain, mail_host=mail_host).count() > 0 + return store.query(Domain).filter_by(mail_host=mail_host).count() > 0 diff --git a/src/mailman/model/listmanager.py b/src/mailman/model/listmanager.py index d648a5bde..df1a31d04 100644 --- a/src/mailman/model/listmanager.py +++ b/src/mailman/model/listmanager.py @@ -52,9 +52,7 @@ class ListManager: raise InvalidEmailAddressError(fqdn_listname) list_id = '{0}.{1}'.format(listname, hostname) notify(ListCreatingEvent(fqdn_listname)) - mlist = store.find( - MailingList, - MailingList._list_id == list_id).one() + mlist = store.query(MailingList).filter_by(_list_id=list_id).first() if mlist: raise ListAlreadyExistsError(fqdn_listname) mlist = MailingList(fqdn_listname) @@ -68,40 +66,40 @@ class ListManager: """See `IListManager`.""" listname, at, hostname = fqdn_listname.partition('@') list_id = '{0}.{1}'.format(listname, hostname) - return store.find(MailingList, MailingList._list_id == list_id).one() + return store.query(MailingList).filter_by(_list_id=list_id).one() @dbconnection def get_by_list_id(self, store, list_id): """See `IListManager`.""" - return store.find(MailingList, MailingList._list_id == list_id).one() + return store.query(MailingList).filter_by(_list_id=list_id).one() @dbconnection def delete(self, store, mlist): """See `IListManager`.""" fqdn_listname = mlist.fqdn_listname notify(ListDeletingEvent(mlist)) - store.find(ContentFilter, ContentFilter.mailing_list == mlist).remove() - store.remove(mlist) + store.query(ContentFilter).filter_by(mailing_list=mlist).delete() + store.delete(mlist) notify(ListDeletedEvent(fqdn_listname)) @property @dbconnection def mailing_lists(self, store): """See `IListManager`.""" - for mlist in store.find(MailingList): + for mlist in store.query(MailingList).all(): yield mlist @dbconnection def __iter__(self, store): """See `IListManager`.""" - for mlist in store.find(MailingList): + for mlist in store.query(MailingList).all(): yield mlist @property @dbconnection def names(self, store): """See `IListManager`.""" - result_set = store.find(MailingList) + result_set = store.query(MailingList).all() for mail_host, list_name in result_set.values(MailingList.mail_host, MailingList.list_name): yield '{0}@{1}'.format(list_name, mail_host) @@ -110,7 +108,7 @@ class ListManager: @dbconnection def list_ids(self, store): """See `IListManager`.""" - result_set = store.find(MailingList) + result_set = store.query(MailingList).all() for list_id in result_set.values(MailingList._list_id): yield list_id @@ -118,7 +116,7 @@ class ListManager: @dbconnection def name_components(self, store): """See `IListManager`.""" - result_set = store.find(MailingList) + result_set = store.query(MailingList).all() 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/mailinglist.py b/src/mailman/model/mailinglist.py index ff757aa98..324d709d6 100644 --- a/src/mailman/model/mailinglist.py +++ b/src/mailman/model/mailinglist.py @@ -27,8 +27,9 @@ __all__ = [ import os -from sqlalchemy import ( Boolean, DateTime, Float, Integer, Unicode - PickleType, Interval) +from sqlalchemy import (Column, Boolean, DateTime, Float, Integer, Unicode, + PickleType, Interval, ForeignKey) +from sqlalchemy.orm import relationship from urlparse import urljoin from zope.component import getUtility from zope.event import notify @@ -66,7 +67,6 @@ from mailman.utilities.string import expand SPACE = ' ' UNDERSCORE = '_' - @implementer(IMailingList) class MailingList(Model): @@ -114,7 +114,7 @@ class MailingList(Model): autoresponse_owner_text = Column(Unicode) autorespond_postings = Column(Enum(enum=ResponseAction)) autoresponse_postings_text = Column(Unicode) - autorespond_requests = Column(Enum(Enum=ResponseAction)) + autorespond_requests = Column(Enum(enum=ResponseAction)) autoresponse_request_text = Column(Unicode) # Content filters. filter_action = Column(Enum(enum=FilterAction)) @@ -495,10 +495,13 @@ class MailingList(Model): class AcceptableAlias(Model): """See `IAcceptableAlias`.""" - id = Int(primary=True) + __tablename__ = 'acceptablealias' + + id = Column(Integer, primary_key=True) mailing_list_id = Column(Integer) - mailing_list = Reference(mailing_list_id, MailingList.id) + mailing_list = relationship('MailingList') + #mailing_list = Reference(mailing_list_id, MailingList.id) alias = Column(Unicode) @@ -547,10 +550,12 @@ class AcceptableAliasSet: class ListArchiver(Model): """See `IListArchiver`.""" - id = Int(primary=True) + __tablename__ = 'listarchiver' - mailing_list_id = Column(Integer) - mailing_list = Reference(mailing_list_id, MailingList.id) + id = Column(Integer, primary_key=True) + + mailing_list_id = Column(Integer, ForeignKey('mailinglist.id')) + mailing_list = relationship('MailingList') name = Column(Unicode) _is_enabled = Column(Boolean) diff --git a/src/mailman/model/member.py b/src/mailman/model/member.py index f7da6b012..739e35484 100644 --- a/src/mailman/model/member.py +++ b/src/mailman/model/member.py @@ -54,14 +54,14 @@ class Member(Model): __tablename__ = 'member' id = Column(Integer, primary_key=True) - _member_id = UUID() + _member_id = Column(UUID) role = Column(Enum(enum=MemberRole)) list_id = Column(Unicode) moderation_action = Column(Enum(enum=Action)) - address_id = Column(Integer, ForegignKey('address.id')) + address_id = Column(Integer, ForeignKey('address.id')) preferences_id = Column(Integer, ForeignKey('preferences.id')) - user_id = Column(Integer, ForiegnKey('user.id')) + user_id = Column(Integer, ForeignKey('user.id')) def __init__(self, role, list_id, subscriber): self._member_id = uid_factory.new_uid() diff --git a/src/mailman/model/message.py b/src/mailman/model/message.py index 64ee2c84a..9d7623d09 100644 --- a/src/mailman/model/message.py +++ b/src/mailman/model/message.py @@ -39,7 +39,7 @@ class Message(Model): __tablename__ = 'message' - id = Column(Integer, primary_key=True, default=AutoReload)) + id = Column(Integer, primary_key=True) message_id = Column(Unicode) message_id_hash = Column(Unicode) path = Column(Unicode) # TODO : was RawStr() diff --git a/src/mailman/model/messagestore.py b/src/mailman/model/messagestore.py index a4950e8c9..69860a6a1 100644 --- a/src/mailman/model/messagestore.py +++ b/src/mailman/model/messagestore.py @@ -128,14 +128,14 @@ class MessageStore: @property @dbconnection def messages(self, store): - for row in store.find(Message): + for row in store.query(Message).all(): yield self._get_message(row) @dbconnection def delete_message(self, store, message_id): - row = store.find(Message, message_id=message_id).one() + row = store.query(Message).filter_by(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) - store.remove(row) + store.delete(row) diff --git a/src/mailman/model/mime.py b/src/mailman/model/mime.py index 3fa051f10..3eac4f07b 100644 --- a/src/mailman/model/mime.py +++ b/src/mailman/model/mime.py @@ -39,11 +39,11 @@ from mailman.interfaces.mime import IContentFilter, FilterType class ContentFilter(Model): """A single filter criteria.""" - __tablename__ == 'contentfilter' + __tablename__ = 'contentfilter' id = Column(Integer, primary_key=True) - mailing_list_id = Column(Integer, ForiegnKey('mailinglist.id')) + mailing_list_id = Column(Integer, ForeignKey('mailinglist.id')) mailing_list = relationship('MailingList') filter_type = Column(Enum(enum=FilterType)) diff --git a/src/mailman/model/pending.py b/src/mailman/model/pending.py index cc203d270..0c41a4ac6 100644 --- a/src/mailman/model/pending.py +++ b/src/mailman/model/pending.py @@ -50,6 +50,8 @@ from mailman.utilities.modules import call_name class PendedKeyValue(Model): """A pended key/value pair, tied to a token.""" + __tablename__ = 'pendedkeyvalue' + def __init__(self, key, value): self.key = key self.value = value @@ -57,7 +59,7 @@ class PendedKeyValue(Model): id = Column(Integer, primary_key=True) key = Column(Unicode) value = Column(Unicode) - pended_id = Column(Integer) + pended_id = Column(Integer, ForeignKey('pended.id')) @@ -65,15 +67,17 @@ class PendedKeyValue(Model): class Pended(Model): """A pended event, tied to a token.""" + __tablename__ = 'pended' + def __init__(self, token, expiration_date): super(Pended, self).__init__() self.token = token self.expiration_date = expiration_date - id = Column(Integer. primary_key=True) + id = Column(Integer, primary_key=True) token = Column(Unicode) # TODO : was RawStr() expiration_date = Column(DateTime) - key_values = relationship('PendedKeyValues') + key_values = relationship('PendedKeyValue') @implementer(IPendable) diff --git a/src/mailman/model/preferences.py b/src/mailman/model/preferences.py index 73bb080a9..d74b17e30 100644 --- a/src/mailman/model/preferences.py +++ b/src/mailman/model/preferences.py @@ -41,7 +41,7 @@ from mailman.interfaces.preferences import IPreferences class Preferences(Model): """See `IPreferences`.""" - __tablename__ == 'preferences' + __tablename__ = 'preferences' id = Column(Integer, primary_key=True) acknowledge_posts = Column(Boolean) diff --git a/src/mailman/model/requests.py b/src/mailman/model/requests.py index 457341557..850ba6b3b 100644 --- a/src/mailman/model/requests.py +++ b/src/mailman/model/requests.py @@ -143,7 +143,7 @@ class ListRequests: class _Request(Model): """Table for mailing list hold requests.""" - __tablename__ == 'request' + __tablename__ = 'request' id = Column(Integer, primary_key=True)# TODO: ???, default=AutoReload) key = Column(Unicode) diff --git a/src/mailman/model/roster.py b/src/mailman/model/roster.py index 5a6a13269..f641c2846 100644 --- a/src/mailman/model/roster.py +++ b/src/mailman/model/roster.py @@ -37,7 +37,7 @@ __all__ = [ ] -from storm.expr import And, Or +#from storm.expr import And, Or from zope.interface import implementer from mailman.database.transaction import dbconnection diff --git a/src/mailman/model/user.py b/src/mailman/model/user.py index 16e87bbfb..88bf62085 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 -from sqlalchemy import relationship, backref +from sqlalchemy.orm import relationship, backref from zope.event import notify from zope.interface import implementer @@ -59,11 +59,13 @@ class User(Model): _user_id = Column(UUID) _created_on = Column(DateTime) - addresses = relationship('Address', backref='user') + addresses = relationship('Address', + backref='user', + foreign_keys='[Address.user_id]') - _preferred_address_id = Column(Integer, ForeignKey='address.id') + _preferred_address_id = Column(Integer, ForeignKey('address.id')) _preferred_address = relationship('Address', - backred=backref('user', uselist=False)) + foreign_keys=[_preferred_address_id]) preferences_id = Column(Integer, ForeignKey('preferences.id')) preferences = relationship('Preferences', diff --git a/src/mailman/model/version.py b/src/mailman/model/version.py index 9824e54d4..8dc0d4e6c 100644 --- a/src/mailman/model/version.py +++ b/src/mailman/model/version.py @@ -32,7 +32,7 @@ from mailman.database.model import Model class Version(Model): - __tablename_ = 'version' + __tablename__ = 'version' id = Column(Integer, primary_key=True) component = Column(Unicode) |
