From 90c303842bab1448b507c83eefbf117d5ac605e6 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 18 Feb 2015 15:46:39 +0100 Subject: [PATCH] Load postfix maps files from extensions. fix #686 --- modoboa/core/commands/postfix_maps.py | 190 +++++++------------------- 1 file changed, 53 insertions(+), 137 deletions(-) diff --git a/modoboa/core/commands/postfix_maps.py b/modoboa/core/commands/postfix_maps.py index 81a5f3fa5..f10c6e111 100644 --- a/modoboa/core/commands/postfix_maps.py +++ b/modoboa/core/commands/postfix_maps.py @@ -4,25 +4,45 @@ import datetime import getpass -import inspect import os import sys from django.template import Context, Template +import dj_database_url + from . import Command - -class MapFilesGenerator(object): - - def __init__(self, dbinfo=None): - """Constructor.""" - self.template = Template("""user = {{ dbuser }} +MAP_FILE_TEMPLATE = """user = {{ dbuser }} password = {{ dbpass }} dbname = {{ dbname }} hosts = {{ dbhost }} query = {{ query|safe }} -""") +""" + + +class MapFilesRegistry(object): + + """A registry of all map files.""" + + def __init__(self): + self.files = [] + + def add_files(self, files): + """Add map files to registry.""" + self.files += files + + +registry = MapFilesRegistry() + + +class MapFilesGenerator(object): + + """Map files generator.""" + + def __init__(self, dbinfo=None): + """Constructor.""" + self.template = Template(MAP_FILE_TEMPLATE) if dbinfo is None: self.tpl_context = { 'dbhost': raw_input('Database host: '), @@ -61,21 +81,16 @@ query = {{ query|safe }} ' '.join(sys.argv[1:])) print >> fp, content - def __render_std_maps(self, args): - """Render standard map files. - - (ie. the ones belonging to the 'std' category) - - :param args: command line arguments - """ - for v in globals().values(): - if not inspect.isclass(v) or not issubclass(v, MapFile): - continue - if v is MapFile: - continue - if v.category not in args.categories: - continue - self.__render_map(args, v) + def __load_extensions(self, extensions): + """Load specified extensions.""" + if "all" in extensions: + # Retrieve extension list from the API + return + for extension in extensions: + try: + __import__(extension, locals(), globals(), ["postfix_maps"]) + except ImportError: + sys.stderr.write("Unknown extension {0}".format(extension)) def render(self, args): """Render all map files. @@ -86,11 +101,16 @@ query = {{ query|safe }} os.mkdir(args.destdir) except OSError: pass - self.__render_std_maps(args) + if args.extensions: + self.__load_extensions(args.extensions) + for mapfile in registry.files: + self.__render_map(args, mapfile) class SQLiteMapFilesGenerator(MapFilesGenerator): + """SQLite special generator.""" + def __init__(self, dbinfo=None): self.template = Template("""dbpath = {{ dbpath }} query = {{ query|safe }} @@ -105,111 +125,6 @@ query = {{ query|safe }} } -class MapFile(object): - category = 'std' - - -class DomainsMap(MapFile): - filename = 'sql-domains.cf' - mysql = "SELECT name FROM admin_domain WHERE name='%s' AND enabled=1" - postgres = "SELECT name FROM admin_domain WHERE name='%s' AND enabled" - sqlite = "SELECT name FROM admin_domain WHERE name='%s' AND enabled=1" - - -class DomainsAliasesMap(MapFile): - filename = 'sql-domain-aliases.cf' - mysql = "SELECT dom.name FROM admin_domain dom INNER JOIN admin_domainalias domal ON dom.id=domal.target_id WHERE domal.name='%s' AND domal.enabled=1 AND dom.enabled=1" - postgres = "SELECT dom.name FROM admin_domain dom INNER JOIN admin_domainalias domal ON dom.id=domal.target_id WHERE domal.name='%s' AND domal.enabled AND dom.enabled" - sqlite = "SELECT dom.name FROM admin_domain dom INNER JOIN admin_domainalias domal ON dom.id=domal.target_id WHERE domal.name='%s' AND domal.enabled=1 AND dom.enabled=1" - - -class AliasesMap(MapFile): - filename = 'sql-aliases.cf' - mysql = "(SELECT concat(mb.address, '@', dom.name) FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias_mboxes al_mb INNER JOIN admin_alias al ON al_mb.alias_id=al.id INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled=1 AND al.address='%u' AND al.enabled=1)) UNION (SELECT concat(al.address, '@', dom.name) FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.id IN (SELECT al_al.to_alias_id FROM admin_alias_aliases al_al INNER JOIN admin_alias al ON al_al.from_alias_id=al.id INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled=1 AND al.address='%u' AND al.enabled=1)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled=1 AND al.address='%u' AND al.enabled=1 AND al.extmboxes<>'')" - postgres = "(SELECT mb.address || '@' || dom.name FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias_mboxes al_mb INNER JOIN admin_alias al ON al_mb.alias_id=al.id INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled AND al.address='%u' AND al.enabled)) UNION (SELECT al.address || '@' || dom.name FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.id IN (SELECT al_al.to_alias_id FROM admin_alias_aliases al_al INNER JOIN admin_alias al ON al_al.from_alias_id=al.id INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled AND al.address='%u' AND al.enabled)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled AND al.address='%u' AND al.enabled AND al.extmboxes<>'')" - sqlite = "(SELECT (mb.address || '@' || dom.name) FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias_mboxes al_mb INNER JOIN admin_alias al ON al_mb.alias_id=al.id INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled=1 AND al.address='%u' AND al.enabled=1)) UNION (SELECT (al.address || '@' || dom.name) FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.id IN (SELECT al_al.to_alias_id FROM admin_alias_aliases al_al INNER JOIN admin_alias al ON al_al.from_alias_id=al.id INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled=1 AND al.address='%u' AND al.enabled=1)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled=1 AND al.address='%u' AND al.enabled=1 AND al.extmboxes<>'')" - - -class DomainAliasesMailboxesMap(MapFile): - filename = 'sql-domain-aliases-mailboxes.cf' - mysql = "(SELECT concat(mb.address, '@', dom.name) FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_mailbox mb ON mb.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled=1 AND mb.address='%u') UNION (SELECT concat(al.address, '@', dom.name) FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_alias al ON al.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled=1 AND al.address='%u')" - postgres = "(SELECT mb.address || '@' || dom.name FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_mailbox mb ON mb.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled AND mb.address='%u') UNION (SELECT al.address || '@' || dom.name FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_alias al ON al.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled AND al.address='%u')" - sqlite = "(SELECT mb.address || '@' || dom.name FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_mailbox mb ON mb.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled=1 AND mb.address='%u') UNION (SELECT al.address || '@' || dom.name FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_alias al ON al.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled=1 AND al.address='%u')" - - -class MailboxesSelfAliasesMap(MapFile): - filename = "sql-mailboxes-self-aliases.cf" - mysql = "SELECT email FROM core_user u INNER JOIN admin_mailbox mb ON mb.user_id=u.id WHERE u.email='%s' AND u.is_active=1" - postgres = "SELECT email FROM core_user u INNER JOIN admin_mailbox mb ON mb.user_id=u.id WHERE u.email='%s' AND u.is_active" - sqlite = "SELECT email FROM core_user u INNER JOIN admin_mailbox mb ON mb.user_id=u.id WHERE u.email='%s' AND u.is_active=1" - - -class CatchallAliasesMap(MapFile): - filename = 'sql-catchall-aliases.cf' - mysql = "(SELECT concat(mb.address, '@', dom.name) FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id INNER JOIN admin_alias_mboxes al_mb ON al.id=al_mb.alias_id WHERE al.enabled=1 AND al.address='*' AND dom.name='%d' AND dom.enabled=1)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.enabled='1' AND al.extmboxes<>'' AND al.address='*' AND dom.name='%d' AND dom.enabled=1)" - postgres = "(SELECT mb.address || '@' || dom.name FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id INNER JOIN admin_alias_mboxes al_mb ON al.id=al_mb.alias_id WHERE al.enabled AND al.address='*' AND dom.name='%d' AND dom.enabled)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.enabled AND al.extmboxes<>'' AND al.address='*' AND dom.name='%d' AND dom.enabled)" - sqlite = "(SELECT (mb.address || '@' || dom.name) FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id INNER JOIN admin_alias_mboxes al_mb ON al.id=al_mb.alias_id WHERE al.enabled=1 AND al.address='*' AND dom.name='%d' AND dom.enabled=1)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.enabled='1' AND al.extmboxes<>'' AND al.address='*' AND dom.name='%d' AND dom.enabled=1)" - - -class MaintainMap(MapFile): - filename = 'sql-maintain.cf' - mysql = "SELECT '450 Requested mail action not taken: mailbox unavailable' FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id INNER JOIN admin_mailboxoperation mbop ON mbop.mailbox_id=mb.id WHERE dom.name='%d' AND mb.address='%u' LIMIT 1" - postgres = "SELECT '450 Requested mail action not taken: mailbox unavailable' FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id INNER JOIN admin_mailboxoperation mbop ON mbop.mailbox_id=mb.id WHERE dom.name='%d' AND mb.address='%u' LIMIT 1" - sqlite = "SELECT '450 Requested mail action not taken: mailbox unavailable' FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id INNER JOIN admin_mailboxoperation mbop ON mbop.mailbox_id=mb.id WHERE dom.name='%d' AND mb.address='%u' LIMIT 1" - - -class TransportMap(MapFile): - category = "autoreply" - filename = 'sql-autoreplies-transport.cf' - mysql = "SELECT method FROM postfix_autoreply_transport WHERE domain='%s'" - postgres = "SELECT method FROM postfix_autoreply_transport WHERE domain='%s'" - sqlite = "SELECT method FROM postfix_autoreply_transport WHERE domain='%s'" - - -class AutoRepliesMap(MapFile): - category = "autoreply" - filename = 'sql-autoreplies.cf' - mysql = "SELECT full_address, autoreply_address FROM postfix_autoreply_alias WHERE full_address='%s'" - postgres = "SELECT full_address, autoreply_address FROM postfix_autoreply_alias WHERE full_address='%s'" - sqlite = "SELECT full_address, autoreply_address FROM postfix_autoreply_alias WHERE full_address='%s'" - - -class RelayDomainsMap(MapFile): - category = "relaydomains" - filename = "sql-relaydomains.cf" - mysql = "SELECT name FROM postfix_relay_domains_relaydomain WHERE name='%s' AND enabled=1" - postgres = "SELECT name FROM postfix_relay_domains_relaydomain WHERE name='%s' AND enabled" - sqlite = "SELECT name FROM postfix_relay_domains_relaydomain WHERE name='%s' AND enabled=1" - - -class RelayDomainsTransportMap(MapFile): - category = "relaydomains" - filename = "sql-relaydomains-transport.cf" - mysql = "SELECT CONCAT(srv.name, ':[', rdom.target_host, ']') FROM postfix_relay_domains_service AS srv INNER JOIN postfix_relay_domains_relaydomain AS rdom ON rdom.service_id=srv.id WHERE rdom.enabled=1 AND rdom.name='%s'" - postgres = "SELECT srv.name || ':[' || rdom.target_host || ']' FROM postfix_relay_domains_service AS srv INNER JOIN postfix_relay_domains_relaydomain AS rdom ON rdom.service_id=srv.id WHERE rdom.enabled AND rdom.name='%s'" - sqlite = "SELECT srv.name || ':[' || rdom.target_host || ']' FROM postfix_relay_domains_service AS srv INNER JOIN postfix_relay_domains_relaydomain AS rdom ON rdom.service_id=srv.id WHERE rdom.enabled=1 AND rdom.name='%s'" - - -class RelayDomainAliasesTransportMap(MapFile): - category = "relaydomains" - filename = "sql-relaydomain-aliases-transport.cf" - mysql = "SELECT CONCAT(srv.name, ':[', rdom.target_host, ']') FROM postfix_relay_domains_service AS srv INNER JOIN postfix_relay_domains_relaydomain AS rdom ON rdom.service_id=srv.id INNER JOIN postfix_relay_domains_relaydomainalias AS rdomalias ON rdom.id=rdomalias.target_id WHERE rdom.enabled=1 AND rdomalias.enabled=1 AND rdomalias.name='%s'" - postgres = "SELECT srv.name || ':[' || rdom.target_host || ']' FROM postfix_relay_domains_service AS srv INNER JOIN postfix_relay_domains_relaydomain AS rdom ON rdom.service_id=srv.id INNER JOIN postfix_relay_domains_relaydomainalias AS rdomalias ON rdom.id=rdomalias.target_id WHERE rdom.enabled AND rdomalias.enabled AND rdomalias.name='%s'" - sqlite = "SELECT srv.name || ':[' || rdom.target_host || ']' FROM postfix_relay_domains_service AS srv INNER JOIN postfix_relay_domains_relaydomain AS rdom ON rdom.service_id=srv.id INNER JOIN postfix_relay_domains_relaydomainalias AS rdomalias ON rdom.id=rdomalias.target_id WHERE rdom.enabled=1 AND rdomalias.enabled=1 AND rdomalias.name='%s'" - - -class RelayRecipientVerification(MapFile): - category = "relaydomains" - filename = "sql-relay-recipient-verification.cf" - mysql = "SELECT 'reject_unverified_recipient' FROM postfix_relay_domains_relaydomain WHERE verify_recipients=1 AND name='%d'" - postgres = "SELECT 'reject_unverified_recipient' FROM postfix_relay_domains_relaydomain WHERE verify_recipients AND name='%d'" - sqlite = ( - "SELECT 'reject_unverified_recipient' " - "FROM postfix_relay_domains_relaydomain " - "WHERE verify_recipients=1 AND name='%d'" - ) - - class PostfixMapsCommand(Command): help = "Generate ready-to-use postfix map files" @@ -229,16 +144,17 @@ class PostfixMapsCommand(Command): help="url of Modoboa's database" ) self._parser.add_argument( - '--categories', type=str, nargs='*', default=['std'], - help='Map file categories to generate (choices: std, autoreply)' + '--extensions', type=str, nargs='+', + help=( + 'Generate map files for this extensions ' + '("all" shortcut available)' + ) ) def handle(self, parsed_args): - """Command entry point. - """ + """Command entry point.""" dbinfo = None if parsed_args.dburl: - import dj_database_url dbinfo = dj_database_url.config(default=parsed_args.dburl[0]) if 'sqlite' in dbinfo['ENGINE']: parsed_args.dbtype = 'sqlite' @@ -247,7 +163,7 @@ class PostfixMapsCommand(Command): else: parsed_args.dbtype = 'mysql' if parsed_args.dbtype == 'sqlite': - g = SQLiteMapFilesGenerator(dbinfo) + generator = SQLiteMapFilesGenerator(dbinfo) else: - g = MapFilesGenerator(dbinfo) - g.render(parsed_args) + generator = MapFilesGenerator(dbinfo) + generator.render(parsed_args)