"Fossies" - the Fresh Open Source Software Archive

Member "roundup-2.0.0/roundup/xmlrpc.py" (1 Jan 2020, 8160 Bytes) of package /linux/www/roundup-2.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "xmlrpc.py": 1.6.1_vs_2.0.0.

    1 #
    2 # Copyright (C) 2007 Stefan Seefeld
    3 # All rights reserved.
    4 # For license terms see the file COPYING.txt.
    5 #
    6 
    7 import logging
    8 from roundup import hyperdb
    9 from roundup.exceptions import Unauthorised, UsageError
   10 from roundup.date import Date, Range, Interval
   11 from roundup import actions
   12 from roundup.anypy.strings import us2s
   13 from traceback import format_exc
   14 from roundup.anypy import xmlrpc_
   15 SimpleXMLRPCDispatcher = xmlrpc_.server.SimpleXMLRPCDispatcher
   16 Binary = xmlrpc_.client.Binary
   17 
   18 
   19 def translate(value):
   20     """Translate value to becomes valid for XMLRPC transmission."""
   21 
   22     if isinstance(value, (Date, Range, Interval)):
   23         return repr(value)
   24     elif type(value) is list:
   25         return [translate(v) for v in value]
   26     elif type(value) is tuple:
   27         return tuple([translate(v) for v in value])
   28     elif type(value) is dict:
   29         return dict([[translate(k), translate(value[k])] for k in value])
   30     else:
   31         return value
   32 
   33 
   34 def props_from_args(db, cl, args, itemid=None):
   35     """Construct a list of properties from the given arguments,
   36     and return them after validation."""
   37 
   38     props = {}
   39     for arg in args:
   40         if isinstance(arg, Binary):
   41             arg = arg.data
   42         try:
   43             key, value = arg.split('=', 1)
   44         except ValueError:
   45             raise UsageError('argument "%s" not propname=value' % arg)
   46         key = us2s(key)
   47         value = us2s(value)
   48         if value:
   49             try:
   50                 props[key] = hyperdb.rawToHyperdb(db, cl, itemid,
   51                                                   key, value)
   52             except hyperdb.HyperdbValueError as message:
   53                 raise UsageError(message)
   54         else:
   55             # If we're syncing a file the contents may not be None
   56             if key == 'content':
   57                 props[key] = ''
   58             else:
   59                 props[key] = None
   60 
   61     return props
   62 
   63 
   64 class RoundupInstance:
   65     """The RoundupInstance provides the interface accessible through
   66     the Python XMLRPC mapping."""
   67 
   68     def __init__(self, db, actions, translator):
   69 
   70         self.db = db
   71         self.actions = actions
   72         self.translator = translator
   73 
   74     def schema(self):
   75         s = {}
   76         for c in self.db.classes:
   77             cls = self.db.classes[c]
   78             props = [(n, repr(v)) for n, v in sorted(cls.properties.items())]
   79             s[c] = props
   80         return s
   81 
   82     def list(self, classname, propname=None):
   83         cl = self.db.getclass(classname)
   84         if not propname:
   85             propname = cl.labelprop()
   86         result = [cl.get(itemid, propname)
   87                   for itemid in cl.list()
   88                   if self.db.security.hasPermission('View', self.db.getuid(),
   89                                                     classname, propname,
   90                                                     itemid)
   91                   ]
   92         return result
   93 
   94     def filter(self, classname, search_matches, filterspec,
   95                sort=[], group=[]):
   96         cl = self.db.getclass(classname)
   97         uid = self.db.getuid()
   98         security = self.db.security
   99         filterspec = security.filterFilterspec(uid, classname, filterspec)
  100         sort = security.filterSortspec(uid, classname, sort)
  101         group = security.filterSortspec(uid, classname, group)
  102         result = cl.filter(search_matches, filterspec, sort=sort, group=group)
  103         check = security.hasPermission
  104         x = [id for id in result if check('View', uid, classname, itemid=id)]
  105         return x
  106 
  107     def lookup(self, classname, key):
  108         cl = self.db.getclass(classname)
  109         uid = self.db.getuid()
  110         prop = cl.getkey()
  111         search = self.db.security.hasSearchPermission
  112         access = self.db.security.hasPermission
  113         if (not search(uid, classname, prop)
  114             and not access('View', uid, classname, prop)):
  115             raise Unauthorised('Permission to lookup %s denied' % classname)
  116         return cl.lookup(key)
  117 
  118     def display(self, designator, *properties):
  119         classname, itemid = hyperdb.splitDesignator(designator)
  120         cl = self.db.getclass(classname)
  121         props = properties and list(properties) or list(cl.properties.keys())
  122         props.sort()
  123         for p in props:
  124             if not self.db.security.hasPermission('View', self.db.getuid(),
  125                                                   classname, p, itemid):
  126                 raise Unauthorised('Permission to view %s of %s denied' %
  127                                    (p, designator))
  128             result = [(prop, cl.get(itemid, prop)) for prop in props]
  129         return dict(result)
  130 
  131     def create(self, classname, *args):
  132         if not self.db.security.hasPermission('Create', self.db.getuid(),
  133                                               classname):
  134             raise Unauthorised('Permission to create %s denied' % classname)
  135 
  136         cl = self.db.getclass(classname)
  137 
  138         # convert types
  139         props = props_from_args(self.db, cl, args)
  140 
  141         # check for the key property
  142         key = cl.getkey()
  143         if key and key not in props:
  144             raise UsageError('you must provide the "%s" property.' % key)
  145 
  146         for key in props:
  147             if not self.db.security.hasPermission('Create', self.db.getuid(),
  148                                                   classname, property=key):
  149                 raise Unauthorised('Permission to create %s.%s denied' %
  150                                    (classname, key))
  151 
  152         # do the actual create
  153         try:
  154             result = cl.create(**props)
  155             self.db.commit()
  156         except (TypeError, IndexError, ValueError) as message:
  157             # The exception we get may be a real error, log the traceback
  158             # if we're debugging
  159             logger = logging.getLogger('roundup.xmlrpc')
  160             for l in format_exc().split('\n'):
  161                 logger.debug(l)
  162             raise UsageError(message)
  163         return result
  164 
  165     def set(self, designator, *args):
  166 
  167         classname, itemid = hyperdb.splitDesignator(designator)
  168         cl = self.db.getclass(classname)
  169         props = props_from_args(self.db, cl, args, itemid)  # convert types
  170         for p in props.keys():
  171             if not self.db.security.hasPermission('Edit', self.db.getuid(),
  172                                                   classname, p, itemid):
  173                 raise Unauthorised('Permission to edit %s of %s denied' %
  174                                    (p, designator))
  175         try:
  176             result = cl.set(itemid, **props)
  177             self.db.commit()
  178         except (TypeError, IndexError, ValueError) as message:
  179             # The exception we get may be a real error, log the
  180             # traceback if we're debugging
  181             logger = logging.getLogger('roundup.xmlrpc')
  182             for l in format_exc().split('\n'):
  183                 logger.debug(l)
  184             raise UsageError(message)
  185         return result
  186 
  187     builtin_actions = dict(retire=actions.Retire, restore=actions.Restore)
  188 
  189     def action(self, name, *args):
  190         """Execute a named action."""
  191 
  192         if name in self.actions:
  193             action_type = self.actions[name]
  194         elif name in self.builtin_actions:
  195             action_type = self.builtin_actions[name]
  196         else:
  197             raise Exception('action "%s" is not supported %s'
  198                             % (name, ','.join(self.actions.keys())))
  199         action = action_type(self.db, self.translator)
  200         return action.execute(*args)
  201 
  202 
  203 class RoundupDispatcher(SimpleXMLRPCDispatcher):
  204     """RoundupDispatcher bridges from cgi.client to RoundupInstance.
  205     It expects user authentication to be done."""
  206 
  207     def __init__(self, db, actions, translator,
  208                  allow_none=False, encoding=None):
  209         SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
  210         self.register_instance(RoundupInstance(db, actions, translator))
  211         self.register_multicall_functions()
  212 
  213     def dispatch(self, input):
  214         return self._marshaled_dispatch(input)
  215 
  216     def _dispatch(self, method, params):
  217 
  218         retn = SimpleXMLRPCDispatcher._dispatch(self, method, params)
  219         retn = translate(retn)
  220         return retn