Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.00% covered (success)
92.00%
69 / 75
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
AutoModeratorFetchRevScoreJob
92.00% covered (success)
92.00%
69 / 75
66.67% covered (warning)
66.67%
2 / 3
14.10
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 run
91.18% covered (success)
91.18%
62 / 68
0.00% covered (danger)
0.00%
0 / 1
10.07
 setAllowRetries
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 allowRetries
n/a
0 / 0
n/a
0 / 0
1
 ignoreDuplicates
n/a
0 / 0
n/a
0 / 0
1
1<?php
2/**
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 */
16
17namespace AutoModerator\Services;
18
19use AutoModerator\Config\AutoModeratorConfigLoaderStaticTrait;
20use AutoModerator\RevisionCheck;
21use AutoModerator\Util;
22use Job;
23use MediaWiki\Logger\LoggerFactory;
24use MediaWiki\MediaWikiServices;
25use MediaWiki\Revision\RevisionRecord;
26use MediaWiki\Revision\SlotRecord;
27use MediaWiki\Title\Title;
28use RuntimeException;
29
30class AutoModeratorFetchRevScoreJob extends Job {
31
32    use AutoModeratorConfigLoaderStaticTrait;
33
34    /**
35     * @var int
36     */
37    private $wikiPageId;
38
39    /**
40     * @var int
41     */
42    private $revId;
43
44    /**
45     * @var int|false
46     */
47    private $originalRevId;
48
49    /**
50     * @var string[]
51     */
52    private $tags;
53
54    /**
55     * @var bool
56     */
57    private bool $isRetryable = true;
58
59    /**
60     * @var string
61     */
62    private string $undoSummary;
63
64    /**
65     * @param Title $title
66     * @param array $params
67     *    - 'wikiPageId': (int)
68     *    - 'revId': (int)
69     *    - 'originalRevId': (int|false)
70     *    - 'userId': (int)
71     *    - 'userName': (string)
72     *    - 'tags': (string[])
73     *    - 'undoSummary': (string)
74     */
75    public function __construct( Title $title, array $params ) {
76        parent::__construct( 'AutoModeratorFetchRevScoreJob', $title, $params );
77        $this->wikiPageId = $params[ 'wikiPageId' ];
78        $this->revId = $params[ 'revId' ];
79        $this->originalRevId = $params[ 'originalRevId' ];
80        $this->tags = $params[ 'tags' ];
81        $this->undoSummary = $params[ 'undoSummary' ];
82    }
83
84    public function run(): bool {
85        $services = MediaWikiServices::getInstance();
86        $wikiPageFactory = $services->getWikiPageFactory();
87        $revisionStore = $services->getRevisionStore();
88        $contentHandlerFactory = $services->getContentHandlerFactory();
89        $userGroupManager = $services->getUserGroupManager();
90        $restrictionStore = $services->getRestrictionStore();
91        $config = $services->getMainConfig();
92        $wikiConfig = $this->getAutoModeratorWikiConfig();
93        $userFactory = $services->getUserFactory();
94        $user = $userFactory->newFromAnyId(
95            $this->params['userId'],
96            $this->params['userName']
97        );
98
99        $autoModeratorUser = Util::getAutoModeratorUser( $config, $userGroupManager );
100        $wikiId = Util::getWikiID( $config );
101        $logger = LoggerFactory::getInstance( 'AutoModerator' );
102        $rev = $revisionStore->getRevisionById( $this->revId );
103        if ( $rev === null ) {
104            $message = 'rev rev_id not found';
105            $error = strtr( $message, [
106                'rev_id' => (string)$this->revId
107            ] );
108            $this->setLastError( $error );
109            $this->setAllowRetries( true );
110            return false;
111        }
112        $contentHandler = $contentHandlerFactory->getContentHandler( $rev->getSlot(
113            SlotRecord::MAIN,
114            RevisionRecord::RAW
115        )->getModel() );
116
117        $liftWingClient = Util::initializeLiftWingClient( $config );
118        $reverted = [];
119        try {
120            $response = $liftWingClient->get( $this->revId );
121            $this->setAllowRetries( $response[ 'allowRetries' ] ?? true );
122            if ( isset( $response['errorMessage'] ) ) {
123                $this->setLastError( $response['errorMessage'] );
124                return false;
125            }
126            $revisionCheck = new RevisionCheck(
127                $this->wikiPageId,
128                $wikiPageFactory,
129                $this->revId,
130                $this->originalRevId,
131                $user,
132                $this->tags,
133                $autoModeratorUser,
134                $revisionStore,
135                $config,
136                $wikiConfig,
137                $contentHandler,
138                $logger,
139                $userGroupManager,
140                $restrictionStore,
141                $wikiId,
142                $this->undoSummary,
143                true
144            );
145            $reverted = $revisionCheck->maybeRevert( $response );
146        } catch ( RuntimeException $exception ) {
147            $this->setLastError( $exception->getMessage() );
148            return false;
149        }
150        // Revision reverted
151        if ( array_key_exists( '1', $reverted ) && $reverted['1'] === 'success' ) {
152            return true;
153        }
154        // Revert attempted but failed
155        if ( array_key_exists( '0', $reverted ) && $reverted['0'] === 'failure' ) {
156            $this->setLastError( 'Revision ' . $this->revId . ' requires a manual revert.' );
157            $this->setAllowRetries( false );
158            return false;
159        }
160        // Revision passed check; noop.
161        if ( array_key_exists( '0', $reverted ) && $reverted['0'] === 'Not reverted' ) {
162            return true;
163        }
164        return false;
165    }
166
167    private function setAllowRetries( bool $isRetryable ) {
168        $this->isRetryable = $isRetryable;
169    }
170
171    /**
172     * @inheritDoc
173     * @codeCoverageIgnore
174     */
175    public function allowRetries(): bool {
176        return $this->isRetryable;
177    }
178
179    /**
180     * @inheritDoc
181     * @codeCoverageIgnore
182     */
183    public function ignoreDuplicates(): bool {
184        return true;
185    }
186}