Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
13.08% |
14 / 107 |
|
50.00% |
1 / 2 |
CRAP | |
0.00% |
0 / 1 |
CheckRevision | |
13.86% |
14 / 101 |
|
50.00% |
1 / 2 |
121.01 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
execute | |
7.45% |
7 / 94 |
|
0.00% |
0 / 1 |
126.17 |
1 | <?php |
2 | |
3 | namespace AutoModerator\Maintenance; |
4 | |
5 | use AutoModerator\Config\AutoModeratorConfigLoaderStaticTrait; |
6 | use AutoModerator\RevisionCheck; |
7 | use AutoModerator\Util; |
8 | use Maintenance; |
9 | use MediaWiki\Logger\LoggerFactory; |
10 | use MediaWiki\MainConfigNames; |
11 | use MediaWiki\MediaWikiServices; |
12 | use MediaWiki\Revision\RevisionRecord; |
13 | use MediaWiki\Revision\SlotRecord; |
14 | |
15 | $IP = getenv( 'MW_INSTALL_PATH' ); |
16 | if ( $IP === false ) { |
17 | $IP = __DIR__ . '/../../..'; |
18 | } |
19 | require_once "$IP/maintenance/Maintenance.php"; |
20 | |
21 | /** |
22 | * Check a revision to see if it would be reverted |
23 | */ |
24 | class CheckRevision extends Maintenance { |
25 | |
26 | use AutoModeratorConfigLoaderStaticTrait; |
27 | |
28 | public function __construct() { |
29 | parent::__construct(); |
30 | $this->requireExtension( 'AutoModerator' ); |
31 | $this->addDescription( |
32 | 'Check a revision and report if it would be reverted based on scoring from a machine learning model.' |
33 | ); |
34 | $this->addOption( 'revid', 'Revision ID', true, true ); |
35 | $this->addOption( 'client', 'Client for score fetching', false, true ); |
36 | } |
37 | |
38 | public function execute() { |
39 | if ( !ctype_digit( $this->getoption( 'revid' ) ) ) { |
40 | $this->output( "'revid' must be an integer\n" ); |
41 | return; |
42 | } |
43 | $revId = (int)$this->getOption( 'revid' ); |
44 | if ( $revId === 0 ) { |
45 | $this->output( "'revid' must be greater than zero\n" ); |
46 | return; |
47 | } |
48 | |
49 | // setup dependencies that we get for free when running in a hook. |
50 | $services = MediaWikiServices::getInstance(); |
51 | $changeTagsStore = $services->getChangeTagsStore(); |
52 | $config = $services->getMainConfig(); |
53 | $wikiConfig = $this->getAutoModeratorWikiConfig(); |
54 | $contentHandlerFactory = $services->getContentHandlerFactory(); |
55 | $revisionLookup = $services->getRevisionLookup(); |
56 | $revisionStore = $services->getRevisionStoreFactory()->getRevisionStore(); |
57 | $userGroupManager = $services->getUserGroupManager(); |
58 | $wikiPageFactory = $services->getWikiPageFactory(); |
59 | $restrictionStore = $services->getRestrictionStore(); |
60 | $autoModeratorUser = Util::getAutoModeratorUser( $config, $userGroupManager ); |
61 | $wikiId = Util::getWikiID( $config ); |
62 | $dbr = $this->getReplicaDB(); |
63 | $tags = $changeTagsStore->getTags( $dbr, null, $revId ); |
64 | $rev = $revisionLookup->getRevisionById( $revId ); |
65 | // Check if revision or the revision user is not null |
66 | $userIdentity = $rev->getUser(); |
67 | if ( !$rev || !$userIdentity ) { |
68 | return; |
69 | } |
70 | $wikiPageId = $rev->getPageId(); |
71 | $undoSummaryMessageKey = ( !$userIdentity->isRegistered() && $config->get( MainConfigNames::DisableAnonTalk ) ) |
72 | ? 'automoderator-wiki-undo-summary-anon' : 'automoderator-wiki-undo-summary'; |
73 | $contentHandler = $contentHandlerFactory->getContentHandler( $rev->getSlot( |
74 | SlotRecord::MAIN, |
75 | RevisionRecord::RAW |
76 | )->getModel() ); |
77 | $logger = LoggerFactory::getInstance( 'AutoModerator' ); |
78 | $revisionCheck = new RevisionCheck( |
79 | $wikiPageId, |
80 | $wikiPageFactory, |
81 | $rev->getId(), |
82 | // @fixme: we should actually check for |
83 | // $originalRevId as defined in onRevisionFromEditComplete |
84 | false, |
85 | $userIdentity, |
86 | $tags, |
87 | $autoModeratorUser, |
88 | $revisionStore, |
89 | $config, |
90 | $wikiConfig, |
91 | $contentHandler, |
92 | $logger, |
93 | $userGroupManager, |
94 | $restrictionStore, |
95 | $wikiId, |
96 | wfMessage( $undoSummaryMessageKey )->rawParams( $revId, $userIdentity->getName() )->plain() |
97 | ); |
98 | if ( !$revisionCheck->passedPreCheck ) { |
99 | $this->output( "precheck skipped rev:\t$revId\n" ); |
100 | return; |
101 | } |
102 | |
103 | // Get a real score or optionally set a fake score |
104 | $score = []; |
105 | switch ( $this->getOption( 'client', 'liftwing' ) ) { |
106 | case 'liftwing': |
107 | $liftWingClient = Util::initializeLiftWingClient( $config ); |
108 | $score = $liftWingClient->get( $rev->getId() ); |
109 | break; |
110 | case 'testfail': |
111 | $score = [ |
112 | 'model_name' => 'revertrisk-language-agnostic', |
113 | 'model_version' => '3', |
114 | 'wiki_db' => 'enwiki', |
115 | 'revision_id' => $revId, |
116 | 'output' => [ |
117 | 'prediction' => true, |
118 | 'probabilities' => [ |
119 | 'true' => 1.000000000000000, |
120 | 'false' => 0.000000000000000, |
121 | ], |
122 | ], |
123 | ]; |
124 | break; |
125 | case 'testpass': |
126 | $score = [ |
127 | 'model_name' => 'revertrisk-language-agnostic', |
128 | 'model_version' => '3', |
129 | 'wiki_db' => 'enwiki', |
130 | 'revision_id' => $revId, |
131 | 'output' => [ |
132 | 'prediction' => false, |
133 | 'probabilities' => [ |
134 | 'true' => 0.000000000000000, |
135 | 'false' => 1.000000000000000, |
136 | ], |
137 | ], |
138 | ]; |
139 | break; |
140 | default: |
141 | break; |
142 | } |
143 | $reverted = json_encode( $revisionCheck->maybeRevert( $score ), JSON_FORCE_OBJECT, JSON_PRETTY_PRINT ); |
144 | $scoreStr = json_encode( $score, JSON_PRETTY_PRINT ); |
145 | $this->output( "Revision ID:\t$revId\nWould revert?\t$reverted\nScore:\t$scoreStr\n" ); |
146 | } |
147 | } |
148 | |
149 | $maintClass = CheckRevision::class; |
150 | require_once RUN_MAINTENANCE_IF_MAIN; |