140
140
Raises a DBException if the dictionary contains invalid fields.
142
142
if not DB.check_dict(dict, tablefields, disallowed):
143
raise DBException("Supplied dictionary contains invalid fields.")
143
extras = set(dict.keys()) - tablefields
144
raise DBException("Supplied dictionary contains invalid fields. (%s)" % (repr(extras)))
144
145
# Build two lists concurrently: field names and values, as SQL strings
173
174
if (not (DB.check_dict(primarydict, primary_keys, must=True)
174
175
and DB.check_dict(updatedict, tablefields, disallowed_update))):
175
raise DBException("Supplied dictionary contains invalid or "
176
raise DBException("Supplied dictionary contains invalid or missing fields (1).")
177
177
# Make a list of SQL fragments of the form "field = 'new value'"
178
178
# These fragments are ALREADY-ESCAPED
199
199
primarydict, tablename, primary_keys: See update.
201
201
if not DB.check_dict(primarydict, primary_keys, must=True):
202
raise DBException("Supplied dictionary contains invalid or "
202
raise DBException("Supplied dictionary contains invalid or missing fields (2).")
205
204
for k,v in primarydict.items():
206
205
wherelist.append("%s = %s" % (k, _escape(v)))
225
224
primary_keys is indeed the primary key).
227
226
if not DB.check_dict(primarydict, primary_keys, must=True):
228
raise DBException("Supplied dictionary contains invalid or "
227
raise DBException("Supplied dictionary contains invalid or missing fields (3).")
231
229
for k,v in primarydict.items():
232
230
wherelist.append("%s = %s" % (k, _escape(v)))
289
287
login_primary = frozenset(["login"])
290
288
login_fields_list = [
291
289
"login", "passhash", "state", "unixid", "email", "nick", "fullname",
292
"rolenm", "studentid", "acct_exp", "pass_exp", "last_login"
290
"rolenm", "studentid", "acct_exp", "pass_exp", "last_login", "svn_pass"
294
292
login_fields = frozenset(login_fields_list)
295
# Do not return passhash when reading from the DB
296
login_getfields = login_fields - frozenset(["passhash"])
298
def create_user(self, dry=False, **kwargs):
294
def create_user(self, user_obj=None, dry=False, **kwargs):
299
295
"""Creates a user login entry in the database.
296
Two ways to call this - passing a user object, or passing
297
all fields as separate arguments.
299
Either pass a "user_obj" as the first argument (in which case other
300
fields will be ignored), or pass all fields as arguments.
300
302
All user fields are to be passed as args. The argument names
301
303
are the field names of the "login" table of the DB schema.
302
304
However, instead of supplying a "passhash", you must supply a
307
309
invalid keys or is missing required keys.
309
311
if 'passhash' in kwargs:
310
raise DBException("Supplied arguments include passhash (invalid).")
312
raise DBException("Supplied arguments include passhash (invalid) (1).")
311
313
# Make a copy of the dict. Change password to passhash (hashing it),
312
314
# and set 'state' to "no_agreement".
313
kwargs = copy.copy(kwargs)
314
if 'password' in kwargs:
315
kwargs['passhash'] = _passhash(kwargs['password'])
316
del kwargs['password']
317
kwargs['state'] = "no_agreement"
317
fields = copy.copy(kwargs)
319
# Use the user object
320
fields = dict(user_obj)
321
if 'password' in fields:
322
fields['passhash'] = _passhash(fields['password'])
323
del fields['password']
325
# Convert role to rolenm
326
fields['rolenm'] = str(user_obj.role)
329
fields['state'] = "no_agreement"
330
# else, we'll trust the user, but it SHOULD be "no_agreement"
331
# (We can't change it because then the user object would not
333
if 'local_password' in fields:
334
del fields['local_password']
318
335
# Execute the query.
319
return self.insert(kwargs, "login", self.login_fields, dry=dry)
336
return self.insert(fields, "login", self.login_fields, dry=dry)
321
338
def update_user(self, login, dry=False, **kwargs):
322
339
"""Updates fields of a particular user. login is the name of the user
345
362
def get_user(self, login, dry=False):
346
"""Given a login, returns a dictionary of the user's DB fields,
347
excluding the passhash field.
363
"""Given a login, returns a User object containing details looked up
349
366
Raises a DBException if the login is not found in the DB.
351
return self.get_single({"login": login}, "login",
352
self.login_getfields, self.login_primary,
368
userdict = self.get_single({"login": login}, "login",
369
self.login_fields, self.login_primary,
353
370
error_notfound="get_user: No user with that login name", dry=dry)
372
return userdict # Query string
373
# Package into a User object
374
return user.User(**userdict)
355
376
def get_users(self, dry=False):
356
"""Returns a list of all users. The list elements are a dictionary of
357
the user's DB fields, excluding the passhash field.
377
"""Returns a list of all users in the DB, as User objects.
359
return self.get_all("login", self.login_getfields, dry=dry)
379
userdicts = self.get_all("login", self.login_fields, dry=dry)
381
return userdicts # Query string
382
# Package into User objects
383
return [user.User(**userdict) for userdict in userdicts]
361
385
def user_authenticate(self, login, password, dry=False):
362
386
"""Performs a password authentication on a user. Returns True if
363
387
"passhash" is the correct passhash for the given login, False
388
if the passhash does not match the password in the DB,
389
and None if the passhash in the DB is NULL.
365
390
Also returns False if the login does not exist (so if you want to
366
391
differentiate these cases, use get_user and catch an exception).
368
query = ("SELECT login FROM login "
369
"WHERE login = '%s' AND passhash = %s;"
370
% (login, _escape(_passhash(password))))
393
query = "SELECT passhash FROM login WHERE login = '%s';" % login
371
394
if dry: return query
372
395
result = self.db.query(query)
373
# If one row was returned, succeed.
374
# Otherwise, fail to authenticate.
375
return result.ntuples() == 1
396
if result.ntuples() == 1:
397
# Valid username. Check password.
398
passhash = result.getresult()[0][0]
401
return _passhash(password) == passhash
378
406
"""Close the DB connection. Do not call any other functions after