Changeset 808
- Timestamp:
- 06/03/06 03:58:41 (3 years ago)
- Files:
-
- xmlrpcplugin/0.10/tracrpc/api.py (modified) (7 diffs)
- xmlrpcplugin/0.10/tracrpc/templates/xmlrpclist.cs (modified) (2 diffs)
- xmlrpcplugin/0.10/tracrpc/ticket.py (modified) (7 diffs)
- xmlrpcplugin/0.10/tracrpc/web_ui.py (modified) (2 diffs)
- xmlrpcplugin/0.10/tracrpc/wiki.py (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
xmlrpcplugin/0.10/tracrpc/api.py
r504 r808 13 13 list: 'array', dict: 'struct', None : 'int'} 14 14 15 class IXMLRPCHandler(Interface):16 def xmlrpc_namespace():17 """ Provide the namespace in which a set of methods lives.18 This can be overridden if the 'name' element is provided by19 xmlrpc_methods(). """20 21 def xmlrpc_methods():22 """ Return an iterator of (permission, signatures, callable[, name]),23 where callable is exposed via XML-RPC if the authenticated user has24 the appropriate permission.25 26 The callable itself can be a method or a normal method. The27 XMLRPCSystem performs some extra magic to remove the "self"28 argument when listing the available methods.29 30 Signatures is a list of XML-RPC introspection signatures for this method.31 """32 33 class AbstractRPCHandler(Component):34 implements(IXMLRPCHandler)35 abstract = True36 37 def _init_methods(self):38 import inspect39 self._rpc_methods = []40 for name, val in inspect.getmembers(self):41 if hasattr(val, '_xmlrpc_signatures'):42 self._rpc_methods.append((val._xml_rpc_permission, val._xmlrpc_signatures, val, name))43 44 def xmlrpc_methods(self):45 if not hasattr(self, '_rpc_methods'):46 self._init_methods()47 return self._rpc_methods48 15 49 16 def expose_rpc(permission, return_type, *arg_types): 50 """ Expose a method as an RPC call with the given signature. """ 17 """ Decorator for exposing a method as an RPC call with the given 18 signature. """ 51 19 def decorator(func): 52 20 if not hasattr(func, '_xmlrpc_signatures'): … … 56 24 return func 57 25 return decorator 26 27 28 class IXMLRPCHandler(Interface): 29 def xmlrpc_namespace(): 30 """ Provide the namespace in which a set of methods lives. 31 This can be overridden if the 'name' element is provided by 32 xmlrpc_methods(). """ 33 34 def xmlrpc_methods(): 35 """ Return an iterator of (permission, signatures, callable[, name]), 36 where callable is exposed via XML-RPC if the authenticated user has the 37 appropriate permission. 38 39 The callable itself can be a method or a normal method. The first 40 argument passed will always be a request object. The XMLRPCSystem 41 performs some extra magic to remove the "self" and "req" arguments when 42 listing the available methods. 43 44 Signatures is a list of XML-RPC introspection signatures for this 45 method. Each signature is a tuple consisting of the return type 46 followed by argument types. 47 """ 48 49 50 class AbstractRPCHandler(Component): 51 implements(IXMLRPCHandler) 52 abstract = True 53 54 def _init_methods(self): 55 import inspect 56 self._rpc_methods = [] 57 for name, val in inspect.getmembers(self): 58 if hasattr(val, '_xmlrpc_signatures'): 59 self._rpc_methods.append((val._xml_rpc_permission, val._xmlrpc_signatures, val, name)) 60 61 def xmlrpc_methods(self): 62 if not hasattr(self, '_rpc_methods'): 63 self._init_methods() 64 return self._rpc_methods 65 58 66 59 67 class Method(object): … … 75 83 def __call__(self, req, args): 76 84 req.perm.assert_permission(self.permission) 77 # Pass optional "req" arg if required 78 argspec = inspect.getargspec(self.callable)[0] 79 if (argspec and argspec[0] == 'req') or (len(argspec) > 1 and argspec[0:2] == ['self', 'req']): 80 result = self.callable(req, *args) 81 else: 82 result = self.callable(*args) 85 result = self.callable(req, *args) 83 86 # If result is null, return a zero 84 87 if result is None: 85 88 result = 0 86 # We'll fully traverse the generator results and return it as a tuple 87 elif type(result) is types.GeneratorType: 88 result = tuple(result) 89 elif type(result) is set: 90 result = tuple(result) 89 elif not isinstance(result, basestring): 90 # Try and convert result to a list 91 try: 92 result = [i for i in result] 93 except TypeError: 94 pass 91 95 return (result,) 92 96 … … 97 101 fullargspec = inspect.getargspec(self.callable) 98 102 argspec = fullargspec[0] 103 assert argspec[0:2] == ['self', 'req'] or argspec[0] == 'req', \ 104 'Invalid argspec %s for %s' % (argspec, self.name) 99 105 while argspec and (argspec[0] in ('self', 'req')): 100 106 argspec.pop(0) … … 130 136 return self.rpc_signatures 131 137 138 132 139 class XMLRPCSystem(Component): 133 140 """ Core of the XML-RPC system. """ … … 171 178 def multicall(self, req, signatures): 172 179 """ Takes an array of XML-RPC calls encoded as structs of the form (in 173 a Pythonish notation here):174 175 {'methodName': string, 'params': array}180 a Pythonish notation here): 181 182 {'methodName': string, 'params': array} 176 183 """ 177 184 for signature in signatures: … … 200 207 def methodSignature(self, req, method): 201 208 """ This method takes one parameter, the name of a method implemented 202 by the XML-RPC server.203 204 It returns an array of possible signatures for this method. A205 signature is an array of types. The first of these types is the206 return type ofthe method, the rest are parameters. """209 by the XML-RPC server. 210 211 It returns an array of possible signatures for this method. A signature 212 is an array of types. The first of these types is the return type of 213 the method, the rest are parameters. """ 207 214 p = self.get_method(method) 208 215 req.perm.assert_permission(p.permission) xmlrpcplugin/0.10/tracrpc/templates/xmlrpclist.cs
r481 r808 2 2 <?cs include "macros.cs"?> 3 3 4 <div id="content" class="report"> 4 <div id="ctxtnav" class="nav"></div> 5 6 <div id="content" class="wiki"> 5 7 6 8 <h2>XML-RPC exported functions</h2> 7 9 10 <div id="searchable"> 8 11 <dl> 9 12 <?cs each:namespace = xmlrpc.functions ?> 10 13 11 <dt><h3 id= <?cs var:namespace.namespace ?>><?cs var:namespace.namespace ?> - <?cs var:namespace.description ?></h3></dt>14 <dt><h3 id=xmlrpc.<?cs var:namespace.namespace ?>><?cs var:namespace.namespace ?> - <?cs var:namespace.description ?></h3></dt> 12 15 <dd> 13 16 <table class="listing tickets"> … … 33 36 <?cs /each ?> 34 37 </dl> 38 </div> 39 40 <script type="text/javascript"> 41 addHeadingLinks(document.getElementById("searchable")); 42 </script 35 43 36 44 </div> xmlrpcplugin/0.10/tracrpc/ticket.py
r786 r808 1 from trac.attachment import Attachment 1 2 from trac.core import * 2 3 from tracrpc.api import IXMLRPCHandler, expose_rpc 3 4 import trac.ticket.model as model 4 5 import trac.ticket.query as query 6 5 7 import pydoc 6 8 import xmlrpclib … … 22 24 yield ('TICKET_ADMIN', ((None, int),), self.delete) 23 25 yield ('TICKET_VIEW', ((dict, int), (dict, int, int)), self.changeLog) 26 yield ('TICKET_VIEW', ((list, int),), self.listAttachments) 27 yield ('TICKET_VIEW', ((xmlrpclib.Binary, int, str),), self.getAttachment) 28 yield ('TICKET_APPEND', ((bool, int, str, xmlrpclib.Binary),), self.putAttachment) 24 29 25 30 # Exported methods 26 def query(self, qstr = 'status!=closed'):31 def query(self, req, qstr = 'status!=closed'): 27 32 """ Perform a ticket query, returning a list of ticket ID's. """ 28 33 q = query.Query.from_string(self.env, qstr) … … 32 37 return out 33 38 34 def get(self, id):39 def get(self, req, id): 35 40 """ Fetch a ticket. Returns [id, time_created, time_changed, attributes]. """ 36 41 t = model.Ticket(self.env, id) 37 42 return (t.id, t.time_created, t.time_changed, t.values) 38 43 39 def create(self, summary, description, attributes = {}):44 def create(self, req, summary, description, attributes = {}): 40 45 """ Create a new ticket, returning the ticket ID. """ 41 46 t = model.Ticket(self.env) 47 t['status'] = 'new' 42 48 t['summary'] = summary 43 49 t['description'] = description … … 55 61 return self.get(t.id) 56 62 57 def delete(self, id):63 def delete(self, req, id): 58 64 """ Delete ticket with the given id. """ 59 65 t = model.Ticket(self.env, id) 60 66 t.delete() 61 67 62 def changeLog(self, id, when = 0):68 def changeLog(self, req, id, when = 0): 63 69 t = model.Ticket(self.env, id) 64 70 return t.get_changelog() 65 66 71 # Use existing documentation from Ticket model 67 72 changeLog.__doc__ = pydoc.getdoc(model.Ticket.get_changelog) 73 74 def listAttachments(self, req, ticket): 75 """ Lists attachments for a given ticket. """ 76 return [a.filename for a in Attachment.select(self.env, 'ticket', ticket)] 77 78 def getAttachment(self, req, ticket, filename): 79 """ returns the content of an attachment. """ 80 attachment = Attachment(self.env, 'ticket', ticket, filename) 81 return xmlrpclib.Binary(attachment.open().read()) 82 83 def putAttachment(self, req, ticket, filename, data): 84 """ (over)writes an attachment. """ 85 if not Ticket(self.env, ticket).exists: 86 raise TracError, 'Ticket "%s" does not exist' % ticket 87 attachment = Attachment(self.env, 'ticket', ticket) 88 attachment.insert(filename, StringIO(data.data), len(data.data)) 89 return True 68 90 69 91 … … 83 105 yield ('TICKET_ADMIN', ((None, str, dict),), self.update) 84 106 85 def getAll(self ):107 def getAll(self, req): 86 108 for i in cls.select(self.env): 87 109 yield i.name 88 110 getAll.__doc__ = """ Get a list of all ticket %s names. """ % cls.__name__.lower() 89 111 90 def get(self, name):112 def get(self, req, name): 91 113 i = cls(self.env, name) 92 114 attributes= {} … … 96 118 get.__doc__ = """ Get a ticket %s. """ % cls.__name__.lower() 97 119 98 def delete(self, name):120 def delete(self, req, name): 99 121 cls(self.env, name).delete() 100 122 delete.__doc__ = """ Delete a ticket %s """ % cls.__name__.lower() 101 123 102 def create(self, name, attributes):124 def create(self, req, name, attributes): 103 125 self._updateHelper(name, attributes).insert() 104 126 create.__doc__ = """ Create a new ticket %s with the given attributes. """ % cls.__name__.lower() 105 127 106 def update(self, name, attributes):128 def update(self, req, name, attributes): 107 129 self._updateHelper(name, attributes).update() 108 130 update.__doc__ = """ Update ticket %s with the given attributes. """ % cls.__name__.lower() … … 133 155 yield ('TICKET_ADMIN', ((None, str, str),), self.update) 134 156 135 def getAll(self ):157 def getAll(self, req): 136 158 for i in cls.select(self.env): 137 159 yield i.name 138 160 getAll.__doc__ = """ Get a list of all ticket %s names. """ % cls.__name__.lower() 139 161 140 def get(self, name):162 def get(self, req, name): 141 163 i = cls(self.env, name) 142 164 return i.value 143 165 get.__doc__ = """ Get a ticket %s. """ % cls.__name__.lower() 144 166 145 def delete(self, name):167 def delete(self, req, name): 146 168 cls(self.env, name).delete() 147 169 delete.__doc__ = """ Delete a ticket %s """ % cls.__name__.lower() 148 170 149 def create(self, name, value):171 def create(self, req, name, value): 150 172 self._updateHelper(name, value).insert() 151 173 create.__doc__ = """ Create a new ticket %s with the given value. """ % cls.__name__.lower() 152 174 153 def update(self, name, value):175 def update(self, req, name, value): 154 176 self._updateHelper(name, value).update() 155 177 update.__doc__ = """ Update ticket %s with the given value. """ % cls.__name__.lower() 156 178 157 def _updateHelper(self, name, value):179 def _updateHelper(self, req, name, value): 158 180 i = cls(self.env) 159 181 i.name = name xmlrpcplugin/0.10/tracrpc/web_ui.py
r229 r808 1 1 from trac.core import * 2 2 from trac.web.main import IRequestHandler 3 from trac.web.chrome import ITemplateProvider 3 from trac.web.chrome import ITemplateProvider, add_stylesheet 4 4 from tracrpc.api import IXMLRPCHandler, XMLRPCSystem 5 5 from trac.wiki.formatter import wiki_to_oneliner … … 42 42 namespaces[namespace]['methods'].append((method.signature, wiki_to_oneliner(method.description, self.env), method.permission)) 43 43 except Exception, e: 44 raise Exception('%s: %s' % (method.name, str(e))) 44 from StringIO import StringIO 45 import traceback 46 out = StringIO() 47 traceback.print_exc(file=out) 48 raise Exception('%s: %s\n%s' % (method.name, str(e), out.getvalue())) 49 add_stylesheet(req, 'common/css/wiki.css') 45 50 req.hdf['xmlrpc.functions'] = namespaces 46 51 return 'xmlrpclist.cs', None xmlrpcplugin/0.10/tracrpc/wiki.py
r478 r808 49 49 author=author, version=int(version)) 50 50 51 def getRecentChanges(self, since):51 def getRecentChanges(self, req, since): 52 52 """ Get list of changed pages since timestamp """ 53 53 since = self._to_timestamp(since) … … 61 61 return result 62 62 63 def getRPCVersionSupported(self ):63 def getRPCVersionSupported(self, req): 64 64 """ Returns 2 with this version of the Trac API. """ 65 65 return 2 66 66 67 def getPage(self, pagename, version=None):67 def getPage(self, req, pagename, version=None): 68 68 """ Get the raw Wiki text of page, latest version. """ 69 69 page = WikiPage(self.env, pagename, version) … … 82 82 return '<html><body>%s</body></html>' % html 83 83 84 def getAllPages(self ):84 def getAllPages(self, req): 85 85 """ Returns a list of all pages. The result is an array of utf8 pagenames. """ 86 86 return list(self.wiki.get_pages()) 87 87 88 def getPageInfo(self, pagename, version=None):88 def getPageInfo(self, req, pagename, version=None): 89 89 """ Returns information about the given page. """ 90 90 page = WikiPage(self.env, pagename, version) … … 113 113 return True 114 114 115 def listAttachments(self, pagename):115 def listAttachments(self, req, pagename): 116 116 """ Lists attachments on a given page. """ 117 117 return [pagename + '/' + a.filename for a in Attachment.select(self.env, 'wiki', pagename)] 118 118 119 def getAttachment(self, path):119 def getAttachment(self, req, path): 120 120 """ returns the content of an attachment. """ 121 121 pagename, filename = posixpath.split(path) … … 123 123 return xmlrpclib.Binary(attachment.open().read()) 124 124 125 def putAttachment(self, path, data):125 def putAttachment(self, req, path, data): 126 126 """ (over)writes an attachment. """ 127 127 pagename, filename = posixpath.split(path) … … 132 132 return True 133 133 134 def listLinks(self, pagename):134 def listLinks(self, req, pagename): 135 135 """ ''Not implemented'' """ 136 136 return []
