view roundup/xmlrpc.py @ 3854:f4e8dc583256

Restored subject parser regexp to the string it was before the... ...implementation of customization of it, i.e., the version from CVS revision 1.184 of mailgw.py. This makes 'testFollowupTitleMatchMultiRe' work again.
author Erik Forsberg <forsberg@users.sourceforge.net>
date Sat, 12 May 2007 16:14:54 +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 :

Roundup Issue Tracker: http://roundup-tracker.org/