lukeplant_me_uk/bibleverses/web/cgi-bin/lib/bibleverses/views.py
author Luke Plant <L.Plant.98@cantab.net>
Thu Jun 05 22:30:59 2008 +0100 (2 years ago)
changeset 245 a8b99d1cd5dc
parent 212fbb422bfe42c
permissions -rwxr-xr-x
Added comment
        1 import simplejson 
        2 from urllib import unquote
        3 from bibleverses.webutils import HttpResponse, dispatch
        4 from bibleverses import db
        5 
        6 #### Error numbers ===
        7 
        8 MSG_NO_EMAIL_ADDRESS = 1
        9 MSG_NO_PASSWORD = 2
       10 MSG_EMAIL_TAKEN = 3
       11 MSG_EMAIL_NOT_FOUND = 4
       12 MSG_PASSWORD_INCORRECT = 5
       13 
       14 #### Helpers #####
       15 
       16 class JsonResponse(HttpResponse):
       17     def __init__(self, obj):
       18         super(JsonResponse, self).__init__()
       19         self.content = simplejson.dumps(obj)
       20         self.content_type = "text/javascript"
       21 
       22 def success(**kwargs):
       23     kwargs['success'] = True
       24     return JsonResponse(kwargs)
       25 
       26 def failure(**kwargs):
       27     kwargs['success'] = False
       28     return JsonResponse(kwargs)
       29 
       30 def authentication_error():
       31     return failure(error="Authentication error")
       32 
       33 ##### Decorators ######
       34 
       35 def catch_all(func):
       36     def wrapper(*args, **kwargs):
       37         try:
       38             return func(*args, **kwargs)
       39         except Exception, e:
       40             return JsonResponse({"error": str(e)})
       41     return wrapper
       42 
       43 def never_cache(func):
       44     def wrapper(*args, **kwargs):
       45         resp = func(*args, **kwargs)
       46         resp.headers['Cache-Control'] = "no-cache, no-store, private";
       47         return resp
       48     return wrapper
       49 
       50 def require_user(func):
       51     """Adds user as attribute of request object if correct creds,
       52     otherwise returns authentication_error()"""
       53     def wrapper(request, *args, **kwargs):
       54         user = get_user_from_request(request)
       55         if user is None:
       56             return authentication_error()
       57         else:
       58             request.user = user
       59             return func(request, *args, **kwargs)
       60     return wrapper
       61 
       62 ##### Model ######
       63 
       64 class User(object):
       65     def __init__(self, uid, email, password):
       66         self.id = uid
       67         self.email = email
       68         self.password = password
       69 
       70     def create(email, password):
       71         db.execute("INSERT INTO users values (NULL, %s, %s);", email, password)
       72     create = staticmethod(create)
       73 
       74     def retrieve(email):
       75         q = db.execute("SELECT id, email, password FROM users WHERE email = %s;", email)
       76         if len(q) > 0:
       77             return User(q[0][0], q[0][1], q[0][2])
       78         else:
       79             return None
       80     retrieve = staticmethod(retrieve)
       81 
       82     def checkPassword(self, password):
       83         return self.password == password
       84 
       85     def get_verses(self):
       86         return [row[0] for row in 
       87                 db.execute("SELECT verseref FROM verses WHERE userid = %s ORDER BY verseref;", self.id)]
       88 
       89     def add_verse(self, verseref):
       90         if len(db.execute("SELECT id FROM verses WHERE verseref = %s AND userid = %s;", verseref, self.id)) == 0:
       91             db.execute("INSERT INTO verses (id, userid, verseref) VALUES (NULL, %s, %s);", self.id, verseref)
       92 
       93     def delete_verse(self, verseref):
       94         db.execute("DELETE FROM verses WHERE verseref = %s AND userid = %s;", verseref, self.id)
       95 
       96 ##### View functions ####
       97 
       98 def register(request):         
       99     email = request.POST.get('email', '').strip()
      100     password = request.POST.get('password', '').strip()
      101     if len(email) == 0:
      102         retval = failure(validation=[MSG_NO_EMAIL_ADDRESS, "Email address was not supplied"])
      103     elif len(password) == 0:
      104         retval = failure(validation=[MSG_NO_PASSWORD, "Password not supplied"])
      105     else:
      106         if User.retrieve(email) is not None:
      107             retval = failure(validation=[MSG_EMAIL_TAKEN, "Email address already taken."])
      108         else:
      109             try:
      110                 User.create(email, password)
      111                 retval = success()
      112             except Exception, e:
      113                 retval = failure(error=str(e))
      114     return retval
      115 
      116 def login(request):
      117     email = request.POST.get('email', '').strip()
      118     password = request.POST.get('password', '').strip()
      119 
      120     user = User.retrieve(email)
      121     if user is not None:
      122         if user.checkPassword(password):
      123             return success()
      124         else:
      125             return failure(validation=[MSG_PASSWORD_INCORRECT, "Password is incorrect."])
      126     else:
      127         return failure(validation=[MSG_EMAIL_NOT_FOUND, "Email address not found."])
      128 
      129 def get_user_from_request(request):
      130     email =  unquote(request.get_cookie('email', ''))
      131     password = unquote(request.get_cookie('password',''))
      132     u = User.retrieve(email)
      133     if u is not None and u.checkPassword(password):
      134         return u
      135     else: 
      136         return None
      137 
      138 def verses(request):
      139     return success(verselist=request.user.get_verses())
      140 verses = require_user(verses)
      141 
      142 def addverse(request):
      143     verseref = request.POST.get('verse')
      144     if verseref is None or verseref == '':
      145         return failure()
      146     request.user.add_verse(verseref)
      147     return success(verse=verseref)
      148 addverse = require_user(addverse)
      149 
      150 def removeverse(request):
      151     verseref = request.POST.get('verse')
      152     if verseref is None or verseref == '':
      153         return failure()
      154     request.user.delete_verse(verseref)
      155     return success(verse=verseref)
      156 removeverse = require_user(removeverse)
      157 
      158 ##### Database creation/upgrade #####
      159 
      160 def initdb(request):
      161     db.execute("""
      162 CREATE TABLE users (
      163        id integer PRIMARY KEY,
      164        email text UNIQUE,
      165        password text
      166 );
      167 
      168 CREATE TABLE verses (
      169         id integer PRIMARY KEY,
      170         userid integer,
      171         verseref text,
      172         foreign key (userid) REFERENCES users(id)
      173 )
      174 
      175 
      176 """)
      177     return success()
      178 
      179 def dropdb(request):
      180     db.execute("""
      181 DROP TABLE users;
      182 DROP TABLE verses;
      183 DROP TABLE metainfo;
      184 """)
      185     return success()
      186 
      187 def upgrade1(request):
      188     try:
      189         res = db.execute("SELECT value FROM metainfo WHERE name='dbversion';");
      190     except:
      191         db.execute("""
      192 CREATE TABLE metainfo (
      193         name text PRIMARY KEY,
      194         value text
      195 )
      196 """)
      197         db.execute("INSERT INTO metainfo (name, value) VALUES ('dbversion', '2');")
      198         import sha
      199         for (email, password) in db.execute("SELECT email, password FROM users;"):
      200             db.execute("UPDATE users SET password = %s WHERE email = %s;", sha.sha(email+password).hexdigest(), email)
      201     # Otherwise don't need to upgrade
      202     return success()
      203 
      204 def debug(req):
      205     return HttpResponse(content=\
      206 """method:
      207 %r
      208 
      209 path:
      210 %r
      211 
      212 POST:
      213 %r
      214 
      215 GET:
      216 %r
      217 
      218 COOKIES:
      219 %r
      220 
      221 Environ: 
      222 %r 
      223 
      224 """ % (req.method, req.path, req.GET, req.POST, req.COOKIES, req.environ), 
      225                         content_type="text/plain")
      226 
      227 
      228 #############################################
      229 
      230 urls = [
      231     ('^/register/$',    register),
      232     ('^/login/$',       login),
      233     ('^/verses/$',      verses),
      234     ('^/addverse/$',    addverse),
      235     ('^/removeverse/$', removeverse),
      236     ('^/debug/$',       debug),
      237 #    ('^/initdb/$',      initdb),
      238 #    ('^/dropdb/$',      dropdb),
      239 #    ('^/upgrade1/$',    upgrade1),
      240 ]
      241 
      242 urls = [(regex, catch_all(never_cache(f))) for regex, f in urls]
      243 
      244 def main():
      245     dispatch(urls)