Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.72% covered (success)
98.72%
77 / 78
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiClient
98.72% covered (success)
98.72%
77 / 78
83.33% covered (warning)
83.33%
5 / 6
11
0.00% covered (danger)
0.00%
0 / 1
 findComment
95.00% covered (success)
95.00%
19 / 20
0.00% covered (danger)
0.00%
0 / 1
3
 getUserTalkPageInfo
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 addFollowUpComment
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
1
 addTopic
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 executeApiQuery
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 checkCommentRedirects
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare( strict_types = 1 );
4
5namespace MediaWiki\Extension\AutoModerator;
6
7use MediaWiki\Api\ApiMain;
8use MediaWiki\Api\ApiUsageException;
9use MediaWiki\Context\DerivativeContext;
10use MediaWiki\Context\RequestContext;
11use MediaWiki\Request\DerivativeRequest;
12use MediaWiki\Title\Title;
13use MediaWiki\User\User;
14
15class ApiClient {
16
17    /**
18     * Make a single call to MediaWiki API discussiontoolsfindcomment and return the decoded result.
19     *
20     * @param string $commentHeader
21     * @param Title $userTalkPageTitle
22     *
23     * @return array Decoded response
24     */
25    public function findComment( string $commentHeader, Title $userTalkPageTitle ): array {
26        try {
27            $context = new DerivativeContext( RequestContext::getMain() );
28            $headerNoEqualsSymbol = trim( str_replace( '==', '', $commentHeader ) );
29            $headerWithoutSpaces = str_replace( ' ', '_', $headerNoEqualsSymbol );
30            $userTalkPageString = $userTalkPageTitle->getPrefixedText();
31            $queryParams = [
32                'action' => 'discussiontoolsfindcomment',
33                'format' => 'json',
34                'heading' => $headerWithoutSpaces,
35                'page' => $userTalkPageString,
36                'formatversion' => '2',
37            ];
38            $data = $this->executeApiQuery( $context, $queryParams );
39        } catch ( ApiUsageException ) {
40            return [];
41        }
42
43        if ( array_key_exists( 'discussiontoolsfindcomment', $data ) ) {
44            // From findcomment, we only need the comment id and couldredirect
45            return $this->checkCommentRedirects(
46                $data['discussiontoolsfindcomment'],
47                $userTalkPageString
48            );
49        } else {
50            return [];
51        }
52    }
53
54    /**
55     * @param Title $userTalkPageTitle
56     *
57     * @return array Decoded response
58     */
59    public function getUserTalkPageInfo( Title $userTalkPageTitle ): array {
60        $context = new DerivativeContext( RequestContext::getMain() );
61        $queryParams = [
62            'action' => 'discussiontoolspageinfo',
63            'format' => 'json',
64            'page' => $userTalkPageTitle->getPrefixedText(),
65            'prop' => 'threaditemshtml',
66            'formatversion' => '2',
67        ];
68
69        return $this->executeApiQuery( $context, $queryParams );
70    }
71
72    /**
73     * Make a single call to MediaWiki API discussiontoolsfindcomment and return the decoded result.
74     *
75     * @param string $commentId
76     * @param Title $userTalkPageTitle
77     * @param string $followUpComment
78     * @param User $autoModeratorUser
79     *
80     * @return array Decoded response
81     */
82    public function addFollowUpComment(
83        string $commentId,
84        Title $userTalkPageTitle,
85        string $followUpComment,
86        User $autoModeratorUser
87    ): array {
88        $requestContext = RequestContext::getMain();
89        $requestContext->setUser( $autoModeratorUser );
90        $context = new DerivativeContext( $requestContext );
91        $context->setUser( $autoModeratorUser );
92        $token = $autoModeratorUser->getEditTokenObject( '', $context->getRequest() )->toString();
93        $queryParams = [
94            'action' => 'discussiontoolsedit',
95            'format' => 'json',
96            'paction' => 'addcomment',
97            'page' => $userTalkPageTitle->getPrefixedText(),
98            'commentid' => $commentId,
99            'wikitext' => $followUpComment,
100            'token' => $token,
101            'formatversion' => '2'
102        ];
103
104        return $this->executeApiQuery( $context, $queryParams );
105    }
106
107    /**
108     * Make a single call to MediaWiki API discussiontoolsfindcomment and return the decoded result.
109     *
110     * @param string $commentHeader
111     * @param Title $userTalkPageTitle
112     * @param string $talkPageMessage
113     * @param string $editSummary
114     * @param User $autoModeratorUser
115     *
116     * @return array Decoded response
117     */
118    public function addTopic(
119        string $commentHeader,
120        Title $userTalkPageTitle,
121        string $talkPageMessage,
122        string $editSummary,
123        User $autoModeratorUser
124    ): array {
125        $requestContext = RequestContext::getMain();
126        $requestContext->setUser( $autoModeratorUser );
127        $context = new DerivativeContext( $requestContext );
128        $context->setUser( $autoModeratorUser );
129        $token = $autoModeratorUser->getEditTokenObject( '', $context->getRequest() )->toString();
130        $queryParams = [
131            'action' => 'discussiontoolsedit',
132            'format' => 'json',
133            'paction' => 'addtopic',
134            'page' => $userTalkPageTitle->getPrefixedText(),
135            'wikitext' => $talkPageMessage,
136            'sectiontitle' => $commentHeader,
137            'summary' => $editSummary,
138            'token' => $token,
139            'formatversion' => '2'
140        ];
141
142        return $this->executeApiQuery( $context, $queryParams );
143    }
144
145    private function executeApiQuery( DerivativeContext $context, array $queryParams ): array {
146        $context->setRequest(
147            new DerivativeRequest(
148                $context->getRequest(),
149                $queryParams
150            )
151        );
152        $api = new ApiMain( $context, enableWrite: true );
153        $api->execute();
154        return $api->getResult()->getResultData();
155    }
156
157    /**
158     * Parses the discussiontoolsfindcomment API response array to check if there are any comments
159     * where we can append a follow-up message. If one exists, it returns true and the id
160     * @param array $comments
161     * @param string $userTalkPageString
162     * @return array
163     */
164    private function checkCommentRedirects( array $comments, string $userTalkPageString ): array {
165        $couldRedirect = false;
166        $commentId = '';
167        foreach ( $comments as $comment ) {
168            if ( $comment['couldredirect'] && $comment['title'] === $userTalkPageString ) {
169                $couldRedirect = true;
170                $commentId = $comment['id'];
171            }
172        }
173        return [ 'couldredirect' => $couldRedirect, 'id' => $commentId ];
174    }
175}