def execute(xmlrpcobj, pagename, filename, action='save', content=None, overwrite=False, log=True): request = xmlrpcobj.request _ = request.getText pagename = xmlrpcobj._instr(pagename) filename = xmlrpcobj._instr(filename) pagename = normalize_pagename(pagename, request.cfg) # Fault at empty pagenames if not pagename: return xmlrpclib.Fault(3, _("No page name entered")) if action == 'list': success = list(request, pagename) elif action == 'load': success = load(request, pagename, filename) elif action == 'delete': success = delete(request, pagename, filename, log) elif action == 'save' and content: success = save(request, pagename, filename, content.data, overwrite, log) else: success = xmlrpclib.Fault(3, _("No method specified or empty data")) # Save, delete return True on success if success is True: return xmlrpclib.Boolean(1) # Other results include the faults and the binary attachments return success
def metaWeblog_newPost(request, blogid, username, password, struct, publish): """ Create a new entry on the server Part of the metaWeblog API if py['xmlrpc_metaweblog_ping'] == 'True' then autoping will be invoked to generate trackbacks and pingbacks @param request: the pyblosxom Request instance @type request: Request @param username: the username @type username: string @param password: the password @type password: string @param struct: the metaWeblog API struct @type struct: dict @param publish: to publish (true) or not @type publish: boolean """ # tools.log("newPost %s %s %s" % (blogid, struct, publish)) authenticate(request, username, password) config = request.getConfiguration() ping = config.get('xmlrpc_metaweblog_ping', 0) postId = _buildPostId(request, blogid, struct) result = _writePost(config, username, postId, struct, publish, ping) if result: return postId else: return xmlrpclib.Boolean(False)
def xmlrpc_putAttachment(self, pagename, attachname, data): """ Store <data> as content of attachment <attachname> of page <pagename>. @param pagename: pagename (utf-8) @param attachname: attachment name (utf-8) @param data: file data (base64) @rtype: bool @return: True if attachment was successfully stored """ pagename = self._instr(pagename) # User may read page? if not self.request.user.may.read(pagename): return self.notAllowedFault() # also check ACLs if not self.request.user.may.write(pagename): return xmlrpclib.Fault(1, "You are not allowed to edit this page") attachname = wikiutil.taintfilename(self._instr(attachname)) filename = AttachFile.getFilename(self.request, pagename, attachname) if os.path.exists(filename) and not os.path.isfile(filename): return self.noSuchPageFault() open(filename, 'wb+').write(data.data) AttachFile._addLogEntry(self.request, 'ATTNEW', pagename, attachname) return xmlrpclib.Boolean(1)
def initAgentList(self): self.agents = [] self.agents.append(["Red", True]) self.agents.append(["Hot", False]) self.agents.append(["Chili", True]) self.agents.append(["Pepper", False]) return xmlrpclib.Boolean(True)
def metaWeblog_editPost(request, postid, username, password, struct, publish): """ Edit an existing post Part of the metaWeblog API @param request: the pyblosxom Request instance @type request: Request @param username: the username @type username: string @param password: the password @type password: string @param struct: the metaWeblog api struct @type struct: dict @param publish: to publish (true) or not @type publish: boolean @returns an xmlrpclib boolean -- true if the edit was successful, false otherwise """ # tools.log("editPost %s %s %s" % (postid, struct, publish)) authenticate(request, username, password) config = request.getConfiguration() ping = config.get('xmlrpc_metaweblog_ping', 0) return xmlrpclib.Boolean( _writePost(config, username, postid, struct, publish, ping))
def deleteAgent(self, agent): lv_index = 0 for i in self.agents: if (self.agents[lv_index][0] == agent): del self.agents[lv_index] else: lv_index = lv_index + 1 return xmlrpclib.Boolean(True)
def bloggerUpdatePost(self, content): """Updates a post with the content given.""" boolTrue = xmlrpclib.Boolean(1) if (not self.checkSetupOK()): return 0 try: self.bloggerSite.blogger.editPost(self.settings["appkey"], \ self.currentPostId, \ self.prefs["username"], \ self.getPassword(), \ content, \ boolTrue) self.setErrorMessage("") except xmlrpclib.Fault, e: self.setErrorMessage("Error updating post: %s" % e.faultString) return 0
def bloggerSetTemplate(self, type, text): """Sets a template for the current blog.""" boolTrue = xmlrpclib.Boolean(1) if (not self.checkSetupOK()): return 0 try: self.bloggerSite.blogger.setTemplate(self.settings["appkey"], \ self.blogs[self.prefs["activeBlog"]-1]["blogid"],\ self.prefs["username"], \ self.getPassword(), \ text, type) self.setErrorMessage("") except xmlrpclib.Fault, e: self.setErrorMessage("Error saving template: %s" % e.faultString) return 0
def bloggerFetchPreviousPosts(self, number = 10): """Fetchs a list of previous posts from the Blogger server.""" boolTrue = xmlrpclib.Boolean(1) if (not self.checkSetupOK()): return 0 try: self.blogs[self.prefs["activeBlog"]-1]["previousPosts"] = \ self.bloggerSite.blogger.getRecentPosts(self.settings["appkey"], \ self.blogs[self.prefs["activeBlog"]-1]["blogid"],\ self.prefs["username"], \ self.getPassword(), \ number) self.setErrorMessage("") except xmlrpclib.Fault, e: self.setErrorMessage("Error downloading previous posts: %s" % e.faultString) return 0
def createPost(self, blogid, content, publish): rpcServer = xmlrpclib.ServerProxy(self.endpoint) """ content['title'] content['description'] content['mt_excerpt'] content['mt_text_more'] content['dateCreated'] content['mt_keywords'] content['mt_tb_ping_urls'] content['mt_allow_comments'] content['mt_allow_pings'] content['mt_convert_breaks'] content['categories'] """ publish = xmlrpclib.Boolean(publish) # these categories are in the format expected by mt.setPostCategories # passing then to metaWeblog.newPos, that expects another format, can raise a exception categories = content.pop('categories') # Sanitize time for xmlrpc transport if needed. if content['dateCreated']: if isinstance(content['dateCreated'], xmlrpclib.DateTime) == False: content['dateCreated'] = xmlrpclib.DateTime( content['dateCreated']) try: result = rpcServer.metaWeblog.newPost(blogid, self.username, self.password, content, publish) except: # Some systems want an int instead of a boolean value. We'll assuage their # craziness for now. if publish == True: publish = 1 else: publish = 0 try: result = rpcServer.metaWeblog.newPost(blogid, self.username, self.password, content, publish) except Exception, e: raise Exception, str(e)
def xmlrpc_deleteAttachment(self, pagename, attachname): """ Deletes attachment <attachname> of page <pagename>. @param pagename: pagename (utf-8) @param attachname: attachment name (utf-8) @rtype: bool @return: True on success """ pagename = self._instr(pagename) if not self.request.user.may.delete(pagename): return xmlrpclib.Fault( 1, 'You are not allowed to delete attachments on this page.') attachname = wikiutil.taintfilename(self._instr(attachname)) filename = AttachFile.getFilename(self.request, pagename, attachname) AttachFile.remove_attachment(self.request, pagename, attachname) return xmlrpclib.Boolean(1)
def bloggerDeletePost(self, index): """Deletes a post.""" boolTrue = xmlrpclib.Boolean(1) postid = self.blogs[self.prefs["activeBlog"] - 1]["previousPosts"][index]["postid"] if (not self.checkSetupOK()): return 0 try: self.bloggerSite.blogger.deletePost(self.settings["appkey"], \ postid, \ self.prefs["username"], \ self.getPassword(), \ boolTrue) self.blogs[self.prefs["activeBlog"]-1]["previousPosts"][index:index+1] = [] self.setErrorMessage("") except xmlrpclib.Fault, e: self.setErrorMessage("Error deleting post: %s" % e.faultString) return 0
def bloggerBlogText(self, text): """Blogs the text to the chosen blog within the current Blogger account.""" boolTrue = xmlrpclib.Boolean(1) if (not self.checkSetupOK()): return if text == "": self.setErrorMessage("Text to blog can't be blank. (You may want to check the output mode.)") return 0 try: postid = self.bloggerSite.blogger.newPost(self.settings["appkey"], \ self.blogs[self.prefs["activeBlog"]-1]["blogid"], \ self.prefs["username"], \ self.getPassword(), \ text, boolTrue) self.setErrorMessage("") except xmlrpclib.Fault, e: self.setErrorMessage("Error adding text to homepage: %s" % e.faultString) return 0
def execute(xmlrpcobj, pagename, comment = None): request = xmlrpcobj.request _ = request.getText pagename = xmlrpcobj._instr(pagename) pagename = normalize_pagename(pagename, request.cfg) # Fault at empty pagenames if not pagename: return xmlrpclib.Fault(2, _("No page name entered")) if comment: comment = xmlrpcobj._instr(comment) else: comment = u'' success = delete(request, pagename, comment) # Save, delete return True on success if success is True: return xmlrpclib.Boolean(1) # Other results include the faults and the binary attachments return success
class XmlRpcBase: """ XMLRPC base class with common functionality of wiki xmlrpc v1 and v2 """ def __init__(self, request): """ Initialize an XmlRpcBase object. @param request: the request object """ self.request = request self.version = None # this has to be defined in derived class self.cfg = request.cfg ############################################################################# ### Helper functions ############################################################################# def _instr(self, text): """ Convert inbound string. @param text: the text to convert (encoded str or unicode) @rtype: unicode @return: text as unicode """ raise NotImplementedError("please implement _instr in derived class") def _outstr(self, text): """ Convert outbound string. @param text: the text to convert (encoded str or unicode) @rtype: str @return: text as encoded str """ raise NotImplementedError("please implement _outstr in derived class") def _inlob(self, text): """ Convert inbound base64-encoded utf-8 to Large OBject. @param text: the text to convert @rtype: unicode @return: text """ text = text.data # this is a already base64-decoded 8bit string text = unicode(text, 'utf-8') return text def _outlob(self, text): """ Convert outbound Large OBject to base64-encoded utf-8. @param text: the text, either unicode or utf-8 string @rtype: str @return: xmlrpc Binary object """ if isinstance(text, unicode): text = text.encode('utf-8') else: if config.charset != 'utf-8': text = unicode(text, config.charset).encode('utf-8') return xmlrpclib.Binary(text) def _dump_exc(self): """ Convert an exception to a string. @rtype: str @return: traceback as string """ import traceback return "%s: %s\n%s" % ( sys.exc_info()[0], sys.exc_info()[1], '\n'.join(traceback.format_tb(sys.exc_info()[2])), ) def process(self): """ xmlrpc v1 and v2 dispatcher """ request = self.request try: if 'xmlrpc' in self.request.cfg.actions_excluded: # we do not handle xmlrpc v1 and v2 differently response = xmlrpclib.Fault( 1, "This moin wiki does not allow xmlrpc method calls.") else: # overwrite any user there might be, if you need a valid user for # xmlrpc, you have to use multicall and getAuthToken / applyAuthToken if request.cfg.xmlrpc_overwrite_user: request.user = user.User(request, auth_method='xmlrpc:invalid') data = request.read() try: params, method = xmlrpclib.loads(data) except: # if anything goes wrong here, we want to see the raw data: logging.debug("Length of raw data: %d bytes" % len(data)) logging.debug(logging_tearline % 'request raw data begin') logging.debug('%r' % data) logging.debug(logging_tearline % 'request raw data end') raise logging.debug(logging_tearline % 'request parsed data begin') logging.debug('%s(%r)' % (method, params)) logging.debug(logging_tearline % 'request parsed data end') response = self.dispatch(method, params) except: logging.exception( "An exception occurred (this is also sent as fault response to the client):" ) # report exception back to client response = xmlrpclib.dumps(xmlrpclib.Fault(1, self._dump_exc())) else: logging.debug(logging_tearline % 'response begin') logging.debug(response) logging.debug(logging_tearline % 'response end') if isinstance(response, xmlrpclib.Fault): response = xmlrpclib.dumps(response) else: # wrap response in a singleton tuple response = (response, ) # serialize it response = xmlrpclib.dumps(response, methodresponse=1, allow_none=True) request = request.request request.content_type = 'text/xml' request.data = response return request def dispatch(self, method, params): """ call dispatcher - for method==xxx it either locates a method called xmlrpc_xxx or loads a plugin from plugin/xmlrpc/xxx.py """ method = method.replace(".", "_") try: fn = getattr(self, 'xmlrpc_' + method) except AttributeError: try: fn = wikiutil.importPlugin(self.request.cfg, 'xmlrpc', method, 'execute') except wikiutil.PluginMissingError: response = xmlrpclib.Fault(1, "No such method: %s." % method) else: response = fn(self, *params) else: response = fn(*params) return response # Common faults ----------------------------------------------------- def notAllowedFault(self): return xmlrpclib.Fault(1, "You are not allowed to read this page.") def noSuchPageFault(self): return xmlrpclib.Fault(1, "No such page was found.") def noLogEntryFault(self): return xmlrpclib.Fault(1, "No log entry was found.") ############################################################################# ### System methods ############################################################################# def xmlrpc_system_multicall(self, call_list): """ system.multicall([{'methodName': 'add', 'params': [2, 2]}, ...]) => [[4], ...] Allows the caller to package multiple XML-RPC calls into a single request. See http://www.xmlrpc.com/discuss/msgReader$1208 Copied from SimpleXMLRPCServer.py """ results = [] for call in call_list: method_name = call['methodName'] params = call['params'] try: # XXX A marshalling error in any response will fail the entire # multicall. If someone cares they should fix this. result = self.dispatch(method_name, params) if not isinstance(result, xmlrpclib.Fault): results.append([result]) else: results.append({ 'faultCode': result.faultCode, 'faultString': result.faultString }) except: results.append({ 'faultCode': 1, 'faultString': "%s:%s" % (sys.exc_type, sys.exc_value) }) return results ############################################################################# ### Interface implementation ############################################################################# def xmlrpc_getRPCVersionSupported(self): """ Returns version of the Wiki xmlrpc API. @rtype: int @return: 1 or 2 (wikirpc version) """ return self.version def xmlrpc_getAllPages(self): """ Get all pages readable by current user @rtype: list @return: a list of all pages. """ # the official WikiRPC interface is implemented by the extended method as well return self.xmlrpc_getAllPagesEx() def xmlrpc_getAllPagesEx(self, opts=None): """ Get all pages readable by current user. Not an WikiRPC method. @param opts: dictionary that can contain the following arguments: include_system:: set it to false if you do not want to see system pages include_revno:: set it to True if you want to have lists with [pagename, revno] include_deleted:: set it to True if you want to include deleted pages exclude_non_writable:: do not include pages that the current user may not write to include_underlay:: return underlay pagenames as well prefix:: the page name must begin with this prefix to be included mark_deleted:: returns the revision number -rev_no if the page was deleted. Makes only sense if you enable include_revno and include_deleted. @rtype: list @return: a list of all pages. """ from MoinMoin.wikisync import normalise_pagename options = { "include_system": True, "include_revno": False, "include_deleted": False, "exclude_non_writable": False, "include_underlay": True, "prefix": "", "pagelist": None, "mark_deleted": False } if opts is not None: options.update(opts) if not options["include_system"]: p_filter = lambda name: not wikiutil.isSystemPage( self.request, name) else: p_filter = lambda name: True if options["exclude_non_writable"]: p_filter = lambda name, p_filter=p_filter: p_filter( name) and self.request.user.may.write(name) if options["prefix"] or options["pagelist"]: def p_filter(name, p_filter=p_filter, prefix=(options["prefix"] or ""), pagelist=options["pagelist"]): if not p_filter(name): return False n_name = normalise_pagename(name, prefix) if not n_name: return False if not pagelist: return True return n_name in pagelist pagelist = self.request.rootpage.getPageList( filter=p_filter, exists=not options["include_deleted"], include_underlay=options["include_underlay"], return_objects=options["include_revno"]) if options['include_revno']: pages = [] for page in pagelist: revno = page.get_real_rev() if options["mark_deleted"] and not page.exists(): revno = -revno pages.append([self._outstr(page.page_name), revno]) return pages else: return [self._outstr(page) for page in pagelist] def xmlrpc_getRecentChanges(self, date): """ Get RecentChanges since date @param date: date since when rc will be listed @rtype: list @return: a list of changed pages since date, which should be in UTC. The result is a list, where each element is a struct: * name (string) : Name of the page. The name is in UTF-8. * lastModified (date) : Date of last modification, in UTC. * author (string) : Name of the author (if available). UTF-8. * version (int) : Current version. """ return_items = [] edit_log = editlog.EditLog(self.request) for log in edit_log.reverse(): # get last-modified UTC (DateTime) from log gmtuple = tuple( time.gmtime(wikiutil.version2timestamp(log.ed_time_usecs))) lastModified_date = xmlrpclib.DateTime(gmtuple) # skip if older than "date" if lastModified_date < date: break # skip if knowledge not permitted if not self.request.user.may.read(log.pagename): continue # get page name (str) from log pagename_str = self._outstr(log.pagename) # get user name (str) from log author_str = log.hostname if log.userid: userdata = user.User(self.request, log.userid) if userdata.name: author_str = userdata.name author_str = self._outstr(author_str) return_item = { 'name': pagename_str, 'lastModified': lastModified_date, 'author': author_str, 'version': int(log.rev) } return_items.append(return_item) return return_items def xmlrpc_getPageInfo(self, pagename): """ Invoke xmlrpc_getPageInfoVersion with rev=None """ return self.xmlrpc_getPageInfoVersion(pagename, rev=None) def xmlrpc_getPageInfoVersion(self, pagename, rev): """ Return page information for specific revision @param pagename: the name of the page (utf-8) @param rev: revision to get info about (int) @rtype: dict @return: page information * name (string): the canonical page name, UTF-8. * lastModified (date): Last modification date, UTC. * author (string): author name, UTF-8. * version (int): current version """ pn = self._instr(pagename) # User may read this page? if not self.request.user.may.read(pn): return self.notAllowedFault() if rev is not None: page = Page(self.request, pn, rev=rev) else: page = Page(self.request, pn) rev = page.current_rev() # Non existing page? if not page.exists(): return self.noSuchPageFault() # Get page info edit_info = page.edit_info() if not edit_info: return self.noLogEntryFault() mtime = wikiutil.version2timestamp(long( edit_info['timestamp'])) # must be long for py 2.2.x gmtuple = tuple(time.gmtime(mtime)) version = rev # our new rev numbers: 1,2,3,4,.... ####################################################################### # BACKWARDS COMPATIBILITY CODE - remove when 1.2.x is regarded stone age # as we run a feed for BadContent on MoinMaster, we want to stay # compatible here for a while with 1.2.x moins asking us for BadContent # 1.3 uses the lastModified field for checking for updates, so it # should be no problem putting the old UNIX timestamp style of version # number in the version field if self.request.cfg.sitename == 'MoinMaster' and pagename == 'BadContent': version = int(mtime) ####################################################################### return { 'name': self._outstr(page.page_name), 'lastModified': xmlrpclib.DateTime(gmtuple), 'author': self._outstr(edit_info['editor']), 'version': version, } def xmlrpc_getProcessingInstruction(self, pagename, pi): """ Invoke getProcessingInstructionVersion with rev=None """ return self.xmlrpc_getProcessingInstructionVersion(pagename, rev=None, pi=pi) def xmlrpc_getProcessingInstructionVersion(self, pagename, rev, pi): """ Returns value of Processing Instruction @param pagename: pagename (utf-8) @param rev: revision number (int) @param pi: PI key """ # User may read page? if not self.request.user.may.read(pagename): return self.notAllowedFault() if rev is not None: page = Page(self.request, pagename, rev=rev) else: page = Page(self.request, pagename) if not page.exists(): return xmlrpclib.Fault("NOT_EXIST", "Page does not exist.") if pi is None: return xmlrpclib.Fault("NOT_EXIST", "Processing Instruction not given.") try: instruction = page.pi[pi] except KeyError: return xmlrpclib.Fault("NOT_EXIST", "Processing Instruction does not exist.") return self._outstr(instruction) def xmlrpc_getPage(self, pagename): """ Invoke xmlrpc_getPageVersion with rev=None """ return self.xmlrpc_getPageVersion(pagename, rev=None) def xmlrpc_getPageVersion(self, pagename, rev): """ Get raw text from specific revision of pagename @param pagename: pagename (utf-8) @param rev: revision number (int) @rtype: str @return: utf-8 encoded page data """ pagename = self._instr(pagename) # User may read page? if not self.request.user.may.read(pagename): return self.notAllowedFault() if rev is not None: page = Page(self.request, pagename, rev=rev) else: page = Page(self.request, pagename) # Non existing page? if not page.exists(): return self.noSuchPageFault() # Return page raw text if self.version == 2: return self._outstr(page.get_raw_body()) elif self.version == 1: return self._outlob(page.get_raw_body()) def xmlrpc_getPageHTML(self, pagename): """ Invoke xmlrpc_getPageHTMLVersion with rev=None """ return self.xmlrpc_getPageHTMLVersion(pagename, rev=None) def xmlrpc_getPageHTMLVersion(self, pagename, rev): """ Get HTML of from specific revision of pagename @param pagename: the page name (utf-8) @param rev: revision number (int) @rtype: str @return: page in rendered HTML (utf-8) """ pagename = self._instr(pagename) # User may read page? if not self.request.user.may.read(pagename): return self.notAllowedFault() if rev is not None: page = Page(self.request, pagename, rev=rev) else: page = Page(self.request, pagename) # Non existing page? if not page.exists(): return self.noSuchPageFault() # Render page into a buffer result = self.request.redirectedOutput(page.send_page, content_only=1) # Return rendered page if self.version == 2: return self._outstr(result) elif self.version == 1: return xmlrpclib.Binary(result) def xmlrpc_listLinks(self, pagename): """ list links for a given page @param pagename: the page name @rtype: list @return: links of the page, structs, with the following elements * name (string) : The page name or URL the link is to, UTF-8 encoding. * type (int) : The link type. Zero (0) for internal Wiki link, one (1) for external link (URL - image link, whatever). """ pagename = self._instr(pagename) # User may read page? if not self.request.user.may.read(pagename): return self.notAllowedFault() page = Page(self.request, pagename) # Non existing page? if not page.exists(): return self.noSuchPageFault() links_out = [] for link in page.getPageLinks(self.request): links_out.append({'name': self._outstr(link), 'type': 0}) return links_out def xmlrpc_putPage(self, pagename, pagetext): """ save a page / change a page to a new text @param pagename: the page name (unicode or utf-8) @param pagetext: the new page text (content, unicode or utf-8) @rtype: bool @return: True on success """ pagename = self._instr(pagename) pagename = wikiutil.normalize_pagename(pagename, self.cfg) if not pagename: return xmlrpclib.Fault("INVALID", "pagename can't be empty") # check ACLs if not self.request.user.may.write(pagename): return xmlrpclib.Fault(1, "You are not allowed to edit this page") page = PageEditor(self.request, pagename, do_editor_backup=0) try: if self.version == 2: newtext = self._instr(pagetext) elif self.version == 1: newtext = self._inlob(pagetext) msg = page.saveText(newtext, 0) except page.SaveError, msg: logging.error("SaveError: %s" % msg) return xmlrpclib.Fault(1, "%s" % msg) # Update pagelinks cache page.getPageLinks(self.request) return xmlrpclib.Boolean(1)
if not pagename: return xmlrpclib.Fault("INVALID", "pagename can't be empty") # check ACLs if not (self.request.user.may.delete(pagename) and self.request.user.may.write(newpagename)): return xmlrpclib.Fault(1, "You are not allowed to rename this page") editor = PageEditor(self.request, pagename, do_editor_backup=0) try: editor.renamePage(newpagename) except PageEditor.SaveError, error: return xmlrpclib.Fault(1, "Rename failed: %s" % (str(error), )) return xmlrpclib.Boolean(1) def xmlrpc_revertPage(self, pagename, revision): """ Revert a page to previous revision This is mainly intended to be used by the jabber bot. @param pagename: the page name (unicode or utf-8) @param revision: revision to revert to @rtype: bool @return: True on success """ pagename = self._instr(pagename)
def update(self, param): param.update({'bool_value': xmlrpclib.Boolean(self.value)})
def update(self, param): param.update( {'bool_prop': { 'default_value': xmlrpclib.Boolean(self.defval) }})
def appendAgentList(self, name, status): self.agents.append([name, status]) return xmlrpclib.Boolean(True)