rendered paste body=== trac/Timeline.py==================================================================--- trac/Timeline.py (revision 3750)+++ trac/Timeline.py (local)@@ -31,6 +31,7 @@ from trac.versioncontrol.svn_authz import SubversionAuthorizer from trac.web.chrome import add_link, add_stylesheet, INavigationContributor from trac.web.main import IRequestHandler+from trac.Rpc import IXmlRpcHandler class ITimelineEventProvider(Interface):@@ -60,10 +61,16 @@ class TimelineModule(Component): - implements(INavigationContributor, IPermissionRequestor, IRequestHandler)+ implements(INavigationContributor, IPermissionRequestor, IRequestHandler, IXmlRpcHandler) event_providers = ExtensionPoint(ITimelineEventProvider) + def xmlrpc_module(self):+ return 'timeline'++ def xmlrpc_methods(self):+ return ['listFilters']+ # INavigationContributor methods def get_active_navigation_item(self, req):@@ -85,6 +92,13 @@ def match_request(self, req): return req.path_info == '/timeline' + def listFilters(self, req):+ req.perm.assert_permission('TIMELINE_VIEW')+ available_filters = []+ for event_provider in self.event_providers:+ available_filters += event_provider.get_timeline_filters(req)+ return available_filters+ def process_request(self, req): req.perm.assert_permission('TIMELINE_VIEW') @@ -109,9 +123,7 @@ req.hdf['timeline.from'] = time.strftime('%x', time.localtime(fromdate)) req.hdf['timeline.daysback'] = daysback - available_filters = []- for event_provider in self.event_providers:- available_filters += event_provider.get_timeline_filters(req)+ available_filters = self.listFilters(req) filters = [] # check the request or session for enabled filters, or enable all@@ -167,9 +179,9 @@ if author: # For RSS, author must be an email address- if author.find('@') != -1:+ if '@' in author: event['author.email'] = author- elif author in email_map.keys():+ elif email_map.has_key(author): event['author.email'] = email_map[author] event['date'] = http_date(time.mktime(t)) === trac/web/cgi_frontend.py==================================================================--- trac/web/cgi_frontend.py (revision 3750)+++ trac/web/cgi_frontend.py (local)@@ -83,6 +83,11 @@ """ get = cgi.FieldStorage.getvalue + def __init__(self, *args, **kwds):+ cgi.FieldStorage.__init__(self, *args, **kwds)+ if self.list is None:+ self.list = []+ def __setitem__(self, name, value): if self.has_key(name): del self[name]=== trac/web/chrome.py==================================================================--- trac/web/chrome.py (revision 3750)+++ trac/web/chrome.py (local)@@ -87,6 +87,27 @@ """ +class PluginTemplateMixin(Component):+ implements(ITemplateProvider)+ # ITemplateProvider+ + def get_htdocs_dir(self):+ """Return the absolute path of a directory containing additional+ static resources (such as images, style sheets, etc).+ """+ from pkg_resources import resource_filename+ return resource_filename(self.__class__.__module__, 'htdocs')++ def get_templates_dir(self):+ """Return the absolute path of the directory containing the provided+ ClearSilver templates.+ """+ from pkg_resources import resource_filename+ self.log.debug('Htdocs: %s' % self.__class__)+ self.log.debug(__name__)+ return resource_filename(self.__class__.__module__, 'templates')++ class Chrome(Component): """Responsible for assembling the web site chrome, i.e. everything that is not actual page content.=== trac/web/main.py==================================================================--- trac/web/main.py (revision 3750)+++ trac/web/main.py (local)@@ -19,6 +19,8 @@ # # Author: Christopher Lenz <cmlenz@gmx.de> +import traceback+ import mimetypes import os import os.path@@ -297,6 +299,8 @@ """ from trac import __version__ from time import gmtime, localtime, strftime+ if hdf is None:+ return hdf['trac'] = { 'version': __version__, 'time': strftime('%c', localtime()),@@ -452,6 +456,8 @@ if env and env.log: env.log.exception(e) populate_hdf(req.hdf, env, req)+ env.log.error('Request args: %s' % req.args)+ populate_hdf(req.hdf, env, req) if isinstance(e, TracError): req.hdf['title'] = e.title or 'Error'@@ -482,6 +488,7 @@ if env and env.log: env.log.error('Failed to render pretty error page: %s', e2, exc_info=True)+ env.log.error(traceback.format_exc()) req.send_response(500) req.send_header('Content-Type', 'text/plain') req.end_headers()=== trac/web/modpython_frontend.py==================================================================--- trac/web/modpython_frontend.py (revision 3750)+++ trac/web/modpython_frontend.py (local)@@ -150,7 +150,12 @@ self.args = '' def __getattr__(self, name): return getattr(self.req, name)- util.FieldStorage.__init__(self, RequestWrapper(req), keep_blank_values=1)+ try:+ util.FieldStorage.__init__(self, RequestWrapper(req), keep_blank_values=1)+ except apache.SERVER_RETURN, e:+ self.value = req.read()+ else:+ self.value = '' # Populate FieldStorage with the original query string parameters, if # they aren't already defined through the request body=== trac/wiki/model.py==================================================================--- trac/wiki/model.py (revision 3750)+++ trac/wiki/model.py (local)@@ -40,6 +40,8 @@ self.version = -1 self.text = '' self.readonly = 0+ self.time = 0+ self.author = '' self.old_text = self.text self.old_readonly = self.readonly @@ -48,23 +50,27 @@ db = self.env.get_db_cnx() cursor = db.cursor() if version:- cursor.execute("SELECT version,text,readonly FROM wiki "+ cursor.execute("SELECT version,text,readonly,time,author FROM wiki " "WHERE name=%s AND version=%s", (name, int(version))) else:- cursor.execute("SELECT version,text,readonly FROM wiki "+ cursor.execute("SELECT version,text,readonly,time,author FROM wiki " "WHERE name=%s ORDER BY version DESC LIMIT 1", (name,)) row = cursor.fetchone() if row:- version,text,readonly = row+ version,text,readonly,time,author = row self.version = int(version) self.text = text self.readonly = readonly and int(readonly) or 0+ self.time = int(time)+ self.author = author else: self.version = -1 self.text = '' self.readonly = 0+ self.time = 0+ self.author = '' exists = property(fget=lambda self: self.version >= 0) === trac/Rpc.py==================================================================--- trac/Rpc.py (revision 3750)+++ trac/Rpc.py (local)@@ -0,0 +1,193 @@+import xmlrpclib+import sys++from trac.core import *+from trac.perm import IPermissionRequestor+from trac.web.main import IRequestHandler+from trac.wiki.api import WikiSystem+from trac.wiki.model import WikiPage++class IXmlRpcHandler(Interface):+ def xmlrpc_module():+ pass++ def xmlrpc_methods():+ pass++class XmlRpcModule(Component):++ implements(IPermissionRequestor, IRequestHandler, IXmlRpcHandler)+ rpc_handlers = ExtensionPoint(IXmlRpcHandler)++ def get_permission_actions(self):+ return ['XML_RPC']++ def match_request(self, req):+ return req.path_info == '/xmlrpc'++ def process_request(self, req):+ req.send_response(200)+ req.send_header('Content-Type', 'text/xml')+ req.end_headers()++ try:+ req.perm.assert_permission('XML_RPC')++ params, method = xmlrpclib.loads(str(req.args.value))++ result = self._call(method, params, req)+ if result is None:+ raise xmlrpclib.Fault(4, 'Method call did not return a value')+ req.write(xmlrpclib.dumps((result,), methodresponse=True))+ except:+ self.log.error(sys.exc_value)+ req.write(xmlrpclib.dumps(self._wrap_except()))+ + def _get_module(self, rpc_module):+ for rpc in self.rpc_handlers:+ if rpc.xmlrpc_module() == rpc_module:+ return rpc++ def _get_method(self, method):+ parts = method.split('.', 1)+ if len(parts) < 2:+ return None++ moduleName, methodName = parts+ module = self._get_module(moduleName)+ if module and methodName in module.xmlrpc_methods():+ return getattr(module, methodName)++ def _call(self, methodName, params, req):+ func = self._get_method(methodName)+ if func:+ return func(req, *params)+ else:+ raise xmlrpclib.Fault(2, 'Unknown method')++ def _wrap_except(self):+ e = sys.exc_value+ if isinstance(e, xmlrpclib.Fault):+ return e+ return xmlrpclib.Fault(1, '%s:%s' % (sys.exc_type, e))++ def xmlrpc_module(self):+ return 'system'++ def xmlrpc_methods(self):+ return ['listMethods',+ 'methodHelp',+ 'methodSignature',+ 'multicall']++ def listMethods(self, req):+ methods = []+ for rpc in self.rpc_handlers:+ module = rpc.xmlrpc_module()+ for method in rpc.xmlrpc_methods():+ methods.append('.'.join((module, method)))+ return methods++ def methodHelp(self, req, methodName):+ func = self._get_method(methodName)+ if func:+ import pydoc+ return pydoc.getdoc(func)+ else:+ raise xmlrpclib.Fault(3, "Can't get help for unknown method: %s" % methodName)++ def methodSignature(self, req, methodName):+ return 'system.methodSignature is not implemented'++ def multicall(self, req, callParams):+ results = []+ for meth_sig in callParams:+ try:+ r = [self._call(**meth_sig)]+ except:+ r = self._wrap_except()+ results.append(r)+ return results+++class WikiRpc(Component):+ implements(IXmlRpcHandler)++ def __init__(self):+ self.wiki = WikiSystem(self.env)++ def xmlrpc_module(self):+ return 'wiki'++ def xmlrpc_methods(self):+ return ['getRecentChanges',+ 'getRPCVersionSupported',+ 'getPage', 'getPageVersion',+ 'getPageInfo', 'getPageInfoVersion',+ 'getAllPages']++ def _to_timestamp(self, datetime):+ import time+ return time.mktime(time.strptime(datetime.value, '%Y%m%dT%H:%M:%S'))++ def _page_info(self, name, time, author, version):+ return dict(name=name, lastModified=xmlrpclib.DateTime(int(time)),+ author=author, version=int(version))++ def getRecentChanges(self, req, since):+ req.perm.assert_permission('WIKI_VIEW')+ since = self._to_timestamp(since)+ db = self.env.get_db_cnx()+ cursor = db.cursor()+ cursor.execute('SELECT name, max(time), author, version FROM wiki'+ ' WHERE time >= %s GROUP BY name ORDER BY max(time) DESC', since)+ result = []+ for name, time, author, version in cursor:+ result.append(self._page_info(name, time, author, version))+ return result++ def getRPCVersionSupported(self, req):+ req.perm.assert_permission('WIKI_VIEW')+ return 2++ def getPage(self, req, pagename, version=None):+ req.perm.assert_permission('WIKI_VIEW')+ page = WikiPage(self.env, pagename, version)+ if page.exists:+ return page.text+ else:+ msg = 'Wiki page "%s" does not exist' % pagename+ if version is not None:+ msg += ' at version %s' % version+ raise xmlrpclib.Fault(0, msg)++ getPageVersion = getPage++ def getPageHTML(self, req, pagename, version=None):+ req.perm.assert_permission('WIKI_VIEW')+ pass++ getPageHTMLVersion = getPageHTML++ def getAllPages(self, req):+ '''+ Returns a list of all pages.+ The result is an array of utf8 pagenames.+ '''+ req.perm.assert_permission('WIKI_VIEW')+ return list(self.wiki.get_pages())++ def getPageInfo(self, req, pagename, version=None):+ req.perm.assert_permission('WIKI_VIEW')+ page = WikiPage(self.env, pagename, version)+ if page.exists:+ return self._page_info(page.name, page.time, page.author,+ page.version)++ getPageInfoVersion = getPageInfo++ def listLinks(self, req, pagename):+ req.perm.assert_permission('WIKI_VIEW')+ pass++