45552872576c75a94f200567e1ca2f5d961d6d1b
1 #
2 # Copyright (C) 2007 Stefan Seefeld
3 # All rights reserved.
4 # For license terms see the file COPYING.txt.
5 #
7 from roundup import hyperdb
8 from roundup.cgi.exceptions import *
9 from roundup.exceptions import UsageError
10 from roundup.date import Date, Range, Interval
11 from SimpleXMLRPCServer import *
13 def translate(value):
14 """Translate value to becomes valid for XMLRPC transmission."""
16 if isinstance(value, (Date, Range, Interval)):
17 return repr(value)
18 elif type(value) is list:
19 return [translate(v) for v in value]
20 elif type(value) is tuple:
21 return tuple([translate(v) for v in value])
22 elif type(value) is dict:
23 return dict([[translate(k), translate(value[k])] for k in value])
24 else:
25 return value
28 def props_from_args(db, cl, args, itemid=None):
29 """Construct a list of properties from the given arguments,
30 and return them after validation."""
32 props = {}
33 for arg in args:
34 if arg.find('=') == -1:
35 raise UsageError, 'argument "%s" not propname=value'%arg
36 l = arg.split('=')
37 if len(l) < 2:
38 raise UsageError, 'argument "%s" not propname=value'%arg
39 key, value = l[0], '='.join(l[1:])
40 if value:
41 try:
42 props[key] = hyperdb.rawToHyperdb(db, cl, itemid,
43 key, value)
44 except hyperdb.HyperdbValueError, message:
45 raise UsageError, message
46 else:
47 props[key] = None
49 return props
51 class RoundupInstance:
52 """The RoundupInstance provides the interface accessible through
53 the Python XMLRPC mapping."""
55 def __init__(self, db, translator):
57 self.db = db
58 self.userid = db.getuid()
59 self.translator = translator
61 def list(self, classname, propname=None):
62 cl = self.db.getclass(classname)
63 if not propname:
64 propname = cl.labelprop()
65 result = [cl.get(itemid, propname)
66 for itemid in cl.list()
67 if self.db.security.hasPermission('View', self.db.getuid(),
68 classname, propname, itemid)
69 ]
70 return result
72 def filter(self, classname, search_matches, filterspec,
73 sort=[], group=[]):
74 cl = self.db.getclass(classname)
75 result = cl.filter(search_matches, filterspec, sort=sort, group=group)
76 return result
78 def display(self, designator, *properties):
79 classname, itemid = hyperdb.splitDesignator(designator)
80 cl = self.db.getclass(classname)
81 props = properties and list(properties) or cl.properties.keys()
82 props.sort()
83 for p in props:
84 if not self.db.security.hasPermission('View', self.db.getuid(),
85 classname, p, itemid):
86 raise Unauthorised('Permission to view %s of %s denied'%
87 (p, designator))
88 result = [(prop, cl.get(itemid, prop)) for prop in props]
89 return dict(result)
91 def create(self, classname, *args):
92 if not self.db.security.hasPermission('Create', self.db.getuid(), classname):
93 raise Unauthorised('Permission to create %s denied'%classname)
95 cl = self.db.getclass(classname)
97 # convert types
98 props = props_from_args(self.db, cl, args)
100 # check for the key property
101 key = cl.getkey()
102 if key and not props.has_key(key):
103 raise UsageError, 'you must provide the "%s" property.'%key
105 # do the actual create
106 try:
107 result = cl.create(**props)
108 except (TypeError, IndexError, ValueError), message:
109 raise UsageError, message
110 return result
112 def set(self, designator, *args):
114 classname, itemid = hyperdb.splitDesignator(designator)
115 cl = self.db.getclass(classname)
116 props = props_from_args(self.db, cl, args, itemid) # convert types
117 for p in props.iterkeys():
118 if not self.db.security.hasPermission('Edit', self.db.getuid(),
119 classname, p, itemid):
120 raise Unauthorised('Permission to edit %s of %s denied'%
121 (p, designator))
122 try:
123 return cl.set(itemid, **props)
124 except (TypeError, IndexError, ValueError), message:
125 raise UsageError, message
128 class RoundupDispatcher(SimpleXMLRPCDispatcher):
129 """RoundupDispatcher bridges from cgi.client to RoundupInstance.
130 It expects user authentication to be done."""
132 def __init__(self, db, userid, translator,
133 allow_none=False, encoding=None):
135 SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
136 self.register_instance(RoundupInstance(db, userid, translator))
139 def dispatch(self, input):
140 return self._marshaled_dispatch(input)
142 def _dispatch(self, method, params):
144 retn = SimpleXMLRPCDispatcher._dispatch(self, method, params)
145 retn = translate(retn)
146 return retn