VirtualMailManager/Domain.py
branchv0.6.x
changeset 236 084331dd1e4c
parent 225 a51809f7940b
child 240 fb6336b25b8f
equal deleted inserted replaced
235:9d3405ed08e5 236:084331dd1e4c
     1 # -*- coding: UTF-8 -*-
     1 # -*- coding: UTF-8 -*-
     2 # Copyright (c) 2007 - 2010, Pascal Volk
     2 # Copyright (c) 2007 - 2010, Pascal Volk
     3 # See COPYING for distribution information.
     3 # See COPYING for distribution information.
     4 
     4 
     5 """Virtual Mail Manager's Domain class to manage e-mail domains."""
     5 """
     6 
     6     VirtualMailManager.Domain
       
     7 
       
     8     Virtual Mail Manager's Domain class to manage e-mail domains.
       
     9 """
       
    10 
       
    11 import os
     7 from random import choice
    12 from random import choice
     8 
    13 
     9 from VirtualMailManager import check_domainname
    14 from VirtualMailManager import check_domainname
    10 from VirtualMailManager.constants.ERROR import \
    15 from VirtualMailManager.constants.ERROR import \
    11      ACCOUNT_AND_ALIAS_PRESENT, ACCOUNT_PRESENT, ALIAS_PRESENT, \
    16      ACCOUNT_AND_ALIAS_PRESENT, ACCOUNT_PRESENT, ALIAS_PRESENT, \
    18 _ = lambda x: x
    23 _ = lambda x: x
    19 
    24 
    20 
    25 
    21 class Domain(object):
    26 class Domain(object):
    22     """Class to manage e-mail domains."""
    27     """Class to manage e-mail domains."""
    23     __slots__ = ('_basedir', '_domaindir', '_id', '_name', '_transport',
    28     __slots__ = ('_directory', '_gid', '_name', '_transport', '_dbh', '_new')
    24                  '_dbh')
    29 
    25 
    30     def __init__(self, dbh, domainname):
    26     def __init__(self, dbh, domainname, basedir=None, transport=None):
       
    27         """Creates a new Domain instance.
    31         """Creates a new Domain instance.
    28 
    32 
    29         Keyword arguments:
    33         Loads all relevant data from the database, if the domain could be
    30         dbh -- a pyPgSQL.PgSQL.connection
    34         found.  To create a new domain call the methods set_directory() and
    31         domainname -- name of the domain (str)
    35         set_transport() before save().
    32         transport -- default vmm.cfg/misc/transport  (str)
    36 
    33         """
    37         A DomainError will be thrown when the *domainname* is the name of
       
    38         an alias domain.
       
    39 
       
    40         Arguments:
       
    41 
       
    42         `dbh` : pyPgSQL.PgSQL.Connection
       
    43           a database connection for the database access
       
    44         `domainname` : basestring
       
    45           The name of the domain
       
    46         """
       
    47         self._name = check_domainname(domainname)
    34         self._dbh = dbh
    48         self._dbh = dbh
    35         self._name = check_domainname(domainname)
    49         self._gid = 0
    36         self._basedir = basedir
    50         self._transport = None
    37         if transport is not None:
    51         self._directory = None
    38             self._transport = Transport(self._dbh, transport=transport)
    52         self._new = True
    39         else:
    53         self._load()
    40             self._transport = transport
    54 
    41         self._id = 0
    55     def _load(self):
    42         self._domaindir = None
    56         """Load information from the database and checks if the domain name
    43         if not self._exists() and self._isAlias():
    57         is the primary one.
    44             raise DomErr(_(u"The domain “%s” is an alias domain.") %
    58 
    45                          self._name, DOMAIN_ALIAS_EXISTS)
    59         Raises a DomainError if Domain._name isn't the primary name of the
    46 
    60         domain.
    47     def _exists(self):
    61         """
    48         """Checks if the domain already exists.
    62         dbc = self._dbh.cursor()
    49 
    63         dbc.execute('SELECT dd.gid, tid, domaindir, is_primary FROM \
    50         If the domain exists _id will be set and returns True, otherwise False
    64  domain_data dd, domain_name dn WHERE domainname = %s AND dn.gid = dd.gid',
    51         will be returned.
    65                     self._name)
    52         """
       
    53         dbc = self._dbh.cursor()
       
    54         dbc.execute("SELECT gid, tid, domaindir FROM domain_data WHERE gid =\
       
    55  (SELECT gid FROM domain_name WHERE domainname = %s AND is_primary)",
       
    56                 self._name)
       
    57         result = dbc.fetchone()
    66         result = dbc.fetchone()
    58         dbc.close()
    67         dbc.close()
    59         if result is not None:
    68         if result:
    60             self._id, self._domaindir = result[0], result[2]
    69             if not result[3]:
       
    70                 raise DomErr(_(u"The domain '%s' is an alias domain.") %
       
    71                              self._name, DOMAIN_ALIAS_EXISTS)
       
    72             self._gid, self._directory = result[0], result[2]
    61             self._transport = Transport(self._dbh, tid=result[1])
    73             self._transport = Transport(self._dbh, tid=result[1])
    62             return True
    74             self._new = False
    63         else:
    75 
    64             return False
    76     def _set_gid(self):
    65 
    77         """Sets the ID of the domain - if not set yet."""
    66     def _isAlias(self):
    78         assert self._gid == 0
    67         """Checks if self._name is known for an alias domain."""
       
    68         dbc = self._dbh.cursor()
       
    69         dbc.execute('SELECT is_primary FROM domain_name WHERE domainname = %s',
       
    70                 self._name)
       
    71         result = dbc.fetchone()
       
    72         dbc.close()
       
    73         if result is not None and not result[0]:
       
    74             return True
       
    75         else:
       
    76             return False
       
    77 
       
    78     def _setID(self):
       
    79         """Sets the ID of the domain."""
       
    80         dbc = self._dbh.cursor()
    79         dbc = self._dbh.cursor()
    81         dbc.execute("SELECT nextval('domain_gid')")
    80         dbc.execute("SELECT nextval('domain_gid')")
    82         self._id = dbc.fetchone()[0]
    81         self._gid = dbc.fetchone()[0]
    83         dbc.close()
    82         dbc.close()
    84 
       
    85     def _prepare(self):
       
    86         self._setID()
       
    87         self._domaindir = "%s/%s/%i" % (self._basedir, choice(MAILDIR_CHARS),
       
    88                 self._id)
       
    89 
    83 
    90     def _has(self, what):
    84     def _has(self, what):
    91         """Checks if aliases or accounts are assigned to the domain.
    85         """Checks if aliases or accounts are assigned to the domain.
    92 
    86 
    93         If there are assigned accounts or aliases True will be returned,
    87         If there are assigned accounts or aliases True will be returned,
    94         otherwise False will be returned.
    88         otherwise False will be returned.
    95 
    89 
    96         Keyword arguments:
    90         Argument:
    97         what -- 'alias' or 'users' (strings)
    91 
    98         """
    92         `what` : basestring
    99         if what not in ['alias', 'users']:
    93             "alias" or "users"
   100             return False
    94         """
       
    95         assert what in ('alias', 'users')
   101         dbc = self._dbh.cursor()
    96         dbc = self._dbh.cursor()
   102         if what == 'users':
    97         if what == 'users':
   103             dbc.execute("SELECT count(gid) FROM users WHERE gid=%s", self._id)
    98             dbc.execute("SELECT count(gid) FROM users WHERE gid=%s", self._gid)
   104         else:
    99         else:
   105             dbc.execute("SELECT count(gid) FROM alias WHERE gid=%s", self._id)
   100             dbc.execute("SELECT count(gid) FROM alias WHERE gid=%s", self._gid)
   106         count = dbc.fetchone()
   101         count = dbc.fetchone()
   107         dbc.close()
   102         dbc.close()
   108         if count[0] > 0:
   103         return count[0] > 0
   109             return True
   104 
       
   105     def _chk_delete(self, deluser, delalias):
       
   106         """Checks dependencies for deletion.
       
   107 
       
   108         Arguments:
       
   109         deluser -- ignore available accounts (bool)
       
   110         delalias -- ignore available aliases (bool)
       
   111         """
       
   112         if not deluser:
       
   113             hasuser = self._has('users')
   110         else:
   114         else:
   111             return False
   115             hasuser = False
   112 
   116         if not delalias:
   113     def _chkDelete(self, delUser, delAlias):
   117             hasalias = self._has('alias')
   114         """Checks dependencies for deletion.
       
   115 
       
   116         Keyword arguments:
       
   117         delUser -- ignore available accounts (bool)
       
   118         delAlias -- ignore available aliases (bool)
       
   119         """
       
   120         if not delUser:
       
   121             hasUser = self._has('users')
       
   122         else:
   118         else:
   123             hasUser = False
   119             hasalias = False
   124         if not delAlias:
   120         if hasuser and hasalias:
   125             hasAlias = self._has('alias')
       
   126         else:
       
   127             hasAlias = False
       
   128         if hasUser and hasAlias:
       
   129             raise DomErr(_(u'There are accounts and aliases.'),
   121             raise DomErr(_(u'There are accounts and aliases.'),
   130                          ACCOUNT_AND_ALIAS_PRESENT)
   122                          ACCOUNT_AND_ALIAS_PRESENT)
   131         elif hasUser:
   123         elif hasuser:
   132             raise DomErr(_(u'There are accounts.'), ACCOUNT_PRESENT)
   124             raise DomErr(_(u'There are accounts.'), ACCOUNT_PRESENT)
   133         elif hasAlias:
   125         elif hasalias:
   134             raise DomErr(_(u'There are aliases.'), ALIAS_PRESENT)
   126             raise DomErr(_(u'There are aliases.'), ALIAS_PRESENT)
       
   127 
       
   128     def _chk_state(self):
       
   129         """Throws a DomainError if the Domain is new - not saved in the
       
   130         database."""
       
   131         if self._new:
       
   132             raise DomErr(_(u"The domain '%s' doesn't exist.") % self._name,
       
   133                          NO_SUCH_DOMAIN)
       
   134 
       
   135     @property
       
   136     def gid(self):
       
   137         """The GID of the Domain."""
       
   138         return self._gid
       
   139 
       
   140     @property
       
   141     def name(self):
       
   142         """The Domain's name."""
       
   143         return self._name
       
   144 
       
   145     @property
       
   146     def directory(self):
       
   147         """The Domain's directory."""
       
   148         return self._directory
       
   149 
       
   150     def set_directory(self, basedir):
       
   151         """Set the path value of the Domain's directory, inside *basedir*.
       
   152 
       
   153         Argument:
       
   154 
       
   155         `basedir` : basestring
       
   156           The base directory of all domains
       
   157         """
       
   158         assert self._new and self._directory is None
       
   159         self._set_gid()
       
   160         self._directory = os.path.join(basedir, choice(MAILDIR_CHARS),
       
   161                                        str(self._gid))
       
   162 
       
   163     @property
       
   164     def transport(self):
       
   165         """The Domain's transport."""
       
   166         return self._transport
       
   167 
       
   168     def set_transport(self, transport):
       
   169         """Set the transport for the new Domain.
       
   170 
       
   171         Argument:
       
   172 
       
   173         `transport` : VirtualMailManager.Transport
       
   174           The transport of the new Domain
       
   175         """
       
   176         assert self._new and isinstance(transport, Transport)
       
   177         self._transport = transport
   135 
   178 
   136     def save(self):
   179     def save(self):
   137         """Stores the new domain in the database."""
   180         """Stores the new domain in the database."""
   138         if self._id < 1:
   181         if not self._new:
   139             self._prepare()
   182             raise DomErr(_(u"The domain '%s' already exists.") % self._name,
   140             dbc = self._dbh.cursor()
   183                          DOMAIN_EXISTS)
   141             dbc.execute("INSERT INTO domain_data (gid, tid, domaindir)\
   184         assert self._directory is not None and self._transport is not None
   142  VALUES (%s, %s, %s)", self._id, self._transport.id, self._domaindir)
   185         dbc = self._dbh.cursor()
   143             dbc.execute("INSERT INTO domain_name (domainname, gid, is_primary)\
   186         dbc.execute("INSERT INTO domain_data VALUES (%s, %s, %s)", self._gid,
   144  VALUES (%s, %s, %s)", self._name, self._id, True)
   187                     self._transport.tid, self._directory)
       
   188         dbc.execute("INSERT INTO domain_name VALUES (%s, %s, %s)", self._name,
       
   189                     self._gid, True)
       
   190         self._dbh.commit()
       
   191         dbc.close()
       
   192         self._new = False
       
   193 
       
   194     def delete(self, deluser=False, delalias=False):
       
   195         """Deletes the domain.
       
   196 
       
   197         Arguments:
       
   198 
       
   199         `deluser` : bool
       
   200           force deletion of all available accounts, default `False`
       
   201         `delalias` : bool
       
   202           force deletion of all available aliases, default `False`
       
   203         """
       
   204         self._chk_state()
       
   205         self._chk_delete(deluser, delalias)
       
   206         dbc = self._dbh.cursor()
       
   207         for tbl in ('alias', 'users', 'relocated', 'domain_name',
       
   208                     'domain_data'):
       
   209             dbc.execute("DELETE FROM %s WHERE gid = %d" % (tbl, self._gid))
       
   210         self._dbh.commit()
       
   211         dbc.close()
       
   212         self._gid = 0
       
   213         self._directory = self._transport = None
       
   214         self._new = True
       
   215 
       
   216     def update_transport(self, transport, force=False):
       
   217         """Sets a new transport for the Domain.
       
   218 
       
   219         If *force* is `True` the new *transport* will be assigned to all
       
   220         existing accounts.  Otherwise the *transport* will be only used for
       
   221         accounts created from now on.
       
   222 
       
   223         Arguments:
       
   224 
       
   225         `transport` : VirtualMailManager.Transport
       
   226           the new transport
       
   227         `force` : bool
       
   228           enforce new transport setting for all accounts, default `False`
       
   229         """
       
   230         self._chk_state()
       
   231         assert isinstance(transport, Transport)
       
   232         if transport == self._transport:
       
   233             return
       
   234         dbc = self._dbh.cursor()
       
   235         dbc.execute("UPDATE domain_data SET tid = %s WHERE gid = %s",
       
   236                     transport.tid, self._gid)
       
   237         if dbc.rowcount > 0:
   145             self._dbh.commit()
   238             self._dbh.commit()
   146             dbc.close()
   239         if force:
   147         else:
   240             dbc.execute("UPDATE users SET tid = %s WHERE gid = %s",
   148             raise DomErr(_(u'The domain “%s” already exists.') % self._name,
   241                         transport.tid, self._gid)
   149                          DOMAIN_EXISTS)
       
   150 
       
   151     def delete(self, delUser=False, delAlias=False):
       
   152         """Deletes the domain.
       
   153 
       
   154         Keyword arguments:
       
   155         delUser -- force deletion of available accounts (bool)
       
   156         delAlias -- force deletion of available aliases (bool)
       
   157         """
       
   158         if self._id > 0:
       
   159             self._chkDelete(delUser, delAlias)
       
   160             dbc = self._dbh.cursor()
       
   161             for tbl in ('alias', 'users', 'relocated', 'domain_name',
       
   162                         'domain_data'):
       
   163                 dbc.execute("DELETE FROM %s WHERE gid = %d" % (tbl, self._id))
       
   164             self._dbh.commit()
       
   165             dbc.close()
       
   166         else:
       
   167             raise DomErr(_(u"The domain “%s” doesn't exist.") % self._name,
       
   168                          NO_SUCH_DOMAIN)
       
   169 
       
   170     def updateTransport(self, transport, force=False):
       
   171         """Sets a new transport for the domain.
       
   172 
       
   173         Keyword arguments:
       
   174         transport -- the new transport (str)
       
   175         force -- True/False force new transport for all accounts (bool)
       
   176         """
       
   177         if self._id > 0:
       
   178             if transport == self._transport.transport:
       
   179                 return
       
   180             trsp = Transport(self._dbh, transport=transport)
       
   181             dbc = self._dbh.cursor()
       
   182             dbc.execute("UPDATE domain_data SET tid = %s WHERE gid = %s",
       
   183                         trsp.id, self._id)
       
   184             if dbc.rowcount > 0:
   242             if dbc.rowcount > 0:
   185                 self._dbh.commit()
   243                 self._dbh.commit()
   186             if force:
   244         dbc.close()
   187                 dbc.execute("UPDATE users SET tid = %s WHERE gid = %s",
   245         self._transport = transport
   188                             trsp.id, self._id)
   246 
   189                 if dbc.rowcount > 0:
   247     def get_info(self):
   190                     self._dbh.commit()
       
   191             dbc.close()
       
   192         else:
       
   193             raise DomErr(_(u"The domain “%s” doesn't exist.") % self._name,
       
   194                          NO_SUCH_DOMAIN)
       
   195 
       
   196     def getID(self):
       
   197         """Returns the ID of the domain."""
       
   198         return self._id
       
   199 
       
   200     def getDir(self):
       
   201         """Returns the directory of the domain."""
       
   202         return self._domaindir
       
   203 
       
   204     def getTransport(self):
       
   205         """Returns domain's transport."""
       
   206         return self._transport.transport
       
   207 
       
   208     def getTransportID(self):
       
   209         """Returns the ID from the domain's transport."""
       
   210         return self._transport.id
       
   211 
       
   212     def getInfo(self):
       
   213         """Returns a dictionary with information about the domain."""
   248         """Returns a dictionary with information about the domain."""
   214         sql = """\
   249         self._chk_state()
   215 SELECT gid, domainname, transport, domaindir, aliasdomains, accounts,
   250         sql = """SELECT gid, domainname, transport, domaindir, aliasdomains,
   216        aliases, relocated
   251        accounts, aliases, relocated
   217   FROM vmm_domain_info
   252   FROM vmm_domain_info
   218  WHERE gid = %i""" % self._id
   253  WHERE gid = %i""" % self._gid
   219         dbc = self._dbh.cursor()
   254         dbc = self._dbh.cursor()
   220         dbc.execute(sql)
   255         dbc.execute(sql)
   221         info = dbc.fetchone()
   256         info = dbc.fetchone()
   222         dbc.close()
   257         dbc.close()
   223         if info is None:
   258         keys = ('gid', 'domainname', 'transport', 'domaindir', 'aliasdomains',
   224             raise DomErr(_(u"The domain “%s” doesn't exist.") % self._name,
   259                 'accounts', 'aliases', 'relocated')
   225                          NO_SUCH_DOMAIN)
   260         return dict(zip(keys, info))
   226         else:
   261 
   227             keys = ['gid', 'domainname', 'transport', 'domaindir',
   262     def get_accounts(self):
   228                     'aliasdomains', 'accounts', 'aliases', 'relocated']
   263         """Returns a list with all accounts of the domain."""
   229             return dict(zip(keys, info))
   264         self._chk_state()
   230 
       
   231     def getAccounts(self):
       
   232         """Returns a list with all accounts from the domain."""
       
   233         dbc = self._dbh.cursor()
   265         dbc = self._dbh.cursor()
   234         dbc.execute("SELECT local_part from users where gid = %s ORDER BY\
   266         dbc.execute("SELECT local_part from users where gid = %s ORDER BY\
   235  local_part", self._id)
   267  local_part", self._gid)
   236         users = dbc.fetchall()
   268         users = dbc.fetchall()
   237         dbc.close()
   269         dbc.close()
   238         accounts = []
   270         accounts = []
   239         if len(users) > 0:
   271         if len(users) > 0:
   240             addr = u'@'.join
   272             addr = u'@'.join
   241             _dom = self._name
   273             _dom = self._name
   242             accounts = [addr((account[0], _dom)) for account in users]
   274             accounts = [addr((account[0], _dom)) for account in users]
   243         return accounts
   275         return accounts
   244 
   276 
   245     def getAliases(self):
   277     def get_aliases(self):
   246         """Returns a list with all aliases from the domain."""
   278         """Returns a list with all aliases e-mail addresses of the domain."""
       
   279         self._chk_state()
   247         dbc = self._dbh.cursor()
   280         dbc = self._dbh.cursor()
   248         dbc.execute("SELECT DISTINCT address FROM alias WHERE gid = %s\
   281         dbc.execute("SELECT DISTINCT address FROM alias WHERE gid = %s\
   249  ORDER BY address", self._id)
   282  ORDER BY address", self._gid)
   250         addresses = dbc.fetchall()
   283         addresses = dbc.fetchall()
   251         dbc.close()
   284         dbc.close()
   252         aliases = []
   285         aliases = []
   253         if len(addresses) > 0:
   286         if addresses:
   254             addr = u'@'.join
   287             addr = u'@'.join
   255             _dom = self._name
   288             _dom = self._name
   256             aliases = [addr((alias[0], _dom)) for alias in addresses]
   289             aliases = [addr((alias[0], _dom)) for alias in addresses]
   257         return aliases
   290         return aliases
   258 
   291 
   259     def getRelocated(self):
   292     def get_relocated(self):
   260         """Returns a list with all addresses from relocated users."""
   293         """Returns a list with all addresses of relocated users."""
       
   294         self._chk_state()
   261         dbc = self._dbh.cursor()
   295         dbc = self._dbh.cursor()
   262         dbc.execute("SELECT address FROM relocated WHERE gid = %s\
   296         dbc.execute("SELECT address FROM relocated WHERE gid = %s\
   263  ORDER BY address", self._id)
   297  ORDER BY address", self._gid)
   264         addresses = dbc.fetchall()
   298         addresses = dbc.fetchall()
   265         dbc.close()
   299         dbc.close()
   266         relocated = []
   300         relocated = []
   267         if len(addresses) > 0:
   301         if addresses:
   268             addr = u'@'.join
   302             addr = u'@'.join
   269             _dom = self._name
   303             _dom = self._name
   270             relocated = [addr((address[0], _dom)) for address in addresses]
   304             relocated = [addr((address[0], _dom)) for address in addresses]
   271         return relocated
   305         return relocated
   272 
   306 
   273     def getAliaseNames(self):
   307     def get_aliase_names(self):
   274         """Returns a list with all alias names from the domain."""
   308         """Returns a list with all alias domain names of the domain."""
       
   309         self._chk_state()
   275         dbc = self._dbh.cursor()
   310         dbc = self._dbh.cursor()
   276         dbc.execute("SELECT domainname FROM domain_name WHERE gid = %s\
   311         dbc.execute("SELECT domainname FROM domain_name WHERE gid = %s\
   277  AND NOT is_primary ORDER BY domainname", self._id)
   312  AND NOT is_primary ORDER BY domainname", self._gid)
   278         anames = dbc.fetchall()
   313         anames = dbc.fetchall()
   279         dbc.close()
   314         dbc.close()
   280         aliasdomains = []
   315         aliasdomains = []
   281         if len(anames) > 0:
   316         if anames:
   282             aliasdomains = [aname[0] for aname in anames]
   317             aliasdomains = [aname[0] for aname in anames]
   283         return aliasdomains
   318         return aliasdomains
   284 
   319 
   285 
   320 
   286 def search(dbh, pattern=None, like=False):
   321 def search(dbh, pattern=None, like=False):
       
   322     """'Search' for domains by *pattern* in the database.
       
   323 
       
   324     *pattern* may be a domain name or a partial domain name - starting
       
   325     and/or ending with a '%' sign.  When the *pattern* starts or ends with
       
   326     a '%' sign *like* has to be `True` to perform a wildcard search.
       
   327     To retrieve all available domains use the arguments' default values.
       
   328 
       
   329     This function returns a tuple with a list and a dict: (order, domains).
       
   330     The order list contains the domains' gid, alphabetical sorted by the
       
   331     primary domain name.  The domains dict's keys are the gids of the
       
   332     domains. The value of item is a list.  The first list element contains
       
   333     the primary domain name or `None`.  The elements [1:] contains the
       
   334     names of alias domains.
       
   335 
       
   336     Arguments:
       
   337 
       
   338     `pattern` : basestring
       
   339       a (partial) domain name (starting and/or ending with a "%" sign)
       
   340     `like` : bool
       
   341       should be `True` when *pattern* starts/ends with a "%" sign
       
   342     """
   287     if pattern is not None and like is False:
   343     if pattern is not None and like is False:
   288         pattern = check_domainname(pattern)
   344         pattern = check_domainname(pattern)
   289     sql = 'SELECT gid, domainname, is_primary FROM domain_name'
   345     sql = 'SELECT gid, domainname, is_primary FROM domain_name'
   290     if pattern is None:
   346     if pattern is None:
   291         pass
   347         pass
   299     doms = dbc.fetchall()
   355     doms = dbc.fetchall()
   300     dbc.close()
   356     dbc.close()
   301 
   357 
   302     domdict = {}
   358     domdict = {}
   303     order = [dom[0] for dom in doms if dom[2]]
   359     order = [dom[0] for dom in doms if dom[2]]
   304     if len(order) == 0:
   360     if not order:
   305         for dom in doms:
   361         for dom in doms:
   306             if dom[0] not in order:
   362             if dom[0] not in order:
   307                 order.append(dom[0])
   363                 order.append(dom[0])
   308     for gid, dom, is_primary in doms:
   364     for gid, dom, is_primary in doms:
   309         if is_primary:
   365         if is_primary:
   319 
   375 
   320 def get_gid(dbh, domainname):
   376 def get_gid(dbh, domainname):
   321     """Returns the group id of the domain *domainname*.
   377     """Returns the group id of the domain *domainname*.
   322 
   378 
   323     If the domain couldn't be found in the database 0 will be returned.
   379     If the domain couldn't be found in the database 0 will be returned.
   324 
       
   325     """
   380     """
   326     domainname = check_domainname(domainname)
   381     domainname = check_domainname(domainname)
   327     dbc = dbh.cursor()
   382     dbc = dbh.cursor()
   328     dbc.execute('SELECT gid FROM domain_name WHERE domainname=%s', domainname)
   383     dbc.execute('SELECT gid FROM domain_name WHERE domainname=%s', domainname)
   329     gid = dbc.fetchone()
   384     gid = dbc.fetchone()