16 ACCOUNT_AND_ALIAS_PRESENT, DOMAIN_ALIAS_EXISTS, DOMAIN_EXISTS, \ |
16 ACCOUNT_AND_ALIAS_PRESENT, DOMAIN_ALIAS_EXISTS, DOMAIN_EXISTS, \ |
17 DOMAIN_INVALID, DOMAIN_TOO_LONG, NO_SUCH_DOMAIN, VMM_ERROR |
17 DOMAIN_INVALID, DOMAIN_TOO_LONG, NO_SUCH_DOMAIN, VMM_ERROR |
18 from VirtualMailManager.errors import VMMError, DomainError as DomErr |
18 from VirtualMailManager.errors import VMMError, DomainError as DomErr |
19 from VirtualMailManager.pycompat import all, any |
19 from VirtualMailManager.pycompat import all, any |
20 from VirtualMailManager.quotalimit import QuotaLimit |
20 from VirtualMailManager.quotalimit import QuotaLimit |
|
21 from VirtualMailManager.serviceset import ServiceSet |
21 from VirtualMailManager.transport import Transport |
22 from VirtualMailManager.transport import Transport |
22 |
23 |
23 |
24 |
24 MAILDIR_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz' |
25 MAILDIR_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz' |
25 RE_DOMAIN = re.compile(r"^(?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}$") |
26 RE_DOMAIN = re.compile(r"^(?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}$") |
27 cfg_dget = lambda option: None |
28 cfg_dget = lambda option: None |
28 |
29 |
29 |
30 |
30 class Domain(object): |
31 class Domain(object): |
31 """Class to manage e-mail domains.""" |
32 """Class to manage e-mail domains.""" |
32 __slots__ = ('_directory', '_gid', '_name', '_qlimit', '_transport', |
33 __slots__ = ('_directory', '_gid', '_name', '_qlimit', '_services', |
33 '_dbh', '_new') |
34 '_transport', '_dbh', '_new') |
34 |
35 |
35 def __init__(self, dbh, domainname): |
36 def __init__(self, dbh, domainname): |
36 """Creates a new Domain instance. |
37 """Creates a new Domain instance. |
37 |
38 |
38 Loads all relevant data from the database, if the domain could be |
39 Loads all relevant data from the database, if the domain could be |
64 |
66 |
65 Raises a DomainError if Domain._name isn't the primary name of the |
67 Raises a DomainError if Domain._name isn't the primary name of the |
66 domain. |
68 domain. |
67 """ |
69 """ |
68 dbc = self._dbh.cursor() |
70 dbc = self._dbh.cursor() |
69 dbc.execute('SELECT dd.gid, qid, tid, domaindir, is_primary FROM ' |
71 dbc.execute('SELECT dd.gid, qid, ssid, tid, domaindir, is_primary ' |
70 'domain_data dd, domain_name dn WHERE domainname = %s AND ' |
72 'FROM domain_data dd, domain_name dn WHERE domainname = ' |
71 'dn.gid = dd.gid', (self._name,)) |
73 '%s AND dn.gid = dd.gid', (self._name,)) |
72 result = dbc.fetchone() |
74 result = dbc.fetchone() |
73 dbc.close() |
75 dbc.close() |
74 if result: |
76 if result: |
75 if not result[4]: |
77 if not result[5]: |
76 raise DomErr(_(u"The domain '%s' is an alias domain.") % |
78 raise DomErr(_(u"The domain '%s' is an alias domain.") % |
77 self._name, DOMAIN_ALIAS_EXISTS) |
79 self._name, DOMAIN_ALIAS_EXISTS) |
78 self._gid, self._directory = result[0], result[3] |
80 self._gid, self._directory = result[0], result[4] |
79 self._qlimit = QuotaLimit(self._dbh, qid=result[1]) |
81 self._qlimit = QuotaLimit(self._dbh, qid=result[1]) |
80 self._transport = Transport(self._dbh, tid=result[2]) |
82 self._services = ServiceSet(self._dbh, ssid=result[2]) |
|
83 self._transport = Transport(self._dbh, tid=result[3]) |
81 self._new = False |
84 self._new = False |
82 |
85 |
83 def _set_gid(self): |
86 def _set_gid(self): |
84 """Sets the ID of the domain - if not set yet.""" |
87 """Sets the ID of the domain - if not set yet.""" |
85 assert self._gid == 0 |
88 assert self._gid == 0 |
120 updated. |
123 updated. |
121 |
124 |
122 Arguments: |
125 Arguments: |
123 |
126 |
124 `column` : basestring |
127 `column` : basestring |
125 Name of the table column. Currently: qid and tid |
128 Name of the table column. Currently: qid, ssid and tid |
126 `value` : long |
129 `value` : long |
127 The referenced key |
130 The referenced key |
128 `force` : bool |
131 `force` : bool |
129 enforce the new setting also for existing users. Default: `False` |
132 enforce the new setting also for existing users. Default: `False` |
130 """ |
133 """ |
131 if column not in ('qid', 'tid'): |
134 if column not in ('qid', 'ssid', 'tid'): |
132 raise ValueError('Unknown column: %r' % column) |
135 raise ValueError('Unknown column: %r' % column) |
133 dbc = self._dbh.cursor() |
136 dbc = self._dbh.cursor() |
134 dbc.execute('UPDATE domain_data SET %s = %%s WHERE gid = %%s' % column, |
137 dbc.execute('UPDATE domain_data SET %s = %%s WHERE gid = %%s' % column, |
135 (value, self._gid)) |
138 (value, self._gid)) |
136 if dbc.rowcount > 0: |
139 if dbc.rowcount > 0: |
161 def quotalimit(self): |
164 def quotalimit(self): |
162 """The Domain's quota limit.""" |
165 """The Domain's quota limit.""" |
163 return self._qlimit |
166 return self._qlimit |
164 |
167 |
165 @property |
168 @property |
|
169 def serviceset(self): |
|
170 """The Domain's serviceset.""" |
|
171 return self._services |
|
172 |
|
173 @property |
166 def transport(self): |
174 def transport(self): |
167 """The Domain's transport.""" |
175 """The Domain's transport.""" |
168 return self._transport |
176 return self._transport |
169 |
177 |
170 def set_directory(self, basedir): |
178 def set_directory(self, basedir): |
195 raise DomErr(_(u"The domain '%s' already exists.") % self._name, |
203 raise DomErr(_(u"The domain '%s' already exists.") % self._name, |
196 DOMAIN_EXISTS) |
204 DOMAIN_EXISTS) |
197 assert isinstance(quotalimit, QuotaLimit) |
205 assert isinstance(quotalimit, QuotaLimit) |
198 self._qlimit = quotalimit |
206 self._qlimit = quotalimit |
199 |
207 |
|
208 def set_serviceset(self, serviceset): |
|
209 """Set the services for the new Domain. |
|
210 |
|
211 Argument: |
|
212 |
|
213 `serviceset` : VirtualMailManager.serviceset.ServiceSet |
|
214 The service set for the new Domain. |
|
215 """ |
|
216 if not self._new: |
|
217 raise DomErr(_(u"The domain '%s' already exists.") % self._name, |
|
218 DOMAIN_EXISTS) |
|
219 assert isinstance(serviceset, ServiceSet) |
|
220 self._services = serviceset |
|
221 |
200 def set_transport(self, transport): |
222 def set_transport(self, transport): |
201 """Set the transport for the new Domain. |
223 """Set the transport for the new Domain. |
202 |
224 |
203 Argument: |
225 Argument: |
204 |
226 |
214 def save(self): |
236 def save(self): |
215 """Stores the new domain in the database.""" |
237 """Stores the new domain in the database.""" |
216 if not self._new: |
238 if not self._new: |
217 raise DomErr(_(u"The domain '%s' already exists.") % self._name, |
239 raise DomErr(_(u"The domain '%s' already exists.") % self._name, |
218 DOMAIN_EXISTS) |
240 DOMAIN_EXISTS) |
219 assert all((self._directory, self._qlimit, self._transport)) |
241 assert all((self._directory, self._qlimit, self._services, |
220 dbc = self._dbh.cursor() |
242 self._transport)) |
221 dbc.execute('INSERT INTO domain_data (gid, qid, tid, domaindir) ' |
243 dbc = self._dbh.cursor() |
222 'VALUES (%s, %s, %s, %s)', (self._gid, self._qlimit.qid, |
244 dbc.execute('INSERT INTO domain_data (gid, qid, ssid, tid, domaindir) ' |
223 self._transport.tid, self._directory)) |
245 'VALUES (%s, %s, %s, %s, %s)', (self._gid, |
|
246 self._qlimit.qid, self._services.ssid, self._transport.tid, |
|
247 self._directory)) |
224 dbc.execute('INSERT INTO domain_name (domainname, gid, is_primary) ' |
248 dbc.execute('INSERT INTO domain_name (domainname, gid, is_primary) ' |
225 'VALUES (%s, %s, TRUE)', (self._name, self._gid)) |
249 'VALUES (%s, %s, TRUE)', (self._name, self._gid)) |
226 self._dbh.commit() |
250 self._dbh.commit() |
227 dbc.close() |
251 dbc.close() |
228 self._new = False |
252 self._new = False |
249 dbc.execute("DELETE FROM %s WHERE gid = %u" % (tbl, self._gid)) |
273 dbc.execute("DELETE FROM %s WHERE gid = %u" % (tbl, self._gid)) |
250 self._dbh.commit() |
274 self._dbh.commit() |
251 dbc.close() |
275 dbc.close() |
252 self._gid = 0 |
276 self._gid = 0 |
253 self._directory = self._qlimit = self._transport = None |
277 self._directory = self._qlimit = self._transport = None |
|
278 self._services = None |
254 self._new = True |
279 self._new = True |
255 |
280 |
256 def update_quotalimit(self, quotalimit, force=False): |
281 def update_quotalimit(self, quotalimit, force=False): |
257 """Update the quota limit of the Domain. |
282 """Update the quota limit of the Domain. |
258 |
283 |
274 assert isinstance(quotalimit, QuotaLimit) |
299 assert isinstance(quotalimit, QuotaLimit) |
275 if not force and quotalimit == self._qlimit: |
300 if not force and quotalimit == self._qlimit: |
276 return |
301 return |
277 self._update_tables('qid', quotalimit.qid, force) |
302 self._update_tables('qid', quotalimit.qid, force) |
278 self._qlimit = quotalimit |
303 self._qlimit = quotalimit |
|
304 |
|
305 def update_serviceset(self, serviceset, force=False): |
|
306 """Assign a different set of services to the Domain, |
|
307 |
|
308 If *force* is `True` the *serviceset* will be also assigned to |
|
309 all existing accounts of the Domain. Otherwise the *serviceset* |
|
310 will be only the 'default' for accounts created from now on. |
|
311 |
|
312 Arguments: |
|
313 `serviceset` : VirtualMailManager.serviceset.ServiceSet |
|
314 the new set of services |
|
315 `force` |
|
316 enforce the serviceset for all accounts, default `False` |
|
317 """ |
|
318 self._chk_state() |
|
319 assert isinstance(serviceset, ServiceSet) |
|
320 if not force and serviceset == self._services: |
|
321 return |
|
322 self._update_tables('ssid', serviceset.ssid, force) |
|
323 self._services = serviceset |
279 |
324 |
280 def update_transport(self, transport, force=False): |
325 def update_transport(self, transport, force=False): |
281 """Sets a new transport for the Domain. |
326 """Sets a new transport for the Domain. |
282 |
327 |
283 If *force* is `True` the new *transport* will be assigned to all |
328 If *force* is `True` the new *transport* will be assigned to all |