2
from cStringIO import StringIO
4
from StringIO import StringIO
8
from trac.core import *
9
from trac.perm import IPermissionRequestor
10
from trac.wiki.api import WikiSystem
11
from trac.wiki.model import WikiPage
12
from trac.wiki.formatter import wiki_to_html
13
from trac.attachment import Attachment
14
from tracrpc.api import IXMLRPCHandler, expose_rpc
15
from tracrpc.util import to_timestamp
17
class WikiRPC(Component):
18
""" Implementation of the [http://www.jspwiki.org/Wiki.jsp?page=WikiRPCInterface2 WikiRPC API]. """
20
implements(IXMLRPCHandler)
23
self.wiki = WikiSystem(self.env)
25
def xmlrpc_namespace(self):
28
def xmlrpc_methods(self):
29
yield ('WIKI_VIEW', ((dict, xmlrpclib.DateTime),), self.getRecentChanges)
30
yield ('WIKI_VIEW', ((int,),), self.getRPCVersionSupported)
31
yield ('WIKI_VIEW', ((str, str), (str, str, int),), self.getPage)
32
yield ('WIKI_VIEW', ((str, str, int),), self.getPage, 'getPageVersion')
33
yield ('WIKI_VIEW', ((str, str), (str, str, int)), self.getPageHTML)
34
yield ('WIKI_VIEW', ((str, str), (str, str, int)), self.getPageHTML, 'getPageHTMLVersion')
35
yield ('WIKI_VIEW', ((list,),), self.getAllPages)
36
yield ('WIKI_VIEW', ((dict, str), (dict, str, int)), self.getPageInfo)
37
yield ('WIKI_VIEW', ((dict, str, int),), self.getPageInfo, 'getPageInfoVersion')
38
yield ('WIKI_CREATE', ((bool, str, str, dict),), self.putPage)
39
yield ('WIKI_VIEW', ((list, str),), self.listAttachments)
40
yield ('WIKI_VIEW', ((xmlrpclib.Binary, str),), self.getAttachment)
41
yield ('WIKI_MODIFY', ((bool, str, xmlrpclib.Binary),), self.putAttachment)
42
yield ('WIKI_MODIFY', ((bool, str, str, str, xmlrpclib.Binary),
43
(bool, str, str, str, xmlrpclib.Binary, bool)),
45
yield ('WIKI_DELETE', ((bool, str),), self.deleteAttachment)
46
yield ('WIKI_VIEW', ((list, str),), self.listLinks)
47
yield ('WIKI_VIEW', ((str, str),), self.wikiToHtml)
49
def _page_info(self, name, time, author, version):
50
return dict(name=name, lastModified=xmlrpclib.DateTime(int(time)),
51
author=author, version=int(version))
53
def getRecentChanges(self, req, since):
54
""" Get list of changed pages since timestamp """
55
since = to_timestamp(since)
56
db = self.env.get_db_cnx()
58
cursor.execute('SELECT name, max(time), author, version FROM wiki'
59
' WHERE time >= %s GROUP BY name ORDER BY max(time) DESC', (since,))
61
for name, time, author, version in cursor:
62
result.append(self._page_info(name, time, author, version))
65
def getRPCVersionSupported(self, req):
66
""" Returns 2 with this version of the Trac API. """
69
def getPage(self, req, pagename, version=None):
70
""" Get the raw Wiki text of page, latest version. """
71
page = WikiPage(self.env, pagename, version)
75
msg = 'Wiki page "%s" does not exist' % pagename
76
if version is not None:
77
msg += ' at version %s' % version
78
raise xmlrpclib.Fault(0, msg)
80
def getPageHTML(self, req, pagename, version=None):
81
""" Return page in rendered HTML, latest version. """
82
text = self.getPage(req, pagename, version)
83
html = wiki_to_html(text, self.env, req, absurls=1)
84
return '<html><body>%s</body></html>' % html
86
def getAllPages(self, req):
87
""" Returns a list of all pages. The result is an array of utf8 pagenames. """
88
return list(self.wiki.get_pages())
90
def getPageInfo(self, req, pagename, version=None):
91
""" Returns information about the given page. """
92
page = WikiPage(self.env, pagename, version)
94
last_update = page.get_history().next()
95
return self._page_info(page.name, last_update[1], last_update[2],
98
def putPage(self, req, pagename, content, attributes):
99
""" writes the content of the page. """
100
page = WikiPage(self.env, pagename)
102
req.perm.assert_permission('WIKI_ADMIN')
103
elif not page.exists:
104
req.perm.assert_permission('WIKI_CREATE')
106
req.perm.assert_permission('WIKI_MODIFY')
109
if req.perm.has_permission('WIKI_ADMIN'):
110
page.readonly = attributes.get('readonly') and 1 or 0
112
page.save(attributes.get('author', req.authname),
113
attributes.get('comment'),
117
def listAttachments(self, req, pagename):
118
""" Lists attachments on a given page. """
119
return [pagename + '/' + a.filename for a in Attachment.select(self.env, 'wiki', pagename)]
121
def getAttachment(self, req, path):
122
""" returns the content of an attachment. """
123
pagename, filename = posixpath.split(path)
124
attachment = Attachment(self.env, 'wiki', pagename, filename)
125
return xmlrpclib.Binary(attachment.open().read())
127
def putAttachment(self, req, path, data):
128
""" (over)writes an attachment. Returns True if successful.
130
This method is compatible with WikiRPC. `putAttachmentEx` has a more
131
extensive set of (Trac-specific) features. """
132
pagename, filename = posixpath.split(path)
133
self.putAttachmentEx(req, pagename, filename, None, data)
136
def putAttachmentEx(self, req, pagename, filename, description, data, replace=True):
137
""" Attach a file to a Wiki page. Returns the (possibly transformed)
138
filename of the attachment.
140
Use this method if you don't care about WikiRPC compatibility. """
141
if not WikiPage(self.env, pagename).exists:
142
raise TracError, 'Wiki page "%s" does not exist' % pagename
145
attachment = Attachment(self.env, 'wiki', pagename, filename)
149
attachment = Attachment(self.env, 'wiki', pagename)
150
attachment.author = req.authname or 'anonymous'
151
attachment.description = description
152
attachment.insert(filename, StringIO(data.data), len(data.data))
153
return attachment.filename
155
def deleteAttachment(self, req, path):
156
""" Delete an attachment. """
157
pagename, filename = posixpath.split(path)
158
if not WikiPage(self.env, pagename).exists:
159
raise TracError, 'Wiki page "%s" does not exist' % pagename
160
attachment = Attachment(self.env, 'wiki', pagename, filename)
164
def listLinks(self, req, pagename):
165
""" ''Not implemented'' """
168
def wikiToHtml(self, req, text):
169
""" Render arbitrary Wiki text as HTML. """
170
return unicode(wiki_to_html(text, self.env, req, absurls=1))