root/xmlrpcplugin/0.10/tracrpc/wiki.py

Revision 1735, 7.1 kB (checked in by athomas, 2 years ago)

XmlRpcPlugin:

Applied patches from gotoh and stp, thanks. Closes #434 and #845.

Line 
1 try:
2     from cStringIO import StringIO
3 except ImportError:
4     from StringIO import StringIO
5 import xmlrpclib
6 import posixpath
7
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
16
17 class WikiRPC(Component):
18     """ Implementation of the [http://www.jspwiki.org/Wiki.jsp?page=WikiRPCInterface2 WikiRPC API]. """
19
20     implements(IXMLRPCHandler)
21
22     def __init__(self):
23         self.wiki = WikiSystem(self.env)
24
25     def xmlrpc_namespace(self):
26         return 'wiki'
27
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)),
44                                self.putAttachmentEx)
45         yield ('WIKI_DELETE', ((bool, str),), self.deleteAttachment)
46         yield ('WIKI_VIEW', ((list, str),), self.listLinks)
47         yield ('WIKI_VIEW', ((str, str),), self.wikiToHtml)
48
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))
52
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()
57         cursor = db.cursor()
58         cursor.execute('SELECT name, max(time), author, version FROM wiki'
59                        ' WHERE time >= %s GROUP BY name ORDER BY max(time) DESC', (since,))
60         result = []
61         for name, time, author, version in cursor:
62             result.append(self._page_info(name, time, author, version))
63         return result
64
65     def getRPCVersionSupported(self, req):
66         """ Returns 2 with this version of the Trac API. """
67         return 2
68
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)
72         if page.exists:
73             return page.text
74         else:
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)
79
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
85
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())
89
90     def getPageInfo(self, req, pagename, version=None):
91         """ Returns information about the given page. """
92         page = WikiPage(self.env, pagename, version)
93         if page.exists:
94             last_update = page.get_history().next()
95             return self._page_info(page.name, last_update[1], last_update[2],
96                                    page.version)
97
98     def putPage(self, req, pagename, content, attributes):
99         """ writes the content of the page. """
100         page = WikiPage(self.env, pagename)
101         if page.readonly:
102             req.perm.assert_permission('WIKI_ADMIN')
103         elif not page.exists:
104             req.perm.assert_permission('WIKI_CREATE')
105         else:
106             req.perm.assert_permission('WIKI_MODIFY')
107
108         page.text = content
109         if req.perm.has_permission('WIKI_ADMIN'):
110             page.readonly = attributes.get('readonly') and 1 or 0
111
112         page.save(attributes.get('author', req.authname),
113                   attributes.get('comment'),
114                   req.remote_addr)
115         return True
116
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)]
120
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())
126
127     def putAttachment(self, req, path, data):
128         """ (over)writes an attachment. Returns True if successful.
129         
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)
134         return True
135
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.
139         
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
143         if replace:
144             try:
145                 attachment = Attachment(self.env, 'wiki', pagename, filename)
146                 attachment.delete()
147             except TracError:
148                 pass
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
154
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)
161         attachment.delete()
162         return True
163
164     def listLinks(self, req, pagename):
165         """ ''Not implemented'' """
166         return []
167
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))
Note: See TracBrowser for help on using the browser.