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 Account class to manage e-mail accounts.""" |
5 """ |
6 |
6 VirtualMailManager.Account |
7 import VirtualMailManager.constants.ERROR as ERR |
7 |
|
8 Virtual Mail Manager's Account class to manage e-mail accounts. |
|
9 """ |
|
10 |
8 from VirtualMailManager.Domain import Domain |
11 from VirtualMailManager.Domain import Domain |
9 from VirtualMailManager.EmailAddress import EmailAddress |
12 from VirtualMailManager.EmailAddress import EmailAddress |
10 from VirtualMailManager.errors import AccountError as AccE |
13 from VirtualMailManager.Transport import Transport |
|
14 from VirtualMailManager.constants.ERROR import \ |
|
15 ACCOUNT_EXISTS, ACCOUNT_MISSING_PASSWORD, ALIAS_EXISTS, ALIAS_PRESENT, \ |
|
16 INVALID_AGUMENT, NO_SUCH_ACCOUNT, NO_SUCH_DOMAIN, RELOCATED_EXISTS, \ |
|
17 UNKNOWN_MAILLOCATION_NAME, UNKNOWN_SERVICE |
|
18 from VirtualMailManager.errors import AccountError as AErr |
11 from VirtualMailManager.maillocation import MailLocation, known_format |
19 from VirtualMailManager.maillocation import MailLocation, known_format |
12 from VirtualMailManager.Transport import Transport |
20 from VirtualMailManager.pycompat import all |
13 |
21 |
14 |
22 |
15 _ = lambda msg: msg |
23 _ = lambda msg: msg |
16 |
24 |
17 |
25 |
18 class Account(object): |
26 class Account(object): |
19 """Class to manage e-mail accounts.""" |
27 """Class to manage e-mail accounts.""" |
20 __slots__ = ('_addr', '_base', '_gid', '_mid', '_passwd', '_tid', '_uid', |
28 __slots__ = ('_addr', '_domain', '_mid', '_new', '_passwd', '_tid', '_uid', |
21 '_dbh') |
29 '_dbh') |
22 |
30 |
23 def __init__(self, dbh, address, password=None): |
31 def __init__(self, dbh, address): |
|
32 """Creates a new Account instance. |
|
33 |
|
34 When an account with the given *address* could be found in the |
|
35 database all relevant data will be loaded. |
|
36 |
|
37 Arguments: |
|
38 |
|
39 `dbh` : pyPgSQL.PgSQL.Connection |
|
40 A database connection for the database access. |
|
41 `address` : basestring |
|
42 The e-mail address of the (new) Account. |
|
43 """ |
|
44 if not isinstance(address, EmailAddress): |
|
45 raise TypeError("Argument 'address' is not an EmailAddress") |
|
46 self._addr = address |
24 self._dbh = dbh |
47 self._dbh = dbh |
25 self._base = None |
48 self._domain = Domain(self._dbh, self._addr.domainname) |
26 if isinstance(address, EmailAddress): |
49 if not self._domain.gid: |
27 self._addr = address |
50 raise AErr(_(u"The domain '%s' doesn't exist.") % |
28 else: |
51 self._addr.domainname, NO_SUCH_DOMAIN) |
29 raise TypeError("Argument 'address' is not an EmailAddress") |
|
30 self._uid = 0 |
52 self._uid = 0 |
31 self._gid = 0 |
|
32 self._mid = 0 |
53 self._mid = 0 |
33 self._tid = 0 |
54 self._tid = 0 |
34 self._passwd = password |
55 self._passwd = None |
35 self._setAddr() |
56 self._new = True |
36 self._exists() |
57 self._load() |
37 from VirtualMailManager.Handler import Handler |
58 |
38 if self._uid < 1 and Handler.aliasExists(self._dbh, self._addr): |
59 def _load(self): |
39 # TP: Hm, what quotation marks should be used? |
60 """Load 'uid', 'mid' and 'tid' from the database and set _new to |
40 # If you are unsure have a look at: |
61 `False` - if the user could be found. """ |
41 # http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage |
|
42 raise AccE(_(u"There is already an alias with the address “%s”.") % |
|
43 self._addr, ERR.ALIAS_EXISTS) |
|
44 if self._uid < 1 and Handler.relocatedExists(self._dbh, self._addr): |
|
45 raise AccE( |
|
46 _(u"There is already a relocated user with the address “%s”.") % |
|
47 self._addr, ERR.RELOCATED_EXISTS) |
|
48 |
|
49 def _exists(self): |
|
50 dbc = self._dbh.cursor() |
62 dbc = self._dbh.cursor() |
51 dbc.execute( |
63 dbc.execute( |
52 "SELECT uid, mid, tid FROM users WHERE gid=%s AND local_part=%s", |
64 "SELECT uid, mid, tid FROM users WHERE gid=%s AND local_part=%s", |
53 self._gid, self._addr.localpart) |
65 self._domain.gid, self._addr.localpart) |
54 result = dbc.fetchone() |
66 result = dbc.fetchone() |
55 dbc.close() |
67 dbc.close() |
56 if result is not None: |
68 if result: |
57 self._uid, self._mid, self._tid = result |
69 self._uid, self._mid, self._tid = result |
58 return True |
70 self._new = False |
59 else: |
71 |
60 return False |
72 def _set_uid(self): |
61 |
73 """Set the unique ID for the new Account.""" |
62 def _setAddr(self): |
74 assert self._uid == 0 |
63 dom = Domain(self._dbh, self._addr.domainname) |
|
64 self._gid = dom.gid |
|
65 if self._gid == 0: |
|
66 raise AccE(_(u"The domain “%s” doesn't exist.") % |
|
67 self._addr.domainname, ERR.NO_SUCH_DOMAIN) |
|
68 self._base = dom.directory |
|
69 self._tid = dom.transport.tid |
|
70 |
|
71 def _setID(self): |
|
72 dbc = self._dbh.cursor() |
75 dbc = self._dbh.cursor() |
73 dbc.execute("SELECT nextval('users_uid')") |
76 dbc.execute("SELECT nextval('users_uid')") |
74 self._uid = dbc.fetchone()[0] |
77 self._uid = dbc.fetchone()[0] |
75 dbc.close() |
78 dbc.close() |
76 |
79 |
77 def _prepare(self, maillocation): |
80 def _prepare(self, maillocation): |
78 if not known_format(maillocation): |
81 """Check and set different attributes - before we store the |
79 raise AccE(_(u'Unknown mail_location mailbox format: %r') % |
82 information in the database.""" |
80 maillocation, ERR.UNKNOWN_MAILLOCATION_NAME) |
83 if not known_format(maillocation): |
81 self._setID() |
84 raise AErr(_(u'Unknown mail_location mailbox format: %r') % |
|
85 maillocation, UNKNOWN_MAILLOCATION_NAME) |
82 self._mid = MailLocation(format=maillocation).mid |
86 self._mid = MailLocation(format=maillocation).mid |
83 |
87 if not self._tid: |
84 def _switchState(self, state, dcvers, service): |
88 self._tid = self._domain.tid |
85 if not isinstance(state, bool): |
89 self._set_uid() |
86 return False |
90 |
87 if not service in (None, 'all', 'imap', 'pop3', 'sieve', 'smtp'): |
91 def _switch_state(self, state, dcvers, service): |
88 raise AccE(_(u"Unknown service “%s”.") % service, |
92 """Switch the state of the Account's services on or off. See |
89 ERR.UNKNOWN_SERVICE) |
93 Account.enable()/Account.disable() for more information.""" |
90 if self._uid < 1: |
94 self._chk_state() |
91 raise AccE(_(u"The account “%s” doesn't exist.") % self._addr, |
95 if service not in (None, 'all', 'imap', 'pop3', 'sieve', 'smtp'): |
92 ERR.NO_SUCH_ACCOUNT) |
96 raise AErr(_(u"Unknown service: '%s'.") % service, UNKNOWN_SERVICE) |
93 if dcvers > 11: |
97 if dcvers > 11: |
94 sieve_col = 'sieve' |
98 sieve_col = 'sieve' |
95 else: |
99 else: |
96 sieve_col = 'managesieve' |
100 sieve_col = 'managesieve' |
97 if service in ('smtp', 'pop3', 'imap'): |
101 if service in ('smtp', 'pop3', 'imap'): |
98 sql = 'UPDATE users SET %s = %s WHERE uid = %d' % (service, state, |
102 sql = 'UPDATE users SET %s = %s WHERE uid = %d' % (service, state, |
99 self._uid) |
103 self._uid) |
100 elif service == 'sieve': |
104 elif service == 'sieve': |
101 sql = 'UPDATE users SET %s = %s WHERE uid = %d' % (sieve_col, |
105 sql = 'UPDATE users SET %s = %s WHERE uid = %d' % (sieve_col, |
102 state, self._uid) |
106 state, |
|
107 self._uid) |
103 else: |
108 else: |
104 sql = 'UPDATE users SET smtp = %(s)s, pop3 = %(s)s, imap = %(s)s,\ |
109 sql = 'UPDATE users SET smtp = %(s)s, pop3 = %(s)s, imap = %(s)s,\ |
105 %(col)s = %(s)s WHERE uid = %(uid)d' % { |
110 %(col)s = %(s)s WHERE uid = %(uid)d' % \ |
106 's': state, 'col': sieve_col, 'uid': self._uid} |
111 {'s': state, 'col': sieve_col, 'uid': self._uid} |
107 dbc = self._dbh.cursor() |
112 dbc = self._dbh.cursor() |
108 dbc.execute(sql) |
113 dbc.execute(sql) |
109 if dbc.rowcount > 0: |
114 if dbc.rowcount > 0: |
110 self._dbh.commit() |
115 self._dbh.commit() |
111 dbc.close() |
116 dbc.close() |
112 |
117 |
113 def __aliaseCount(self): |
118 def _count_aliases(self): |
114 dbc = self._dbh.cursor() |
119 """Count all alias addresses where the destination address is the |
115 q = "SELECT COUNT(destination) FROM alias WHERE destination = '%s'"\ |
120 address of the Account.""" |
116 % self._addr |
121 dbc = self._dbh.cursor() |
117 dbc.execute(q) |
122 sql = "SELECT COUNT(destination) FROM alias WHERE destination = '%s'"\ |
|
123 % self._addr |
|
124 dbc.execute(sql) |
118 a_count = dbc.fetchone()[0] |
125 a_count = dbc.fetchone()[0] |
119 dbc.close() |
126 dbc.close() |
120 return a_count |
127 return a_count |
121 |
128 |
122 def setPassword(self, password): |
129 def _chk_state(self): |
|
130 """Raise an AccountError if the Account is new - not yet saved in the |
|
131 database.""" |
|
132 if self._new: |
|
133 raise AErr(_(u"The account '%s' doesn't exist.") % self._addr, |
|
134 NO_SUCH_ACCOUNT) |
|
135 |
|
136 @property |
|
137 def domain_directory(self): |
|
138 """The directory of the domain the Account belongs to.""" |
|
139 return self._domain.directory |
|
140 |
|
141 @property |
|
142 def gid(self): |
|
143 """The Account's group ID.""" |
|
144 return self._domain.gid |
|
145 |
|
146 @property |
|
147 def home(self): |
|
148 """The Account's home directory.""" |
|
149 return '%s/%s' % (self._domain.directory, self._uid) |
|
150 |
|
151 @property |
|
152 def uid(self): |
|
153 """The Account's unique ID.""" |
|
154 return self._uid |
|
155 |
|
156 def set_password(self, password): |
|
157 """Set a password for the new Account. |
|
158 |
|
159 If you want to update the password of an existing Account use |
|
160 Account.modify(). |
|
161 |
|
162 Argument: |
|
163 |
|
164 `password` : basestring |
|
165 The hashed password for the new Account.""" |
123 self._passwd = password |
166 self._passwd = password |
124 |
167 |
125 def getUID(self): |
168 def set_transport(self, transport): |
126 return self._uid |
169 """Set the transport for the new Account. |
127 |
170 |
128 def getGID(self): |
171 If you want to update the transport of an existing Account use |
129 return self._gid |
172 Account.modify(). |
130 |
173 |
131 def getDir(self, directory): |
174 Argument: |
132 if directory == 'domain': |
175 |
133 return '%s' % self._base |
176 `transport` : basestring |
134 elif directory == 'home': |
177 The string representation of the transport, e.g.: 'dovecot:' |
135 return '%s/%i' % (self._base, self._uid) |
178 """ |
|
179 self._tid = Transport(self._dbh, transport=transport).tid |
136 |
180 |
137 def enable(self, dcvers, service=None): |
181 def enable(self, dcvers, service=None): |
138 self._switchState(True, dcvers, service) |
182 """Enable a/all service/s for the Account. |
|
183 |
|
184 Possible values for the *service* are: 'imap', 'pop3', 'sieve' and |
|
185 'smtp'. When all services should be enabled, use 'all' or the |
|
186 default value `None`. |
|
187 |
|
188 Arguments: |
|
189 |
|
190 `dcvers` : int |
|
191 The concatenated major and minor version number from |
|
192 `dovecot --version`. |
|
193 `service` : basestring |
|
194 The name of a service ('imap', 'pop3', 'smtp', 'sieve'), 'all' |
|
195 or `None`. |
|
196 """ |
|
197 self._switch_state(True, dcvers, service) |
139 |
198 |
140 def disable(self, dcvers, service=None): |
199 def disable(self, dcvers, service=None): |
141 self._switchState(False, dcvers, service) |
200 """Disable a/all service/s for the Account. |
|
201 |
|
202 For more information see: Account.enable().""" |
|
203 self._switch_state(False, dcvers, service) |
142 |
204 |
143 def save(self, maillocation, dcvers, smtp, pop3, imap, sieve): |
205 def save(self, maillocation, dcvers, smtp, pop3, imap, sieve): |
144 if self._uid < 1: |
206 """Save the new Account in the database. |
145 if dcvers > 11: |
207 |
146 sieve_col = 'sieve' |
208 Arguments: |
147 else: |
209 |
148 sieve_col = 'managesieve' |
210 `maillocation` : basestring |
149 self._prepare(maillocation) |
211 The mailbox format of the mail_location: 'maildir', 'mbox', |
150 sql = "INSERT INTO users (local_part, passwd, uid, gid, mid, tid,\ |
212 'dbox' or 'mdbox'. |
|
213 `dcvers` : int |
|
214 The concatenated major and minor version number from |
|
215 `dovecot --version`. |
|
216 `smtp, pop3, imap, sieve` : bool |
|
217 Indicates if the user of the Account should be able to use this |
|
218 services. |
|
219 """ |
|
220 if not self._new: |
|
221 raise AErr(_(u"The account '%s' already exists.") % self._addr, |
|
222 ACCOUNT_EXISTS) |
|
223 if not self._passwd: |
|
224 raise AErr(_(u"No password set for '%s'.") % self._addr, |
|
225 ACCOUNT_MISSING_PASSWORD) |
|
226 assert all(isinstance(service, bool) for service in (smtp, pop3, imap, |
|
227 sieve)) |
|
228 if dcvers > 11: |
|
229 sieve_col = 'sieve' |
|
230 else: |
|
231 sieve_col = 'managesieve' |
|
232 self._prepare(maillocation) |
|
233 sql = "INSERT INTO users (local_part, passwd, uid, gid, mid, tid,\ |
151 smtp, pop3, imap, %s) VALUES ('%s', '%s', %d, %d, %d, %d, %s, %s, %s, %s)" % ( |
234 smtp, pop3, imap, %s) VALUES ('%s', '%s', %d, %d, %d, %d, %s, %s, %s, %s)" % ( |
152 sieve_col, self._addr.localpart, self._passwd, self._uid, |
235 sieve_col, self._addr.localpart, self._passwd, self._uid, |
153 self._gid, self._mid, self._tid, smtp, pop3, imap, sieve) |
236 self._domain.gid, self._mid, self._tid, smtp, pop3, imap, sieve) |
154 dbc = self._dbh.cursor() |
237 dbc = self._dbh.cursor() |
155 dbc.execute(sql) |
238 dbc.execute(sql) |
156 self._dbh.commit() |
239 self._dbh.commit() |
157 dbc.close() |
240 dbc.close() |
158 else: |
241 self._new = False |
159 raise AccE(_(u'The account “%s” already exists.') % self._addr, |
242 |
160 ERR.ACCOUNT_EXISTS) |
243 def modify(self, field, value): |
161 |
244 """Update the Account's *field* to the new *value*. |
162 def modify(self, what, value): |
245 |
163 if self._uid == 0: |
246 Possible values for *filed* are: 'name', 'password' and |
164 raise AccE(_(u"The account “%s” doesn't exist.") % self._addr, |
247 'transport'. *value* is the *field*'s new value. |
165 ERR.NO_SUCH_ACCOUNT) |
248 |
166 if what not in ['name', 'password', 'transport']: |
249 Arguments: |
167 return False |
250 |
168 dbc = self._dbh.cursor() |
251 `field` : basestring |
169 if what == 'password': |
252 The attribute name: 'name', 'password' or 'transport' |
|
253 `value` : basestring |
|
254 The new value of the attribute. The password is expected as a |
|
255 hashed password string. |
|
256 """ |
|
257 if field not in ('name', 'password', 'transport'): |
|
258 raise AErr(_(u"Unknown field: '%s'") % field, INVALID_AGUMENT) |
|
259 self._chk_state() |
|
260 dbc = self._dbh.cursor() |
|
261 if field == 'password': |
170 dbc.execute('UPDATE users SET passwd = %s WHERE uid = %s', |
262 dbc.execute('UPDATE users SET passwd = %s WHERE uid = %s', |
171 value, self._uid) |
263 value, self._uid) |
172 elif what == 'transport': |
264 elif field == 'transport': |
173 self._tid = Transport(self._dbh, transport=value).tid |
265 self._tid = Transport(self._dbh, transport=value).tid |
174 dbc.execute('UPDATE users SET tid = %s WHERE uid = %s', |
266 dbc.execute('UPDATE users SET tid = %s WHERE uid = %s', |
175 self._tid, self._uid) |
267 self._tid, self._uid) |
176 else: |
268 else: |
177 dbc.execute('UPDATE users SET name = %s WHERE uid = %s', |
269 dbc.execute('UPDATE users SET name = %s WHERE uid = %s', |
178 value, self._uid) |
270 value, self._uid) |
179 if dbc.rowcount > 0: |
271 if dbc.rowcount > 0: |
180 self._dbh.commit() |
272 self._dbh.commit() |
181 dbc.close() |
273 dbc.close() |
182 |
274 |
183 def getInfo(self, dcvers): |
275 def get_info(self, dcvers): |
|
276 """Returns a dict with some information about the Account. |
|
277 |
|
278 The keys of the dict are: 'address', 'gid', 'home', 'imap' |
|
279 'mail_location', 'name', 'pop3', 'sieve', 'smtp', transport' and |
|
280 'uid'. |
|
281 |
|
282 Argument: |
|
283 |
|
284 `dcvers` : int |
|
285 The concatenated major and minor version number from |
|
286 `dovecot --version`. |
|
287 """ |
|
288 self._chk_state() |
184 if dcvers > 11: |
289 if dcvers > 11: |
185 sieve_col = 'sieve' |
290 sieve_col = 'sieve' |
186 else: |
291 else: |
187 sieve_col = 'managesieve' |
292 sieve_col = 'managesieve' |
188 sql = 'SELECT name, uid, gid, mid, tid, smtp, pop3, imap, %s\ |
293 sql = 'SELECT name, uid, gid, mid, tid, smtp, pop3, imap, %s\ |
189 FROM users WHERE uid = %d' % (sieve_col, self._uid) |
294 FROM users WHERE uid = %d' % (sieve_col, self._uid) |
190 dbc = self._dbh.cursor() |
295 dbc = self._dbh.cursor() |
191 dbc.execute(sql) |
296 dbc.execute(sql) |
192 info = dbc.fetchone() |
297 info = dbc.fetchone() |
193 dbc.close() |
298 dbc.close() |
194 if info is None: |
299 if info: |
195 raise AccE(_(u"The account “%s” doesn't exist.") % self._addr, |
300 keys = ('name', 'uid', 'gid', 'mid', 'transport', 'smtp', |
196 ERR.NO_SUCH_ACCOUNT) |
301 'pop3', 'imap', sieve_col) |
197 else: |
|
198 keys = ['name', 'uid', 'gid', 'mid', 'transport', 'smtp', |
|
199 'pop3', 'imap', sieve_col] |
|
200 info = dict(zip(keys, info)) |
302 info = dict(zip(keys, info)) |
201 for service in ('smtp', 'pop3', 'imap', sieve_col): |
303 for service in ('smtp', 'pop3', 'imap', sieve_col): |
202 if bool(info[service]): |
304 if info[service]: |
203 # TP: A service (pop3/imap/…) is enabled/usable for a user |
305 # TP: A service (pop3/imap) is enabled/usable for a user |
204 info[service] = _('enabled') |
306 info[service] = _('enabled') |
205 else: |
307 else: |
206 # TP: A service (pop3/imap) isn't enabled/usable for a user |
308 # TP: A service (pop3/imap) isn't enabled/usable for a user |
207 info[service] = _('disabled') |
309 info[service] = _('disabled') |
208 info['address'] = self._addr |
310 info['address'] = self._addr |
209 info['home'] = '%s/%s' % (self._base, info['uid']) |
311 info['home'] = '%s/%s' % (self._domain.directory, info['uid']) |
210 info['mail_location'] = MailLocation(mid=info['mid']).mail_location |
312 info['mail_location'] = MailLocation(mid=info['mid']).mail_location |
211 info['transport'] = Transport(self._dbh, |
313 info['transport'] = Transport(self._dbh, |
212 tid=info['transport']).transport |
314 tid=info['transport']).transport |
|
315 del info['mid'] |
213 return info |
316 return info |
214 |
317 # nearly impossible‽ |
215 def getAliases(self): |
318 raise AErr(_(u"Couldn't fetch information for account: '%s'") \ |
|
319 % self._addr, NO_SUCH_ACCOUNT) |
|
320 |
|
321 def get_aliases(self): |
|
322 """Return a list with all alias e-mail addresses, whose destination |
|
323 is the address of the Account.""" |
|
324 self._chk_state() |
216 dbc = self._dbh.cursor() |
325 dbc = self._dbh.cursor() |
217 dbc.execute("SELECT address ||'@'|| domainname FROM alias, domain_name\ |
326 dbc.execute("SELECT address ||'@'|| domainname FROM alias, domain_name\ |
218 WHERE destination = %s AND domain_name.gid = alias.gid\ |
327 WHERE destination = %s AND domain_name.gid = alias.gid\ |
219 AND domain_name.is_primary ORDER BY address", str(self._addr)) |
328 AND domain_name.is_primary ORDER BY address", str(self._addr)) |
220 addresses = dbc.fetchall() |
329 addresses = dbc.fetchall() |
221 dbc.close() |
330 dbc.close() |
222 aliases = [] |
331 aliases = [] |
223 if len(addresses) > 0: |
332 if addresses: |
224 aliases = [alias[0] for alias in addresses] |
333 aliases = [alias[0] for alias in addresses] |
225 return aliases |
334 return aliases |
226 |
335 |
227 def delete(self, delalias): |
336 def delete(self, delalias): |
228 if self._uid < 1: |
337 """Delete the Account from the database. |
229 raise AccE(_(u"The account “%s” doesn't exist.") % self._addr, |
338 |
230 ERR.NO_SUCH_ACCOUNT) |
339 Argument: |
|
340 |
|
341 `delalias` : basestring |
|
342 if the values of delalias is 'delalias', all aliases, which |
|
343 points to the Account, will be also deleted.""" |
|
344 self._chk_state() |
231 dbc = self._dbh.cursor() |
345 dbc = self._dbh.cursor() |
232 if delalias == 'delalias': |
346 if delalias == 'delalias': |
233 dbc.execute('DELETE FROM users WHERE uid= %s', self._uid) |
347 dbc.execute('DELETE FROM users WHERE uid= %s', self._uid) |
234 u_rc = dbc.rowcount |
|
235 # delete also all aliases where the destination address is the same |
348 # delete also all aliases where the destination address is the same |
236 # as for this account. |
349 # as for this account. |
237 dbc.execute("DELETE FROM alias WHERE destination = %s", |
350 dbc.execute("DELETE FROM alias WHERE destination = %s", |
238 str(self._addr)) |
351 str(self._addr)) |
239 if u_rc > 0 or dbc.rowcount > 0: |
352 self._dbh.commit() |
240 self._dbh.commit() |
353 else: # check first for aliases |
241 else: # check first for aliases |
354 a_count = self._count_aliases() |
242 a_count = self.__aliaseCount() |
|
243 if a_count == 0: |
355 if a_count == 0: |
244 dbc.execute('DELETE FROM users WHERE uid = %s', self._uid) |
356 dbc.execute('DELETE FROM users WHERE uid = %s', self._uid) |
245 if dbc.rowcount > 0: |
357 self._dbh.commit() |
246 self._dbh.commit() |
|
247 else: |
358 else: |
248 dbc.close() |
359 dbc.close() |
249 raise AccE( |
360 raise AErr(_(u"There are %(count)d aliases with the \ |
250 _(u"There are %(count)d aliases with the destination address\ |
361 destination address '%(address)s'.") % \ |
251 “%(address)s”.") % {'count': a_count, 'address': self._addr}, |
362 {'count': a_count, 'address': self._addr}, |
252 ERR.ALIAS_PRESENT) |
363 ALIAS_PRESENT) |
253 dbc.close() |
364 dbc.close() |
254 |
365 |
255 |
366 |
256 def getAccountByID(uid, dbh): |
367 def getAccountByID(uid, dbh): |
|
368 """Search an Account by its UID. |
|
369 |
|
370 Argument: |
|
371 |
|
372 `uid` : long |
|
373 The Account unique ID. |
|
374 `dbh` : pyPgSQL.PgSQL.Connection |
|
375 a database connection for the database access. |
|
376 """ |
257 try: |
377 try: |
258 uid = long(uid) |
378 uid = long(uid) |
259 except ValueError: |
379 except ValueError: |
260 raise AccE(_(u'uid must be an int/long.'), ERR.INVALID_AGUMENT) |
380 raise AErr(_(u'UID must be an int/long.'), INVALID_AGUMENT) |
261 if uid < 1: |
381 if uid < 1: |
262 raise AccE(_(u'uid must be greater than 0.'), ERR.INVALID_AGUMENT) |
382 raise AErr(_(u'UID must be greater than 0.'), INVALID_AGUMENT) |
263 dbc = dbh.cursor() |
383 dbc = dbh.cursor() |
264 dbc.execute("SELECT local_part||'@'|| domain_name.domainname AS address,\ |
384 dbc.execute("SELECT local_part||'@'|| domain_name.domainname AS address,\ |
265 uid, users.gid FROM users LEFT JOIN domain_name ON (domain_name.gid \ |
385 uid, users.gid FROM users LEFT JOIN domain_name ON (domain_name.gid \ |
266 = users.gid AND is_primary) WHERE uid = %s;", uid) |
386 = users.gid AND is_primary) WHERE uid = %s;", uid) |
267 info = dbc.fetchone() |
387 info = dbc.fetchone() |
268 dbc.close() |
388 dbc.close() |
269 if info is None: |
389 if not info: |
270 raise AccE(_(u"There is no account with the UID “%d”.") % uid, |
390 raise AErr(_(u"There is no account with the UID '%d'.") % uid, |
271 ERR.NO_SUCH_ACCOUNT) |
391 NO_SUCH_ACCOUNT) |
272 keys = ['address', 'uid', 'gid'] |
392 info = dict(zip(('address', 'uid', 'gid'), info)) |
273 info = dict(zip(keys, info)) |
|
274 return info |
393 return info |
275 |
394 |
276 |
395 |
277 del _ |
396 del _ |