Esempio n. 1
0
    def xmlrpc_getDiff(self, pagename, from_rev, to_rev, n_name=None):
        """
        Gets the binary difference between two page revisions.

        @param pagename: unicode string qualifying the page name

        @param fromRev: integer specifying the source revision. May be None to
        refer to a virtual empty revision which leads to a diff
        containing the whole page.

        @param toRev: integer specifying the target revision. May be None to
        refer to the current revision. If the current revision is the same
        as fromRev, there will be a special error condition "ALREADY_CURRENT"

        @param n_name: do a tag check verifying that n_name was the normalised
        name of the last tag

        If both fromRev and toRev are None, this function acts similar to getPage, i.e. it will diff("",currentRev).

        @return: Returns a dict:
        * status (not a field, implicit, returned as Fault if not SUCCESS):
        * "SUCCESS" - if the diff could be retrieved successfully
        * "NOT_EXIST" - item does not exist
        * "FROMREV_INVALID" - the source revision is invalid
        * "TOREV_INVALID" - the target revision is invalid
        * "INTERNAL_ERROR" - there was an internal error
        * "INVALID_TAG" - the last tag does not match the supplied normalised name
        * "ALREADY_CURRENT" - this not merely an error condition. It rather means that
         there is no new revision to diff against which is a good thing while
         synchronisation.
        * current: the revision number of the current revision (not the one which was diff'ed against)
        * diff: Binary object that transports a zlib-compressed binary diff (see bdiff.py, taken from Mercurial)
        * conflict: if there is a conflict on the page currently
        """
        from MoinMoin.util.bdiff import textdiff, compress
        from MoinMoin.wikisync import TagStore

        pagename = self._instr(pagename)
        if n_name is not None:
            n_name = self._instr(n_name)

        # User may read page?
        if not self.request.user.may.read(pagename):
            return self.notAllowedFault()

        def allowed_rev_type(data):
            if data is None:
                return True
            return isinstance(data, int) and data > 0

        if not allowed_rev_type(from_rev):
            return xmlrpclib.Fault("FROMREV_INVALID",
                                   "Incorrect type for from_rev.")

        if not allowed_rev_type(to_rev):
            return xmlrpclib.Fault("TOREV_INVALID",
                                   "Incorrect type for to_rev.")

        currentpage = Page(self.request, pagename)
        if not currentpage.exists():
            return xmlrpclib.Fault("NOT_EXIST", "Page does not exist.")

        revisions = currentpage.getRevList()

        if from_rev is not None and from_rev not in revisions:
            return xmlrpclib.Fault("FROMREV_INVALID", "Unknown from_rev.")
        if to_rev is not None and to_rev not in revisions:
            return xmlrpclib.Fault("TOREV_INVALID", "Unknown to_rev.")

        # use lambda to defer execution in the next lines
        if from_rev is None:
            oldcontents = lambda: ""
        else:
            oldpage = Page(self.request, pagename, rev=from_rev)
            oldcontents = lambda: oldpage.get_raw_body_str()

        if to_rev is None:
            newpage = currentpage
            newcontents = lambda: currentpage.get_raw_body_str()
        else:
            newpage = Page(self.request, pagename, rev=to_rev)
            newcontents = lambda: newpage.get_raw_body_str()

        if oldcontents() and oldpage.get_real_rev() == newpage.get_real_rev():
            return xmlrpclib.Fault("ALREADY_CURRENT", "There are no changes.")

        if n_name is not None:
            tags = TagStore(newpage)
            last_tag = tags.get_last_tag()
            if last_tag is not None and last_tag.normalised_name != n_name:
                return xmlrpclib.Fault(
                    "INVALID_TAG",
                    "The used tag is incorrect because the normalised name does not match."
                )

        newcontents = newcontents()
        conflict = wikiutil.containsConflictMarker(newcontents)
        diffblob = xmlrpclib.Binary(
            compress(textdiff(oldcontents(), newcontents)))

        return {
            "conflict": conflict,
            "diff": diffblob,
            "diffversion": 1,
            "current": currentpage.get_real_rev()
        }
    def xmlrpc_getDiff(self, pagename, from_rev, to_rev, n_name=None):
        """
        Gets the binary difference between two page revisions.

        @param pagename: unicode string qualifying the page name

        @param fromRev: integer specifying the source revision. May be None to
        refer to a virtual empty revision which leads to a diff
        containing the whole page.

        @param toRev: integer specifying the target revision. May be None to
        refer to the current revision. If the current revision is the same
        as fromRev, there will be a special error condition "ALREADY_CURRENT"

        @param n_name: do a tag check verifying that n_name was the normalised
        name of the last tag

        If both fromRev and toRev are None, this function acts similar to getPage, i.e. it will diff("",currentRev).

        @return: Returns a dict:
        * status (not a field, implicit, returned as Fault if not SUCCESS):
        * "SUCCESS" - if the diff could be retrieved successfully
        * "NOT_EXIST" - item does not exist
        * "FROMREV_INVALID" - the source revision is invalid
        * "TOREV_INVALID" - the target revision is invalid
        * "INTERNAL_ERROR" - there was an internal error
        * "INVALID_TAG" - the last tag does not match the supplied normalised name
        * "ALREADY_CURRENT" - this not merely an error condition. It rather means that
         there is no new revision to diff against which is a good thing while
         synchronisation.
        * current: the revision number of the current revision (not the one which was diff'ed against)
        * diff: Binary object that transports a zlib-compressed binary diff (see bdiff.py, taken from Mercurial)
        * conflict: if there is a conflict on the page currently
        """
        from MoinMoin.util.bdiff import textdiff, compress
        from MoinMoin.wikisync import TagStore

        pagename = self._instr(pagename)
        if n_name is not None:
            n_name = self._instr(n_name)

        # User may read page?
        if not self.request.user.may.read(pagename):
            return self.notAllowedFault()

        def allowed_rev_type(data):
            if data is None:
                return True
            return isinstance(data, int) and data > 0

        if not allowed_rev_type(from_rev):
            return xmlrpclib.Fault("FROMREV_INVALID", "Incorrect type for from_rev.")

        if not allowed_rev_type(to_rev):
            return xmlrpclib.Fault("TOREV_INVALID", "Incorrect type for to_rev.")

        currentpage = Page(self.request, pagename)
        if not currentpage.exists():
            return xmlrpclib.Fault("NOT_EXIST", "Page does not exist.")

        revisions = currentpage.getRevList()

        if from_rev is not None and from_rev not in revisions:
            return xmlrpclib.Fault("FROMREV_INVALID", "Unknown from_rev.")
        if to_rev is not None and to_rev not in revisions:
            return xmlrpclib.Fault("TOREV_INVALID", "Unknown to_rev.")

        # use lambda to defer execution in the next lines
        if from_rev is None:
            oldcontents = lambda: ""
        else:
            oldpage = Page(self.request, pagename, rev=from_rev)
            oldcontents = lambda: oldpage.get_raw_body_str()

        if to_rev is None:
            newpage = currentpage
            newcontents = lambda: currentpage.get_raw_body_str()
        else:
            newpage = Page(self.request, pagename, rev=to_rev)
            newcontents = lambda: newpage.get_raw_body_str()

        if oldcontents() and oldpage.get_real_rev() == newpage.get_real_rev():
            return xmlrpclib.Fault("ALREADY_CURRENT", "There are no changes.")

        if n_name is not None:
            tags = TagStore(newpage)
            last_tag = tags.get_last_tag()
            if last_tag is not None and last_tag.normalised_name != n_name:
                return xmlrpclib.Fault("INVALID_TAG", "The used tag is incorrect because the normalised name does not match.")

        newcontents = newcontents()
        conflict = wikiutil.containsConflictMarker(newcontents)
        diffblob = xmlrpclib.Binary(compress(textdiff(oldcontents(), newcontents)))

        return {"conflict": conflict, "diff": diffblob, "diffversion": 1, "current": currentpage.get_real_rev()}
Esempio n. 3
0
            return xmlrpclib.Fault(
                "NOT_EXIST",
                "The page does not exist and no diff was supplied.")

        if diff is None:  # delete the page
            try:
                currentpage.deletePage(comment)
            except PageEditor.AccessDenied, (msg, ):
                return xmlrpclib.Fault("NOT_ALLOWED", msg)
            return currentpage.get_real_rev()

        # base revision used for the diff
        basepage = Page(self.request, pagename, rev=(delta_remote_rev or 0))

        # generate the new page revision by applying the diff
        newcontents = patch(basepage.get_raw_body_str(), decompress(str(diff)))
        #print "Diff against %r" % basepage.get_raw_body_str()

        # write page
        try:
            currentpage.saveText(newcontents.decode("utf-8"),
                                 last_remote_rev or 0,
                                 comment=comment)
        except PageEditor.Unchanged:  # could happen in case of both wiki's pages being equal
            pass
        except PageEditor.EditConflict:
            return LASTREV_INVALID

        current_rev = currentpage.get_real_rev()

        tags = TagStore(currentpage)
        if not currentpage.exists() and diff is None:
            return xmlrpclib.Fault("NOT_EXIST", "The page does not exist and no diff was supplied.")

        if diff is None: # delete the page
            try:
                currentpage.deletePage(comment)
            except PageEditor.AccessDenied, (msg, ):
                return xmlrpclib.Fault("NOT_ALLOWED", msg)
            return currentpage.get_real_rev()

        # base revision used for the diff
        basepage = Page(self.request, pagename, rev=(delta_remote_rev or 0))

        # generate the new page revision by applying the diff
        newcontents = patch(basepage.get_raw_body_str(), decompress(str(diff)))
        #print "Diff against %r" % basepage.get_raw_body_str()

        # write page
        try:
            currentpage.saveText(newcontents.decode("utf-8"), last_remote_rev or 0, comment=comment)
        except PageEditor.Unchanged: # could happen in case of both wiki's pages being equal
            pass
        except PageEditor.EditConflict:
            return LASTREV_INVALID

        current_rev = currentpage.get_real_rev()

        tags = TagStore(currentpage)
        tags.add(remote_wiki=interwiki_name, remote_rev=local_rev, current_rev=current_rev, direction=BOTH, normalised_name=normalised_name)