diff options
| -rw-r--r-- | src/mailman/database/base.py | 99 | ||||
| -rw-r--r-- | src/mailman/database/factory.py | 6 | ||||
| -rw-r--r-- | src/mailman/database/model.py | 15 | ||||
| -rw-r--r-- | src/mailman/model/autorespond.py | 20 | ||||
| -rw-r--r-- | src/mailman/model/bans.py | 17 | ||||
| -rw-r--r-- | src/mailman/model/bounce.py | 2 | ||||
| -rw-r--r-- | src/mailman/model/listmanager.py | 4 | ||||
| -rw-r--r-- | src/mailman/model/mailinglist.py | 7 | ||||
| -rw-r--r-- | src/mailman/model/roster.py | 38 | ||||
| -rw-r--r-- | src/mailman/model/tests/test_listmanager.py | 8 | ||||
| -rw-r--r-- | src/mailman/model/user.py | 6 | ||||
| -rw-r--r-- | src/mailman/model/usermanager.py | 14 |
12 files changed, 121 insertions, 115 deletions
diff --git a/src/mailman/database/base.py b/src/mailman/database/base.py index a2392bb3a..0bc530e6b 100644 --- a/src/mailman/database/base.py +++ b/src/mailman/database/base.py @@ -68,6 +68,16 @@ class SABaseDatabase: def _prepare(self, url): pass + 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. @@ -90,11 +100,10 @@ class SABaseDatabase: log.debug('Database url: %s', url) self.url = url self._prepare(url) - engine = create_engine(url) - Session = sessionmaker(bind=engine) - store = Session() - self.store = store - store.commit() + self.engine = create_engine(url) + Session = sessionmaker(bind=self.engine) + self.store = Session() + self.store.commit() def load_migrations(self, until=None): """Load schema migrations. @@ -103,45 +112,47 @@ class SABaseDatabase: With default value of None, load all migrations. :type until: string """ - migrations_path = config.database.migrations_path - if '.' in migrations_path: - parent, dot, child = migrations_path.rpartition('.') - else: - parent = migrations_path - child = '' - # If the database does not yet exist, load the base schema. - filenames = sorted(resource_listdir(parent, child)) - # Find out which schema migrations have already been loaded. - if self._database_exists(self.store): - versions = set(version.version for version in - self.store.find(Version, component='schema')) - else: - versions = set() - for filename in filenames: - module_fn, extension = os.path.splitext(filename) - if extension != '.py': - continue - parts = module_fn.split('_') - if len(parts) < 2: - continue - version = parts[1].strip() - if len(version) == 0: - # Not a schema migration file. - continue - if version in versions: - log.debug('already migrated to %s', version) - continue - if until is not None and version > until: - # We're done. - break - module_path = migrations_path + '.' + module_fn - __import__(module_path) - upgrade = getattr(sys.modules[module_path], 'upgrade', None) - if upgrade is None: - continue - log.debug('migrating db to %s: %s', version, module_path) - upgrade(self, self.store, version, module_path) - self.commit() + from mailman.database.model import Model + Model.metadata.create_all(self.engine) + # migrations_path = config.database.migrations_path + # if '.' in migrations_path: + # parent, dot, child = migrations_path.rpartition('.') + # else: + # parent = migrations_path + # child = '' + # # If the database does not yet exist, load the base schema. + # filenames = sorted(resource_listdir(parent, child)) + # # Find out which schema migrations have already been loaded. + # if self._database_exists(self.store): + # versions = set(version.version for version in + # self.store.query(Version, component='schema')) + # else: + # versions = set() + # for filename in filenames: + # module_fn, extension = os.path.splitext(filename) + # if extension != '.py': + # continue + # parts = module_fn.split('_') + # if len(parts) < 2: + # continue + # version = parts[1].strip() + # if len(version) == 0: + # # Not a schema migration file. + # continue + # if version in versions: + # log.debug('already migrated to %s', version) + # continue + # if until is not None and version > until: + # # We're done. + # break + # module_path = migrations_path + '.' + module_fn + # __import__(module_path) + # upgrade = getattr(sys.modules[module_path], 'upgrade', None) + # if upgrade is None: + # continue + # log.debug('migrating db to %s: %s', version, module_path) + # upgrade(self, self.store, version, module_path) + # self.commit() def load_sql(self, store, sql): """Load the given SQL into the store. diff --git a/src/mailman/database/factory.py b/src/mailman/database/factory.py index 426d283e1..64fcc242c 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 @@ -62,10 +62,10 @@ class DatabaseFactory: def _reset(self): """See `IDatabase`.""" - from mailman.database.model import ModelMeta + from mailman.database.model import Model self.store.rollback() self._pre_reset(self.store) - ModelMeta._reset(self.store) + Model._reset(self) self._post_reset(self.store) self.store.commit() diff --git a/src/mailman/database/model.py b/src/mailman/database/model.py index 4b8478fc6..0cb60b7cd 100644 --- a/src/mailman/database/model.py +++ b/src/mailman/database/model.py @@ -50,13 +50,14 @@ class ModelMeta(object): ModelMeta._class_registry.add(self) @staticmethod - def _reset(store): - from mailman.config import config - config.db._pre_reset(store) + def _reset(db): + Model.metadata.drop_all(db.engine) + Model.metadata.create_all(db.engine) + # Make sure this is deterministic, by sorting on the storm table name. - classes = sorted(ModelMeta._class_registry, - key=attrgetter('__tablename__')) - for model_class in classes: - store.query(model_class).delete() + # classes = sorted(ModelMeta._class_registry, + # key=attrgetter('__tablename__')) + # for model_class in classes: + # store.query(model_class).delete() Model = declarative_base(cls=ModelMeta) diff --git a/src/mailman/model/autorespond.py b/src/mailman/model/autorespond.py index 92e0b6ebe..47f15cd54 100644 --- a/src/mailman/model/autorespond.py +++ b/src/mailman/model/autorespond.py @@ -75,12 +75,11 @@ class AutoResponseSet: @dbconnection def todays_count(self, store, address, response_type): """See `IAutoResponseSet`.""" - return store.find( - AutoResponseRecord, - And(AutoResponseRecord.address == address, - AutoResponseRecord.mailing_list == self._mailing_list, - AutoResponseRecord.response_type == response_type, - AutoResponseRecord.date_sent == today())).count() + return store.find(AutoResponseRecord).filter_by( + address = address, + mailing_list = self._mailing_list, + response_type = response_type, + date_sent = today()).count() @dbconnection def response_sent(self, store, address, response_type): @@ -92,10 +91,9 @@ class AutoResponseSet: @dbconnection def last_response(self, store, address, response_type): """See `IAutoResponseSet`.""" - results = store.find( - AutoResponseRecord, - And(AutoResponseRecord.address == address, - AutoResponseRecord.mailing_list == self._mailing_list, - AutoResponseRecord.response_type == response_type) + results = store.find(AutoResponseRecord).filter_by( + 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 57dbdbbd5..bf02f3127 100644 --- a/src/mailman/model/bans.py +++ b/src/mailman/model/bans.py @@ -64,7 +64,7 @@ class BanManager: @dbconnection def ban(self, store, email): """See `IBanManager`.""" - bans = store.find(Ban, email=email, list_id=self._list_id) + bans = store.query(Ban).filter_by(email=email, list_id=self._list_id) if bans.count() == 0: ban = Ban(email, self._list_id) store.add(ban) @@ -72,7 +72,8 @@ class BanManager: @dbconnection def unban(self, store, email): """See `IBanManager`.""" - ban = store.find(Ban, email=email, list_id=self._list_id).one() + ban = store.query(Ban).filter_by(email=email, + list_id=self._list_id).first() if ban is not None: store.remove(ban) @@ -83,32 +84,32 @@ class BanManager: if list_id is None: # The client is asking for global bans. Look up bans on the # specific email address first. - bans = store.find(Ban, email=email, list_id=None) + bans = store.query(Ban).filter_by(email=email, list_id=None) if bans.count() > 0: return True # And now look for global pattern bans. - bans = store.find(Ban, list_id=None) + bans = store.query(Ban).filter_by(list_id=None) for ban in bans: if (ban.email.startswith('^') and re.match(ban.email, email, re.IGNORECASE) is not None): return True else: # This is a list-specific ban. - bans = store.find(Ban, email=email, list_id=list_id) + bans = store.query(Ban).filter_by(email=email, list_id=list_id) if bans.count() > 0: return True # Try global bans next. - bans = store.find(Ban, email=email, list_id=None) + bans = store.query(Ban).filter_by(email=email, list_id=None) if bans.count() > 0: return True # Now try specific mailing list bans, but with a pattern. - bans = store.find(Ban, list_id=list_id) + bans = store.query(Ban).filteR_by(list_id=list_id) 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 = store.find(Ban, list_id=None) + bans = store.query(Ban).filter_by(list_id=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 b3f053cba..7340a4824 100644 --- a/src/mailman/model/bounce.py +++ b/src/mailman/model/bounce.py @@ -85,5 +85,5 @@ class BounceProcessor: @dbconnection def unprocessed(self, store): """See `IBounceProcessor`.""" - for event in store.find(BounceEvent, BounceEvent.processed == False): + for event in store.query(BounceEvent).filter_by(processed = False): yield event diff --git a/src/mailman/model/listmanager.py b/src/mailman/model/listmanager.py index df1a31d04..a67f7b5e1 100644 --- a/src/mailman/model/listmanager.py +++ b/src/mailman/model/listmanager.py @@ -66,12 +66,12 @@ class ListManager: """See `IListManager`.""" listname, at, hostname = fqdn_listname.partition('@') list_id = '{0}.{1}'.format(listname, hostname) - return store.query(MailingList).filter_by(_list_id=list_id).one() + return store.query(MailingList).filter_by(_list_id=list_id).first() @dbconnection def get_by_list_id(self, store, list_id): """See `IListManager`.""" - return store.query(MailingList).filter_by(_list_id=list_id).one() + return store.query(MailingList).filter_by(_list_id=list_id).first() @dbconnection def delete(self, store, mlist): diff --git a/src/mailman/model/mailinglist.py b/src/mailman/model/mailinglist.py index 324d709d6..abbf370e8 100644 --- a/src/mailman/model/mailinglist.py +++ b/src/mailman/model/mailinglist.py @@ -355,10 +355,9 @@ class MailingList(Model): """See `IMailingList`.""" # First, delete all existing MIME type filter patterns. store = Store.of(self) - results = store.find( - ContentFilter, - And(ContentFilter.mailing_list == self, - ContentFilter.filter_type == FilterType.filter_mime)) + results = store.query(ContentFilter).filter( + ContentFilter.mailing_list == self, + ContentFilter.filter_type == FilterType.filter_mime) results.remove() # Now add all the new filter types. for mime_type in sequence: diff --git a/src/mailman/model/roster.py b/src/mailman/model/roster.py index f641c2846..c8bfdc582 100644 --- a/src/mailman/model/roster.py +++ b/src/mailman/model/roster.py @@ -38,6 +38,7 @@ __all__ = [ #from storm.expr import And, Or +from sqlalchemy import and_, or_ from zope.interface import implementer from mailman.database.transaction import dbconnection @@ -65,8 +66,7 @@ class AbstractRoster: @dbconnection def _query(self, store): - return store.find( - Member, + return store.query(Member).filter( Member.list_id == self._mlist.list_id, Member.role == self.role) @@ -104,8 +104,7 @@ class AbstractRoster: @dbconnection def get_member(self, store, address): """See `IRoster`.""" - results = store.find( - Member, + results = store.query(Member).filter( Member.list_id == self._mlist.list_id, Member.role == self.role, Address.email == address, @@ -160,19 +159,17 @@ class AdministratorRoster(AbstractRoster): @dbconnection def _query(self, store): - return store.find( - Member, + return store.query(Member).filter( Member.list_id == self._mlist.list_id, - Or(Member.role == MemberRole.owner, + or_(Member.role == MemberRole.owner, Member.role == MemberRole.moderator)) @dbconnection def get_member(self, store, address): """See `IRoster`.""" - results = store.find( - Member, + results = store.query(Member).filter( Member.list_id == self._mlist.list_id, - Or(Member.role == MemberRole.moderator, + or_(Member.role == MemberRole.moderator, Member.role == MemberRole.owner), Address.email == address, Member.address_id == Address.id) @@ -206,10 +203,9 @@ class DeliveryMemberRoster(AbstractRoster): :return: A generator of members. :rtype: generator """ - results = store.find( - Member, - And(Member.list_id == self._mlist.list_id, - Member.role == MemberRole.member)) + results = store.query(Member).filter( + list_id == self._mlist.list_id, + role == MemberRole.member) for member in results: if member.delivery_mode in delivery_modes: yield member @@ -250,7 +246,7 @@ class Subscribers(AbstractRoster): @dbconnection def _query(self, store): - return store.find(Member, Member.list_id == self._mlist.list_id) + return store.query(Member).filter_by(list_id = self._mlist.list_id) @@ -265,11 +261,10 @@ class Memberships: @dbconnection def _query(self, store): - results = store.find( - Member, - Or(Member.user_id == self._user.id, - And(Address.user_id == self._user.id, - Member.address_id == Address.id))) + results = store.query(Member).filter( + or_(Member.user_id == self._user.id, + and_(Member.user_id == self._user.id, + Member.address_id == Address.id))) return results.config(distinct=True) @property @@ -297,8 +292,7 @@ class Memberships: @dbconnection def get_member(self, store, address): """See `IRoster`.""" - results = store.find( - Member, + results = store.query(Member).filter( Member.address_id == Address.id, Address.user_id == self._user.id) if results.count() == 0: diff --git a/src/mailman/model/tests/test_listmanager.py b/src/mailman/model/tests/test_listmanager.py index 2d3a4e3dc..287a4dba5 100644 --- a/src/mailman/model/tests/test_listmanager.py +++ b/src/mailman/model/tests/test_listmanager.py @@ -29,7 +29,7 @@ __all__ = [ import unittest -from storm.locals import Store +from sqlalchemy.orm import sessionmaker from zope.component import getUtility from mailman.app.lifecycle import create_list @@ -139,9 +139,9 @@ Message-ID: <argon> for name in filter_names: setattr(self._ant, name, ['test-filter-1', 'test-filter-2']) getUtility(IListManager).delete(self._ant) - store = Store.of(self._ant) - filters = store.find(ContentFilter, - ContentFilter.mailing_list == self._ant) + Session = sessionmaker() + store = Session.object_session(self._ant) + filters = store.query(ContentFilter).filter_by(mailing_list = self._ant) self.assertEqual(filters.count(), 0) diff --git a/src/mailman/model/user.py b/src/mailman/model/user.py index 88bf62085..efe00c6aa 100644 --- a/src/mailman/model/user.py +++ b/src/mailman/model/user.py @@ -59,11 +59,13 @@ class User(Model): _user_id = Column(UUID) _created_on = Column(DateTime) - addresses = relationship('Address', + 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', + use_alter=True, + name='prefered_address_id')) _preferred_address = relationship('Address', foreign_keys=[_preferred_address_id]) diff --git a/src/mailman/model/usermanager.py b/src/mailman/model/usermanager.py index 6f4a7ff5c..a5ee40ae8 100644 --- a/src/mailman/model/usermanager.py +++ b/src/mailman/model/usermanager.py @@ -57,7 +57,7 @@ class UserManager: @dbconnection def get_user(self, store, email): """See `IUserManager`.""" - addresses = store.find(Address, email=email.lower()) + addresses = store.query(Address).filter_by(email=email.lower()) if addresses.count() == 0: return None return addresses.one().user @@ -65,7 +65,7 @@ class UserManager: @dbconnection def get_user_by_id(self, store, user_id): """See `IUserManager`.""" - users = store.find(User, _user_id=user_id) + users = store.query(User).filter_by(_user_id=user_id) if users.count() == 0: return None return users.one() @@ -74,13 +74,13 @@ class UserManager: @dbconnection def users(self, store): """See `IUserManager`.""" - for user in store.find(User): + for user in store.query(User).all(): yield user @dbconnection def create_address(self, store, email, display_name=None): """See `IUserManager`.""" - addresses = store.find(Address, email=email.lower()) + addresses = store.query(Address).filter_by(email=email.lower()) if addresses.count() == 1: found = addresses[0] raise ExistingAddressError(found.original_email) @@ -106,7 +106,7 @@ class UserManager: @dbconnection def get_address(self, store, email): """See `IUserManager`.""" - addresses = store.find(Address, email=email.lower()) + addresses = store.query(Address).filter_by(email=email.lower()) if addresses.count() == 0: return None return addresses.one() @@ -115,12 +115,12 @@ class UserManager: @dbconnection def addresses(self, store): """See `IUserManager`.""" - for address in store.find(Address): + for address in store.query(Address).all(): yield address @property @dbconnection def members(self, store): """See `IUserManager.""" - for member in store.find(Member): + for member in store.query(Member).all(): yield member |
