jenkins-bot has submitted this change and it was merged.
Change subject: Reimplement Site.undelete and Page.undelete ......................................................................
Reimplement Site.undelete and Page.undelete
* Reimplement Site.undelete and Page.undelete * Make Page.markDeletedRevision raise ValueError if an invalid timestamp is passed, fix marking * Add tests in page_tests.py (requires sysop) * Rename summary param for delete/undelete to reason
Site.deletedrevs needs to be updated to listdeletedrevisions for 1.25wmf.
Change-Id: I1eb2c158f6450bf7b4e9c3f26c83bb7674b9f766 Bug: T74733 --- M pywikibot/page.py M pywikibot/site.py M tests/page_tests.py 3 files changed, 96 insertions(+), 20 deletions(-)
Approvals: John Vandenberg: Looks good to me, approved jenkins-bot: Verified
diff --git a/pywikibot/page.py b/pywikibot/page.py index d96b8cb..386f6cc 100644 --- a/pywikibot/page.py +++ b/pywikibot/page.py @@ -1532,10 +1532,8 @@ self.text = template + self.text return self.save(comment=reason)
- # all these DeletedRevisions methods need to be reviewed and harmonized - # with the new framework; they do not appear functional def loadDeletedRevisions(self, step=None, total=None): - """Retrieve all deleted revisions for this Page from Special/Undelete. + """Retrieve deleted revisions for this Page.
Stores all revisions' timestamps, dates, editors and comments in self._deletedRevs attribute. @@ -1576,21 +1574,18 @@ """Mark the revision identified by timestamp for undeletion.
@param undelete: if False, mark the revision to remain deleted. - + @type undelete: bool """ if not hasattr(self, "_deletedRevs"): self.loadDeletedRevisions() if timestamp not in self._deletedRevs: - # TODO: Throw an exception? - return - self._deletedRevs[timestamp][4] = undelete - self._deletedRevsModified = True + raise ValueError(u'Timestamp %d is not a deleted revision' % timestamp) + self._deletedRevs[timestamp]['marked'] = undelete
- @deprecate_arg("throttle", None) - def undelete(self, comment=None): + @deprecate_arg('throttle', None) + @deprecate_arg('comment', 'reason') + def undelete(self, reason=None): """Undelete revisions based on the markers set by previous calls. - - NOT IMPLEMENTED.
If no calls have been made since loadDeletedRevisions(), everything will be restored. @@ -1608,11 +1603,17 @@ pg.markDeletedRevision(rev) #mark for undeletion pg.undelete('This will restore only selected revisions.')
- @param comment: The undeletion edit summary. - @type comment: basestring + @param reason: Reason for the action. + @type reason: basestring + """ - # FIXME: Site.undelete needs to be implemented. - raise NotImplementedError('Page.undelete is not implemented.') + undelete_revs = [ts for ts, rev in self._deletedRevs.items() + if 'marked' in rev and rev['marked']] + if reason is None: + pywikibot.warning('Not passing a reason for undelete() is deprecated.') + pywikibot.output(u'Undeleting %s.' % (self.title(asLink=True))) + reason = pywikibot.input(u'Please enter a reason for the undeletion:') + self.site.undelete_page(self, reason, undelete_revs)
@deprecate_arg("throttle", None) def protect(self, edit=False, move=False, create=None, upload=None, diff --git a/pywikibot/site.py b/pywikibot/site.py index b1e9c7d..1483080 100644 --- a/pywikibot/site.py +++ b/pywikibot/site.py @@ -1411,6 +1411,7 @@ 'centralauth', 'delete', 'deleteglobalaccount', + 'undelete', 'edit', 'email', 'import', @@ -3657,6 +3658,7 @@ wlgen.request["wlshow"] = "|".join(wlshow) return wlgen
+ # TODO: T75370 def deletedrevs(self, page, start=None, end=None, reverse=None, get_text=False, step=None, total=None): """Iterate deleted revisions. @@ -4114,23 +4116,64 @@ _dl_errors = { "noapiwrite": "API editing not enabled on %(site)s wiki", "writeapidenied": "User %(user)s not allowed to edit through the API", - "permissiondenied": "User %(user)s not authorized to delete pages on %(site)s wiki.", + "permissiondenied": "User %(user)s not authorized to (un)delete " + "pages on %(site)s wiki.", "cantdelete": "Could not delete [[%(title)s]]. Maybe it was deleted already.", + "cantundelete": "Could not undelete [[%(title)s]]. " + "Revision may not exist or was already undeleted." } # other errors shouldn't occur because of pre-submission checks
@must_be(group='sysop') - def deletepage(self, page, summary): + @deprecate_arg("summary", "reason") + def deletepage(self, page, reason): """Delete page from the wiki. Requires appropriate privilege level.
@param page: Page to be deleted. - @param summary: Edit summary (required!). + @type page: Page + @param reason: Deletion reason. + @type reason: basestring
""" token = self.tokens['delete'] self.lock_page(page) req = api.Request(site=self, action="delete", token=token, title=page.title(withSection=False), - reason=summary) + reason=reason) + try: + req.submit() + except api.APIError as err: + errdata = { + 'site': self, + 'title': page.title(withSection=False), + 'user': self.user(), + } + if err.code in self._dl_errors: + raise Error(self._dl_errors[err.code] % errdata) + pywikibot.debug(u"delete: Unexpected error code '%s' received." + % err.code, + _logger) + raise + finally: + self.unlock_page(page) + + @must_be(group='sysop') + @deprecate_arg("summary", "reason") + def undelete_page(self, page, reason, revisions=None): + """Undelete page from the wiki. Requires appropriate privilege level. + + @param page: Page to be deleted. + @type page: Page + @param revisions: List of timestamps to restore. If None, restores all revisions. + @type revisions: list + @param reason: Undeletion reason. + @type reason: basestring + + """ + token = self.tokens['undelete'] + self.lock_page(page) + req = api.Request(site=self, action="undelete", token=token, + title=page.title(withSection=False), + timestamps=revisions, reason=reason) try: req.submit() except api.APIError as err: diff --git a/tests/page_tests.py b/tests/page_tests.py index a756d5d..63e5e32 100644 --- a/tests/page_tests.py +++ b/tests/page_tests.py @@ -575,6 +575,38 @@ self.assertTrue(rv)
+class TestPageDelete(TestCase): + + """Test page delete / undelete actions.""" + + family = 'test' + code = 'test' + + write = True + sysop = True + + def test_delete(self): + """Test the site.delete and site.undelete method.""" + site = self.get_site() + p = pywikibot.Page(site, u'User:Unicodesnowman/DeleteTest') + # Ensure the page exists + p.text = 'pywikibot unit test page' + p.save('unit test', botflag=True) + # Test deletion + p.delete(reason='pywikibot unit test', prompt=False, mark=False) + self.assertRaises(pywikibot.NoPage, p.get, force=True) + # Test undeleting last two revisions + del_revs = list(p.loadDeletedRevisions()) + revid = p.getDeletedRevision(del_revs[-1])[u'revid'] + p.markDeletedRevision(del_revs[-1]) + p.markDeletedRevision(del_revs[-2]) + self.assertRaises(ValueError, p.markDeletedRevision, 123) + p.undelete(reason='pywikibot unit test') + revs = list(p.getVersionHistory()) + self.assertEqual(len(revs), 2) + self.assertEqual(revs[1].revid, revid) + + class TestPageProtect(TestCase):
"""Test page protect / unprotect actions."""
pywikibot-commits@lists.wikimedia.org