jenkins-bot has submitted this change. (
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1203490?usp=email )
Change subject: Add new function review_revision() to pywikibot/site/
_apisite.py
......................................................................
Add new function review_revision() to pywikibot/site/ _apisite.py
Implements the FlaggedRevs `action=review` API in Pywikibot
so that bots can approve, tag, or un-approve revisions.
Bug: T408389
Change-Id: I8a3ce367f312016ffc4c632cfbd28d254d0e2cb7
---
M pywikibot/data/api/_requests.py
M pywikibot/site/_extensions.py
M tests/flaggedrevs_tests.py
3 files changed, 206 insertions(+), 4 deletions(-)
Approvals:
jenkins-bot: Verified
Xqt: Looks good to me, approved
diff --git a/pywikibot/data/api/_requests.py b/pywikibot/data/api/_requests.py
index 8da3f14..7939fea 100644
--- a/pywikibot/data/api/_requests.py
+++ b/pywikibot/data/api/_requests.py
@@ -70,13 +70,15 @@
'strikevote', 'tag', 'thank', 'threadaction', 'transcodereset',
'translationreview', 'unblock', 'undelete', 'unlinkaccount', 'upload',
'userrights', 'watch', 'wikilove',
+ # FlaggedRevs extension
+ 'review',
# wikibase actions, see https://www.mediawiki.org/wiki/Wikibase/API
'wbcreateclaim', 'wbcreateredirect', 'wbeditentity', 'wblinktitles',
'wbmergeitems', 'wbremoveclaims', 'wbremovequalifiers',
'wbremovereferences', 'wbsetaliases', 'wbsetclaim', 'wbsetclaimvalue',
'wbsetdescription', 'wbsetlabel', 'wbsetqualifier', 'wbsetreference',
'wbsetsitelink',
- # lexeme (internal) actions
+ # WikibaseLexeme (internal) actions
'wbladdform', 'wbladdsense', 'wbleditformelements', 'wbleditsenseelements',
'wblmergelexemes', 'wblremoveform', 'wblremovesense',
}
diff --git a/pywikibot/site/_extensions.py b/pywikibot/site/_extensions.py
index 499a7f0..821d77e 100644
--- a/pywikibot/site/_extensions.py
+++ b/pywikibot/site/_extensions.py
@@ -18,8 +18,9 @@
InconsistentTitleError,
NoPageError,
SiteDefinitionError,
+ UnexpectedAPIDataError,
)
-from pywikibot.site._decorators import need_extension
+from pywikibot.site._decorators import need_extension, need_right
from pywikibot.tools import merge_unique_dicts
@@ -497,3 +498,65 @@
return None
return pages[0].get('flagged', {}).get('stable_revid')
+
+ @need_extension('FlaggedRevs')
+ @need_right('review')
+ def review_revision(
+ self,
+ revid: int,
+ *,
+ comment: str | None = None,
+ unapprove: bool = False,
+ flag: int | None = None,
+ ) -> None:
+ """Review a revision using the FlaggedRevs ``action=review`` API.
+
+ .. note::
+ Reviewing or unapproving a revision may change the stable
+ revision of the associated page. Cached
+ :attr:`BasePage.stable_revision_id
+ <page.BasePage.stable_revision_id>` values are not
+ invalidated automatically.
+
+ :param revid: Revision ID to review.
+ :param comment: Optional review comment.
+ :param unapprove: If True, the revision will be *unapproved*.
+ :param flag: Set the review flag value.
+ :raises APIError: On API failure.
+ :raises UnexpectedAPIDataError: Unexpected API data for review
+ parameters or review result.
+ :raises UnknownExtensionError: FlaggedRevs not available.
+ :raises UserRightsError: User has insufficient rights.
+ :raises ValueError: Unsupported *flag* parameter.
+ """
+ try:
+ review_params = self._paraminfo['review']['parameters']
+ except KeyError as e:
+ raise UnexpectedAPIDataError(
+ 'Unexpected API data: no param info found') from e
+
+ names = {item['name'] for item in review_params}
+ flag_param = next((p for p in names if p.startswith('flag_')), None)
+
+ params = {
+ 'action': 'review',
+ 'token': self.tokens['csrf'],
+ 'revid': revid,
+ 'comment': comment,
+ }
+
+ if flag is not None:
+ if flag_param is None:
+ raise ValueError(
+ "The 'flag' parameter is not supported by this wiki")
+ params[flag_param] = flag
+
+ if unapprove:
+ params['unapprove'] = '1'
+
+ request = self.simple_request(**params, formatversion=2)
+ data = request.submit()
+
+ if data.get('review', {}).get('result') != 'Success':
+ raise UnexpectedAPIDataError(
+ f'Unexpected review result:\n{data!r}')
diff --git a/tests/flaggedrevs_tests.py b/tests/flaggedrevs_tests.py
index 6766609..08527df 100644
--- a/tests/flaggedrevs_tests.py
+++ b/tests/flaggedrevs_tests.py
@@ -11,9 +11,9 @@
from unittest.mock import MagicMock, patch
import pywikibot
-from pywikibot.exceptions import UnknownExtensionError
+from pywikibot.exceptions import APIError, UnknownExtensionError
from pywikibot.page import Revision
-from tests.aspects import TestCase
+from tests.aspects import PatchingTestCase, TestCase
class TestPageStableRevision(TestCase):
@@ -141,6 +141,143 @@
self.assertEqual(result.revid, 999)
+class TestFlaggedRevsReview(PatchingTestCase):
+
+ """Test site.review() with flagged revisions."""
+
+ family = 'wikipedia'
+ code = 'fi'
+ dry = True
+
+ def setUp(self):
+ """Set up Test and patches."""
+ super().setUp()
+ self.token = '123ABC+\\'
+
+ self.mock_req = MagicMock()
+ self.patch(
+ pywikibot.site._apisite.APISite,
+ 'simple_request',
+ self.mock_req,
+ )
+ self.submit = self.mock_req.return_value.submit
+
+ self.patch(
+ pywikibot.site._tokenwallet.TokenWallet,
+ '__getitem__',
+ lambda *_: self.token,
+ )
+
+ self.patch(
+ pywikibot.site._apisite.APISite,
+ 'has_extension',
+ lambda *_: True,
+ )
+
+ self.patch(
+ pywikibot.site._apisite.APISite,
+ 'has_right',
+ lambda *_: True,
+ )
+
+ self.patch(
+ self.site,
+ '_paraminfo',
+ {
+ 'review': {
+ 'parameters': [
+ {'name': 'comment'},
+ {'name': 'flag_accuracy'},
+ ]
+ }
+ },
+ )
+
+ def _mock_success(self, revid: int, **extra):
+ return {
+ 'review': {
+ 'revid': revid,
+ 'result': 'Success',
+ **extra
+ }
+ }
+
+ def test_review_basic(self) -> None:
+ """Review a revision without any flags (simple approval)."""
+ revid = 12345
+ self.submit.return_value = self._mock_success(revid)
+ self.site.review_revision(revid=revid, comment='unit test')
+
+ self.mock_req.assert_called_once_with(
+ action='review',
+ token=self.token,
+ revid=revid,
+ comment='unit test',
+ formatversion=2,
+ )
+
+ def test_review_unapprove(self) -> None:
+ """Un-approve a previously approved revision."""
+ revid = 12347
+ self.submit.return_value = self._mock_success(revid)
+
+ self.site.review_revision(
+ revid=revid,
+ comment='unit test unapprove',
+ unapprove=True
+ )
+
+ self.mock_req.assert_called_once_with(
+ action='review',
+ token=self.token,
+ revid=revid,
+ comment='unit test unapprove',
+ unapprove='1',
+ formatversion=2,
+ )
+
+ def test_review_missing_token(self) -> None:
+ """Calling review() without a token raises ``notoken``."""
+ self.site.tokens.clear()
+ self.submit.side_effect = APIError(
+ code='notoken',
+ info='No CSRF token',
+ other={},
+ )
+
+ with self.assertRaises(APIError) as cm:
+ self.site.review_revision(revid=999)
+
+ self.assertEqual(cm.exception.code, 'notoken')
+
+ def test_review_insufficient_rights(self) -> None:
+ """User without ``review`` right gets ``permissiondenied``."""
+ self.submit.side_effect = APIError(
+ code='permissiondenied',
+ info="You don't have permission to review revisions.",
+ other={},
+ )
+
+ with self.assertRaises(APIError) as cm:
+ self.site.review_revision(revid=888)
+
+ self.assertEqual(cm.exception.code, 'permissiondenied')
+
+ def test_review_defaults(self) -> None:
+ """Calling review() with only revid and token is allowed."""
+ revid = 12348
+ self.submit.return_value = self._mock_success(revid)
+ self.site.review_revision(revid=revid)
+
+ self.mock_req.assert_called_once_with(
+ action='review',
+ token=self.token,
+ revid=revid,
+ comment=None,
+ formatversion=2,
+ )
+
+
if __name__ == '__main__':
with suppress(SystemExit):
unittest.main()
--
To view, visit
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1203490?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.wikimedia.org/r/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I8a3ce367f312016ffc4c632cfbd28d254d0e2cb7
Gerrit-Change-Number: 1203490
Gerrit-PatchSet: 30
Gerrit-Owner: Ezra yendau <[email protected]>
Gerrit-Reviewer: Tacsipacsi <[email protected]>
Gerrit-Reviewer: Xqt <[email protected]>
Gerrit-Reviewer: Zache-tool <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]