Mercurial > p > roundup > code
comparison roundup/xmlrpc.py @ 6015:af1067e0f6d9
flake8 changes; move imports before first statements; whitespace
normalization.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Tue, 31 Dec 2019 21:56:14 -0500 |
| parents | ed02a1e0aa5d |
| children | f7bd22bdef9d |
comparison
equal
deleted
inserted
replaced
| 6014:6ed03d01491d | 6015:af1067e0f6d9 |
|---|---|
| 7 import logging | 7 import logging |
| 8 from roundup import hyperdb | 8 from roundup import hyperdb |
| 9 from roundup.exceptions import Unauthorised, UsageError | 9 from roundup.exceptions import Unauthorised, UsageError |
| 10 from roundup.date import Date, Range, Interval | 10 from roundup.date import Date, Range, Interval |
| 11 from roundup import actions | 11 from roundup import actions |
| 12 from roundup.anypy.strings import us2s | |
| 13 from traceback import format_exc | |
| 12 from roundup.anypy import xmlrpc_ | 14 from roundup.anypy import xmlrpc_ |
| 13 SimpleXMLRPCDispatcher = xmlrpc_.server.SimpleXMLRPCDispatcher | 15 SimpleXMLRPCDispatcher = xmlrpc_.server.SimpleXMLRPCDispatcher |
| 14 Binary = xmlrpc_.client.Binary | 16 Binary = xmlrpc_.client.Binary |
| 15 from roundup.anypy.strings import us2s | 17 |
| 16 from traceback import format_exc | |
| 17 | 18 |
| 18 def translate(value): | 19 def translate(value): |
| 19 """Translate value to becomes valid for XMLRPC transmission.""" | 20 """Translate value to becomes valid for XMLRPC transmission.""" |
| 20 | 21 |
| 21 if isinstance(value, (Date, Range, Interval)): | 22 if isinstance(value, (Date, Range, Interval)): |
| 36 | 37 |
| 37 props = {} | 38 props = {} |
| 38 for arg in args: | 39 for arg in args: |
| 39 if isinstance(arg, Binary): | 40 if isinstance(arg, Binary): |
| 40 arg = arg.data | 41 arg = arg.data |
| 41 try : | 42 try: |
| 42 key, value = arg.split('=', 1) | 43 key, value = arg.split('=', 1) |
| 43 except ValueError : | 44 except ValueError: |
| 44 raise UsageError('argument "%s" not propname=value'%arg) | 45 raise UsageError('argument "%s" not propname=value' % arg) |
| 45 key = us2s(key) | 46 key = us2s(key) |
| 46 value = us2s(value) | 47 value = us2s(value) |
| 47 if value: | 48 if value: |
| 48 try: | 49 try: |
| 49 props[key] = hyperdb.rawToHyperdb(db, cl, itemid, | 50 props[key] = hyperdb.rawToHyperdb(db, cl, itemid, |
| 57 else: | 58 else: |
| 58 props[key] = None | 59 props[key] = None |
| 59 | 60 |
| 60 return props | 61 return props |
| 61 | 62 |
| 63 | |
| 62 class RoundupInstance: | 64 class RoundupInstance: |
| 63 """The RoundupInstance provides the interface accessible through | 65 """The RoundupInstance provides the interface accessible through |
| 64 the Python XMLRPC mapping.""" | 66 the Python XMLRPC mapping.""" |
| 65 | 67 |
| 66 def __init__(self, db, actions, translator): | 68 def __init__(self, db, actions, translator): |
| 71 | 73 |
| 72 def schema(self): | 74 def schema(self): |
| 73 s = {} | 75 s = {} |
| 74 for c in self.db.classes: | 76 for c in self.db.classes: |
| 75 cls = self.db.classes[c] | 77 cls = self.db.classes[c] |
| 76 props = [(n,repr(v)) for n,v in sorted(cls.properties.items())] | 78 props = [(n, repr(v)) for n, v in sorted(cls.properties.items())] |
| 77 s[c] = props | 79 s[c] = props |
| 78 return s | 80 return s |
| 79 | 81 |
| 80 def list(self, classname, propname=None): | 82 def list(self, classname, propname=None): |
| 81 cl = self.db.getclass(classname) | 83 cl = self.db.getclass(classname) |
| 82 if not propname: | 84 if not propname: |
| 83 propname = cl.labelprop() | 85 propname = cl.labelprop() |
| 84 result = [cl.get(itemid, propname) | 86 result = [cl.get(itemid, propname) |
| 85 for itemid in cl.list() | 87 for itemid in cl.list() |
| 86 if self.db.security.hasPermission('View', self.db.getuid(), | 88 if self.db.security.hasPermission('View', self.db.getuid(), |
| 87 classname, propname, itemid) | 89 classname, propname, |
| 90 itemid) | |
| 88 ] | 91 ] |
| 89 return result | 92 return result |
| 90 | 93 |
| 91 def filter(self, classname, search_matches, filterspec, | 94 def filter(self, classname, search_matches, filterspec, |
| 92 sort=[], group=[]): | 95 sort=[], group=[]): |
| 93 cl = self.db.getclass(classname) | 96 cl = self.db.getclass(classname) |
| 94 uid = self.db.getuid() | 97 uid = self.db.getuid() |
| 95 security = self.db.security | 98 security = self.db.security |
| 96 filterspec = security.filterFilterspec (uid, classname, filterspec) | 99 filterspec = security.filterFilterspec(uid, classname, filterspec) |
| 97 sort = security.filterSortspec (uid, classname, sort) | 100 sort = security.filterSortspec(uid, classname, sort) |
| 98 group = security.filterSortspec (uid, classname, group) | 101 group = security.filterSortspec(uid, classname, group) |
| 99 result = cl.filter(search_matches, filterspec, sort=sort, group=group) | 102 result = cl.filter(search_matches, filterspec, sort=sort, group=group) |
| 100 check = security.hasPermission | 103 check = security.hasPermission |
| 101 x = [id for id in result if check('View', uid, classname, itemid=id)] | 104 x = [id for id in result if check('View', uid, classname, itemid=id)] |
| 102 return x | 105 return x |
| 103 | 106 |
| 106 uid = self.db.getuid() | 109 uid = self.db.getuid() |
| 107 prop = cl.getkey() | 110 prop = cl.getkey() |
| 108 search = self.db.security.hasSearchPermission | 111 search = self.db.security.hasSearchPermission |
| 109 access = self.db.security.hasPermission | 112 access = self.db.security.hasPermission |
| 110 if (not search(uid, classname, prop) | 113 if (not search(uid, classname, prop) |
| 111 and not access('View', uid, classname, prop)): | 114 and not access('View', uid, classname, prop)): |
| 112 raise Unauthorised('Permission to lookup %s denied'%classname) | 115 raise Unauthorised('Permission to lookup %s denied' % classname) |
| 113 return cl.lookup(key) | 116 return cl.lookup(key) |
| 114 | 117 |
| 115 def display(self, designator, *properties): | 118 def display(self, designator, *properties): |
| 116 classname, itemid = hyperdb.splitDesignator(designator) | 119 classname, itemid = hyperdb.splitDesignator(designator) |
| 117 cl = self.db.getclass(classname) | 120 cl = self.db.getclass(classname) |
| 118 props = properties and list(properties) or list(cl.properties.keys()) | 121 props = properties and list(properties) or list(cl.properties.keys()) |
| 119 props.sort() | 122 props.sort() |
| 120 for p in props: | 123 for p in props: |
| 121 if not self.db.security.hasPermission('View', self.db.getuid(), | 124 if not self.db.security.hasPermission('View', self.db.getuid(), |
| 122 classname, p, itemid): | 125 classname, p, itemid): |
| 123 raise Unauthorised('Permission to view %s of %s denied'% | 126 raise Unauthorised('Permission to view %s of %s denied' % |
| 124 (p, designator)) | 127 (p, designator)) |
| 125 result = [(prop, cl.get(itemid, prop)) for prop in props] | 128 result = [(prop, cl.get(itemid, prop)) for prop in props] |
| 126 return dict(result) | 129 return dict(result) |
| 127 | 130 |
| 128 def create(self, classname, *args): | 131 def create(self, classname, *args): |
| 129 | 132 if not self.db.security.hasPermission('Create', self.db.getuid(), |
| 130 if not self.db.security.hasPermission('Create', self.db.getuid(), classname): | 133 classname): |
| 131 raise Unauthorised('Permission to create %s denied'%classname) | 134 raise Unauthorised('Permission to create %s denied' % classname) |
| 132 | 135 |
| 133 cl = self.db.getclass(classname) | 136 cl = self.db.getclass(classname) |
| 134 | 137 |
| 135 # convert types | 138 # convert types |
| 136 props = props_from_args(self.db, cl, args) | 139 props = props_from_args(self.db, cl, args) |
| 137 | 140 |
| 138 # check for the key property | 141 # check for the key property |
| 139 key = cl.getkey() | 142 key = cl.getkey() |
| 140 if key and key not in props: | 143 if key and key not in props: |
| 141 raise UsageError('you must provide the "%s" property.'%key) | 144 raise UsageError('you must provide the "%s" property.' % key) |
| 142 | 145 |
| 143 for key in props: | 146 for key in props: |
| 144 if not self.db.security.hasPermission('Create', self.db.getuid(), | 147 if not self.db.security.hasPermission('Create', self.db.getuid(), |
| 145 classname, property=key): | 148 classname, property=key): |
| 146 raise Unauthorised('Permission to create %s.%s denied'%(classname, key)) | 149 raise Unauthorised('Permission to create %s.%s denied' % |
| 150 (classname, key)) | |
| 147 | 151 |
| 148 # do the actual create | 152 # do the actual create |
| 149 try: | 153 try: |
| 150 result = cl.create(**props) | 154 result = cl.create(**props) |
| 151 self.db.commit() | 155 self.db.commit() |
| 152 except (TypeError, IndexError, ValueError) as message: | 156 except (TypeError, IndexError, ValueError) as message: |
| 153 # The exception we get may be a real error, log the traceback if we're debugging | 157 # The exception we get may be a real error, log the traceback |
| 158 # if we're debugging | |
| 154 logger = logging.getLogger('roundup.xmlrpc') | 159 logger = logging.getLogger('roundup.xmlrpc') |
| 155 for l in format_exc().split('\n'): | 160 for l in format_exc().split('\n'): |
| 156 logger.debug(l) | 161 logger.debug(l) |
| 157 raise UsageError (message) | 162 raise UsageError(message) |
| 158 return result | 163 return result |
| 159 | 164 |
| 160 def set(self, designator, *args): | 165 def set(self, designator, *args): |
| 161 | 166 |
| 162 classname, itemid = hyperdb.splitDesignator(designator) | 167 classname, itemid = hyperdb.splitDesignator(designator) |
| 163 cl = self.db.getclass(classname) | 168 cl = self.db.getclass(classname) |
| 164 props = props_from_args(self.db, cl, args, itemid) # convert types | 169 props = props_from_args(self.db, cl, args, itemid) # convert types |
| 165 for p in props.keys(): | 170 for p in props.keys(): |
| 166 if not self.db.security.hasPermission('Edit', self.db.getuid(), | 171 if not self.db.security.hasPermission('Edit', self.db.getuid(), |
| 167 classname, p, itemid): | 172 classname, p, itemid): |
| 168 raise Unauthorised('Permission to edit %s of %s denied'% | 173 raise Unauthorised('Permission to edit %s of %s denied' % |
| 169 (p, designator)) | 174 (p, designator)) |
| 170 try: | 175 try: |
| 171 result = cl.set(itemid, **props) | 176 result = cl.set(itemid, **props) |
| 172 self.db.commit() | 177 self.db.commit() |
| 173 except (TypeError, IndexError, ValueError) as message: | 178 except (TypeError, IndexError, ValueError) as message: |
| 174 # The exception we get may be a real error, log the traceback if we're debugging | 179 # The exception we get may be a real error, log the |
| 180 # traceback if we're debugging | |
| 175 logger = logging.getLogger('roundup.xmlrpc') | 181 logger = logging.getLogger('roundup.xmlrpc') |
| 176 for l in format_exc().split('\n'): | 182 for l in format_exc().split('\n'): |
| 177 logger.debug(l) | 183 logger.debug(l) |
| 178 raise UsageError (message) | 184 raise UsageError(message) |
| 179 return result | 185 return result |
| 180 | 186 |
| 181 | 187 builtin_actions = dict(retire=actions.Retire, restore=actions.Restore) |
| 182 builtin_actions = dict (retire = actions.Retire, restore = actions.Restore) | |
| 183 | 188 |
| 184 def action(self, name, *args): | 189 def action(self, name, *args): |
| 185 """Execute a named action.""" | 190 """Execute a named action.""" |
| 186 | 191 |
| 187 if name in self.actions: | 192 if name in self.actions: |
| 188 action_type = self.actions[name] | 193 action_type = self.actions[name] |
| 189 elif name in self.builtin_actions: | 194 elif name in self.builtin_actions: |
| 190 action_type = self.builtin_actions[name] | 195 action_type = self.builtin_actions[name] |
| 191 else: | 196 else: |
| 192 raise Exception('action "%s" is not supported %s' | 197 raise Exception('action "%s" is not supported %s' |
| 193 % (name, ','.join(self.actions.keys()))) | 198 % (name, ','.join(self.actions.keys()))) |
| 194 action = action_type(self.db, self.translator) | 199 action = action_type(self.db, self.translator) |
| 195 return action.execute(*args) | 200 return action.execute(*args) |
| 196 | 201 |
| 197 | 202 |
| 198 class RoundupDispatcher(SimpleXMLRPCDispatcher): | 203 class RoundupDispatcher(SimpleXMLRPCDispatcher): |
| 202 def __init__(self, db, actions, translator, | 207 def __init__(self, db, actions, translator, |
| 203 allow_none=False, encoding=None): | 208 allow_none=False, encoding=None): |
| 204 SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding) | 209 SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding) |
| 205 self.register_instance(RoundupInstance(db, actions, translator)) | 210 self.register_instance(RoundupInstance(db, actions, translator)) |
| 206 self.register_multicall_functions() | 211 self.register_multicall_functions() |
| 207 | |
| 208 | 212 |
| 209 def dispatch(self, input): | 213 def dispatch(self, input): |
| 210 return self._marshaled_dispatch(input) | 214 return self._marshaled_dispatch(input) |
| 211 | 215 |
| 212 def _dispatch(self, method, params): | 216 def _dispatch(self, method, params): |
| 213 | 217 |
| 214 retn = SimpleXMLRPCDispatcher._dispatch(self, method, params) | 218 retn = SimpleXMLRPCDispatcher._dispatch(self, method, params) |
| 215 retn = translate(retn) | 219 retn = translate(retn) |
| 216 return retn | 220 return retn |
| 217 |
