Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.41% covered (success)
90.41%
66 / 73
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
AutoModeratorSendRevertTalkPageMsgJob
90.41% covered (success)
90.41%
66 / 73
66.67% covered (warning)
66.67%
2 / 3
14.17
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 run
88.89% covered (warning)
88.89%
56 / 63
0.00% covered (danger)
0.00%
0 / 1
10.14
 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\AutoModeratorServices;
20use AutoModerator\Util;
21use MediaWiki\JobQueue\Job;
22use MediaWiki\Logger\LoggerFactory;
23use MediaWiki\MediaWikiServices;
24use MediaWiki\Title\Title;
25use RuntimeException;
26
27class AutoModeratorSendRevertTalkPageMsgJob extends Job {
28
29    /**
30     * @var bool
31     */
32    private bool $isRetryable = true;
33
34    /**
35     * @var int
36     */
37    private $revId;
38
39    /**
40     * @var ?string
41     */
42    private ?string $pageTitle;
43
44    /**
45     * @var int
46     */
47    private int $autoModeratorUserId;
48
49    /**
50     * @var string
51     */
52    private string $autoModeratorUserName;
53
54    /**
55     * @var string
56     */
57    private string $talkPageMessageHeader;
58
59    /**
60     * @var string
61     */
62    private string $talkPageMessageEditSummary;
63
64    /**
65     * @var string
66     */
67    private string $falsePositiveReportPageTitle;
68
69    private const NO_USER_TALK_PAGE_ERROR_MESSAGE = 'Failed to retrieve user talk page title '
70        . 'for sending AutoModerator revert talk page message.';
71
72    private const NO_PARENT_REVISION_FOUND = 'Failed to retrieve reverted revision from revision store.';
73    /**
74     * @var int
75     */
76    private $rollbackRevId;
77
78    /**
79     * @param Title $title
80     * @param array $params
81     *    - 'revId': (int)
82     *    - 'rollbackRevId': (int)
83     *    - 'autoModeratorUserId': (int)
84     *    - 'autoModeratorUserName': (string)
85     *    - 'talkPageMessageHeader': (string)
86     *    - 'talkPageMessageEditSummary': (string)
87     *    - 'falsePositiveReportPageTitle': (string)
88     */
89    public function __construct( Title $title, array $params ) {
90        parent::__construct( 'AutoModeratorSendRevertTalkPageMsgJob', $title, $params );
91        $this->pageTitle = $title;
92        $this->revId = $params['revId'];
93        $this->rollbackRevId = $params['rollbackRevId'];
94        $this->autoModeratorUserId = $params['autoModeratorUserId'];
95        $this->autoModeratorUserName = $params['autoModeratorUserName'];
96        $this->talkPageMessageHeader = $params['talkPageMessageHeader'];
97        $this->talkPageMessageEditSummary = $params['talkPageMessageEditSummary'];
98        $this->falsePositiveReportPageTitle = $params['falsePositiveReportPageTitle'];
99    }
100
101    public function run(): bool {
102        $logger = LoggerFactory::getInstance( 'AutoModerator' );
103        try {
104            $services = MediaWikiServices::getInstance();
105            $autoModeratorServices = AutoModeratorServices::wrap( $services );
106            $userFactory = $services->getUserFactory();
107            $revisionStore = $services->getRevisionStore();
108            $revision = $revisionStore->getRevisionById( $this->revId );
109            $wikiConfig = $autoModeratorServices->getAutoModeratorWikiConfig();
110            if ( !$revision ) {
111                $this->setLastError( self::NO_PARENT_REVISION_FOUND );
112                $this->setAllowRetries( false );
113                return false;
114            }
115            $userTalkPageTitle = $services->getTitleFactory()->makeTitleSafe(
116                NS_USER_TALK,
117                $revision->getUser()->getName()
118            );
119            if ( !$userTalkPageTitle ) {
120                $this->setLastError( self::NO_USER_TALK_PAGE_ERROR_MESSAGE );
121                $this->setAllowRetries( false );
122                return false;
123            }
124
125            $userTalkPage = $services->getWikiPageFactory()->newFromTitle( $userTalkPageTitle );
126
127            $autoModeratorUser = $userFactory->newFromAnyId(
128                $this->autoModeratorUserId,
129                $this->autoModeratorUserName
130            );
131
132            $apiClient = Util::initializeApiClient();
133            // Find if the User Talk page exists before we search for it
134            $findApiResponse = [];
135            if ( $userTalkPage->exists() ) {
136                $findApiResponse = $apiClient->findComment( $this->talkPageMessageHeader, $userTalkPageTitle );
137            }
138
139            if ( array_key_exists( "couldredirect", $findApiResponse ) &&
140                $findApiResponse[ "couldredirect" ] ) {
141                // AutoModerator has already posted on this User Talk page this month
142                // and the topic has not been deleted, adding a follow-up comment instead
143                $pageInfoResponse = $apiClient->getUserTalkPageInfo( $userTalkPageTitle );
144                // Getting the pageInformation to get the comment's id
145                $headerId = $findApiResponse[ "id" ];
146                $threadItems = $pageInfoResponse[ "discussiontoolspageinfo" ][ "threaditemshtml" ];
147                foreach ( $threadItems as $threadItem ) {
148                    if ( $threadItem[ "id" ] === $headerId ) {
149                        // Getting the first reply id from this thread item
150                        $commentId = $threadItem[ "replies" ][ 0 ][ "id" ];
151                        $followUpComment = wfMessage( 'automoderator-wiki-revert-message-follow-up' )->params(
152                            $this->rollbackRevId,
153                            $this->pageTitle
154                        )->plain();
155                        $apiClient->addFollowUpComment( $commentId, $userTalkPageTitle, $followUpComment,
156                            $autoModeratorUser );
157                        break;
158                    }
159                }
160            } else {
161                // AutoModerator hasn't added a User Talk page message this month,
162                // adding a new topic message
163                $talkPageMessage = wfMessage( 'automoderator-wiki-revert-message' )->params(
164                    $this->autoModeratorUserName,
165                    $this->rollbackRevId,
166                    $this->pageTitle,
167                    $this->falsePositiveReportPageTitle )->plain();
168                $helpPageLink = $wikiConfig->get( 'AutoModeratorHelpPageLink' );
169                if ( $helpPageLink ) {
170                    $helpPageBulletPoint = wfMessage( 'automoderator-wiki-revert-message-help-page' )->params(
171                        $helpPageLink
172                    )->plain();
173                    $apiClient->addTopic( $this->talkPageMessageHeader, $userTalkPageTitle,
174                        $talkPageMessage . "\n" . $helpPageBulletPoint, $this->talkPageMessageEditSummary,
175                        $autoModeratorUser );
176                } else {
177                    $apiClient->addTopic( $this->talkPageMessageHeader, $userTalkPageTitle, $talkPageMessage,
178                        $this->talkPageMessageEditSummary, $autoModeratorUser );
179                }
180            }
181
182        } catch ( RuntimeException $e ) {
183            $this->setLastError( $e->getMessage() );
184            $logger->error( $e->getMessage() );
185            return false;
186        }
187        return true;
188    }
189
190    private function setAllowRetries( bool $isRetryable ) {
191        $this->isRetryable = $isRetryable;
192    }
193
194    /**
195     * @inheritDoc
196     * @codeCoverageIgnore
197     */
198    public function allowRetries(): bool {
199        return $this->isRetryable;
200    }
201
202    /**
203     * @inheritDoc
204     * @codeCoverageIgnore
205     */
206    public function ignoreDuplicates(): bool {
207        return true;
208    }
209}