~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to lib/common/db.py

  • Committer: mattgiuca
  • Date: 2008-02-29 00:40:57 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:617
Added upload panel to the topbar instead of being on the side.
browser/listing.js: Removed all upload panel generation code.
browser/__init__.py: Statically generates upload panel as part of the top bar.
browser/browser.css, js: minor.

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
import md5
37
37
import copy
38
38
 
 
39
from common import (caps, user)
 
40
 
39
41
def _escape(val):
40
42
    """Wrapper around pg.escape_string. Prepares the Python value for use in
41
43
    SQL. Returns a string, which may be safely placed verbatim into an SQL
45
47
    * int/long/float: Just converts to an unquoted string.
46
48
    * bool: Returns as "TRUE" or "FALSE", unquoted.
47
49
    * NoneType: Returns "NULL", unquoted.
 
50
    * common.caps.Role: Returns the role as a quoted, lowercase string.
48
51
    Raises a DBException if val has an unsupported type.
49
52
    """
50
53
    # "E'" is postgres's way of making "escape" strings.
62
65
    elif isinstance(val, int) or isinstance(val, long) \
63
66
        or isinstance(val, float):
64
67
        return str(val)
 
68
    elif isinstance(val, caps.Role):
 
69
        return _escape(str(val))
65
70
    else:
66
71
        raise DBException("Attempt to insert an unsupported type "
67
72
            "into the database")
89
94
    def __init__(self):
90
95
        """Connects to the database and creates a DB object.
91
96
        Takes no parameters - gets all the DB info from the configuration."""
 
97
        self.open = False
92
98
        self.db = pg.connect(dbname=conf.db_dbname, host=conf.db_host,
93
99
                port=conf.db_port, user=conf.db_user, passwd=conf.db_password)
94
100
        self.open = True
134
140
        Raises a DBException if the dictionary contains invalid fields.
135
141
        """
136
142
        if not DB.check_dict(dict, tablefields, disallowed):
137
 
            raise DBException("Supplied dictionary contains invalid fields.")
 
143
            extras = set(dict.keys()) - tablefields
 
144
            raise DBException("Supplied dictionary contains invalid fields. (%s)" % (repr(extras)))
138
145
        # Build two lists concurrently: field names and values, as SQL strings
139
146
        fieldnames = []
140
147
        values = []
166
173
        """
167
174
        if (not (DB.check_dict(primarydict, primary_keys, must=True)
168
175
            and DB.check_dict(updatedict, tablefields, disallowed_update))):
169
 
            raise DBException("Supplied dictionary contains invalid or "
170
 
                " missing fields.")
 
176
            raise DBException("Supplied dictionary contains invalid or missing fields (1).")
171
177
        # Make a list of SQL fragments of the form "field = 'new value'"
172
178
        # These fragments are ALREADY-ESCAPED
173
179
        setlist = []
193
199
        primarydict, tablename, primary_keys: See update.
194
200
        """
195
201
        if not DB.check_dict(primarydict, primary_keys, must=True):
196
 
            raise DBException("Supplied dictionary contains invalid or "
197
 
                " missing fields.")
 
202
            raise DBException("Supplied dictionary contains invalid or missing fields (2).")
198
203
        wherelist = []
199
204
        for k,v in primarydict.items():
200
205
            wherelist.append("%s = %s" % (k, _escape(v)))
219
224
            primary_keys is indeed the primary key).
220
225
        """
221
226
        if not DB.check_dict(primarydict, primary_keys, must=True):
222
 
            raise DBException("Supplied dictionary contains invalid or "
223
 
                " missing fields.")
 
227
            raise DBException("Supplied dictionary contains invalid or missing fields (3).")
224
228
        wherelist = []
225
229
        for k,v in primarydict.items():
226
230
            wherelist.append("%s = %s" % (k, _escape(v)))
254
258
        if dry: return query
255
259
        return self.db.query(query).dictresult()
256
260
 
 
261
    def start_transaction(self, dry=False):
 
262
        """Starts a DB transaction.
 
263
        Will not commit any changes until self.commit() is called.
 
264
        """
 
265
        query = "START TRANSACTION;"
 
266
        if dry: return query
 
267
        self.db.query(query)
 
268
 
 
269
    def commit(self, dry=False):
 
270
        """Commits (ends) a DB transaction.
 
271
        Commits all changes since the call to start_transaction.
 
272
        """
 
273
        query = "COMMIT;"
 
274
        if dry: return query
 
275
        self.db.query(query)
 
276
 
 
277
    def rollback(self, dry=False):
 
278
        """Rolls back (ends) a DB transaction, undoing all changes since the
 
279
        call to start_transaction.
 
280
        """
 
281
        query = "ROLLBACK;"
 
282
        if dry: return query
 
283
        self.db.query(query)
 
284
 
257
285
    # USER MANAGEMENT FUNCTIONS #
258
286
 
259
287
    login_primary = frozenset(["login"])
260
288
    login_fields_list = [
261
289
        "login", "passhash", "state", "unixid", "email", "nick", "fullname",
262
 
        "rolenm", "studentid", "acct_exp", "pass_exp", "last_login"
 
290
        "rolenm", "studentid", "acct_exp", "pass_exp", "last_login", "svn_pass"
263
291
    ]
264
292
    login_fields = frozenset(login_fields_list)
265
 
    # Do not return passhash when reading from the DB
266
 
    login_getfields = login_fields - frozenset(["passhash"])
267
293
 
268
 
    def create_user(self, dry=False, **kwargs):
 
294
    def create_user(self, user_obj=None, dry=False, **kwargs):
269
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.
 
298
 
 
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.
 
301
 
270
302
        All user fields are to be passed as args. The argument names
271
303
        are the field names of the "login" table of the DB schema.
272
304
        However, instead of supplying a "passhash", you must supply a
277
309
        invalid keys or is missing required keys.
278
310
        """
279
311
        if 'passhash' in kwargs:
280
 
            raise DBException("Supplied arguments include passhash (invalid).")
 
312
            raise DBException("Supplied arguments include passhash (invalid) (1).")
281
313
        # Make a copy of the dict. Change password to passhash (hashing it),
282
314
        # and set 'state' to "no_agreement".
283
 
        kwargs = copy.copy(kwargs)
284
 
        if 'password' in kwargs:
285
 
            kwargs['passhash'] = _passhash(kwargs['password'])
286
 
            del kwargs['password']
287
 
        kwargs['state'] = "no_agreement"
 
315
        if user_obj is None:
 
316
            # Use the kwargs
 
317
            fields = copy.copy(kwargs)
 
318
        else:
 
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']
 
324
        if 'role' in fields:
 
325
            # Convert role to rolenm
 
326
            fields['rolenm'] = str(user_obj.role)
 
327
            del fields['role']
 
328
        if user_obj is None:
 
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
 
332
            # reflect the DB).
 
333
        if 'local_password' in fields:
 
334
            del fields['local_password']
288
335
        # Execute the query.
289
 
        return self.insert(kwargs, "login", self.login_fields, dry=dry)
 
336
        return self.insert(fields, "login", self.login_fields, dry=dry)
290
337
 
291
338
    def update_user(self, login, dry=False, **kwargs):
292
339
        """Updates fields of a particular user. login is the name of the user
303
350
        with a new one.
304
351
        """
305
352
        if 'passhash' in kwargs:
306
 
            raise DBException("Supplied arguments include passhash (invalid).")
 
353
            raise DBException("Supplied arguments include passhash (invalid) (2).")
307
354
        if "password" in kwargs:
308
355
            kwargs = copy.copy(kwargs)
309
356
            kwargs['passhash'] = _passhash(kwargs['password'])
313
360
            dry=dry)
314
361
 
315
362
    def get_user(self, login, dry=False):
316
 
        """Given a login, returns a dictionary of the user's DB fields,
317
 
        excluding the passhash field.
 
363
        """Given a login, returns a User object containing details looked up
 
364
        in the DB.
318
365
 
319
366
        Raises a DBException if the login is not found in the DB.
320
367
        """
321
 
        return self.get_single({"login": login}, "login",
322
 
            self.login_getfields, self.login_primary,
 
368
        userdict = self.get_single({"login": login}, "login",
 
369
            self.login_fields, self.login_primary,
323
370
            error_notfound="get_user: No user with that login name", dry=dry)
 
371
        if dry:
 
372
            return userdict     # Query string
 
373
        # Package into a User object
 
374
        return user.User(**userdict)
324
375
 
325
376
    def get_users(self, dry=False):
326
 
        """Returns a list of all users. The list elements are a dictionary of
327
 
        the user's DB fields, excluding the passhash field.
 
377
        """Returns a list of all users in the DB, as User objects.
328
378
        """
329
 
        return self.get_all("login", self.login_getfields, dry=dry)
 
379
        userdicts = self.get_all("login", self.login_fields, dry=dry)
 
380
        if dry:
 
381
            return userdicts    # Query string
 
382
        # Package into User objects
 
383
        return [user.User(**userdict) for userdict in userdicts]
330
384
 
331
385
    def user_authenticate(self, login, password, dry=False):
332
386
        """Performs a password authentication on a user. Returns True if
333
387
        "passhash" is the correct passhash for the given login, False
334
 
        otherwise.
 
388
        if the passhash does not match the password in the DB,
 
389
        and None if the passhash in the DB is NULL.
335
390
        Also returns False if the login does not exist (so if you want to
336
391
        differentiate these cases, use get_user and catch an exception).
337
392
        """
338
 
        query = ("SELECT login FROM login "
339
 
            "WHERE login = '%s' AND passhash = %s;"
340
 
            % (login, _escape(_passhash(password))))
 
393
        query = "SELECT passhash FROM login WHERE login = '%s';" % login
341
394
        if dry: return query
342
395
        result = self.db.query(query)
343
 
        # If one row was returned, succeed.
344
 
        # Otherwise, fail to authenticate.
345
 
        return result.ntuples() == 1
 
396
        if result.ntuples() == 1:
 
397
            # Valid username. Check password.
 
398
            passhash = result.getresult()[0][0]
 
399
            if passhash is None:
 
400
                return None
 
401
            return _passhash(password) == passhash
 
402
        else:
 
403
            return False
346
404
 
347
405
    def close(self):
348
406
        """Close the DB connection. Do not call any other functions after