Mercurial > p > roundup > code
view roundup/xmlrpc.py @ 3909:e89bcb28f683
indexargs_url force ids to int
ids appear as hyperdb.String instances, which confused indexargs_url when they
appear in the filterspec. They need to be treated as treated as integers when
generating URLs.
It feels sort of hacky to check for 'id' like this but I'm at a loss for what
else to do in this case. Suggestions are welcome :)
Maybe we should look into using some other hyperdb class to represent ids?
this fixes [SF#783492]
Some trailing whitespace also got trimmed.
| author | Justus Pendleton <jpend@users.sourceforge.net> |
|---|---|
| date | Tue, 18 Sep 2007 16:59:42 +0000 |
| parents | c31da624ae3b |
| children | 3c3077582c16 |
line wrap: on
line source
# # Copyright (C) 2007 Stefan Seefeld # All rights reserved. # For license terms see the file COPYING.txt. # import base64 import roundup.instance from roundup import hyperdb from roundup.cgi.exceptions import * from roundup.admin import UsageError from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler class RoundupRequestHandler(SimpleXMLRPCRequestHandler): """A SimpleXMLRPCRequestHandler with support for basic HTTP Authentication.""" def do_POST(self): """Extract username and password from authorization header.""" # Try to extract username and password from HTTP Authentication. self.username = None self.password = None authorization = self.headers.get('authorization', ' ') scheme, challenge = authorization.split(' ', 1) if scheme.lower() == 'basic': decoded = base64.decodestring(challenge) self.username, self.password = decoded.split(':') SimpleXMLRPCRequestHandler.do_POST(self) def _dispatch(self, method, params): """Inject username and password into function arguments.""" # Add username and password to function arguments params = [self.username, self.password] + list(params) return self.server._dispatch(method, params) class RoundupRequest: """Little helper class to handle common per-request tasks such as authentication and login.""" def __init__(self, tracker, username, password): """Open the database for the given tracker, using the given username and password.""" self.tracker = tracker self.db = self.tracker.open('admin') try: userid = self.db.user.lookup(username) except KeyError: # No such user self.db.close() raise Unauthorised, 'Invalid user.' stored = self.db.user.get(userid, 'password') if stored != password: # Wrong password self.db.close() raise Unauthorised, 'Invalid user.' self.db.setCurrentUser(username) def close(self): """Close the database, after committing any changes, if needed.""" if getattr(self, 'db'): try: if self.db.transactions: self.db.commit() finally: self.db.close() def get_class(self, classname): """Return the class for the given classname.""" try: return self.db.getclass(classname) except KeyError: raise UsageError, 'no such class "%s"'%classname def props_from_args(self, cl, args): """Construct a list of properties from the given arguments, and return them after validation.""" props = {} for arg in args: if arg.find('=') == -1: raise UsageError, 'argument "%s" not propname=value'%arg l = arg.split('=') if len(l) < 2: raise UsageError, 'argument "%s" not propname=value'%arg key, value = l[0], '='.join(l[1:]) if value: try: props[key] = hyperdb.rawToHyperdb(self.db, cl, None, key, value) except hyperdb.HyperdbValueError, message: raise UsageError, message else: props[key] = None return props #The server object class RoundupServer: """The RoundupServer provides the interface accessible through the Python XMLRPC mapping. All methods take an additional username and password argument so each request can be authenticated.""" def __init__(self, tracker, verbose = False): self.tracker = roundup.instance.open(tracker) self.verbose = verbose def list(self, username, password, classname, propname = None): r = RoundupRequest(self.tracker, username, password) cl = r.get_class(classname) if not propname: propname = cl.labelprop() result = [cl.get(id, propname) for id in cl.list()] r.close() return result def display(self, username, password, designator, *properties): r = RoundupRequest(self.tracker, username, password) classname, nodeid = hyperdb.splitDesignator(designator) cl = r.get_class(classname) props = properties and list(properties) or cl.properties.keys() props.sort() result = [(property, cl.get(nodeid, property)) for property in props] r.close() return dict(result) def create(self, username, password, classname, *args): r = RoundupRequest(self.tracker, username, password) cl = r.get_class(classname) # convert types props = r.props_from_args(cl, args) # check for the key property key = cl.getkey() if key and not props.has_key(key): raise UsageError, 'you must provide the "%s" property.'%key # do the actual create try: try: result = cl.create(**props) except (TypeError, IndexError, ValueError), message: raise UsageError, message finally: r.close() return result def set(self, username, password, designator, *args): r = RoundupRequest(self.tracker, username, password) classname, itemid = hyperdb.splitDesignator(designator) cl = r.get_class(classname) # convert types props = r.props_from_args(cl, args) try: try: cl.set(itemid, **props) except (TypeError, IndexError, ValueError), message: raise UsageError, message finally: r.close() # vim: set et sts=4 sw=4 :
