Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
MassMessageHooks
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 12
1406
0.00% covered (danger)
0.00%
0 / 1
 onParserFirstCallInit
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 outputParserFunction
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 storeDataParserFunction
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 onUserGetReservedNames
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onAPIQuerySiteInfoStatisticsInfo
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onSkinTemplateNavigation__Universal
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
240
 onBeforePageDisplay
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
30
 onRejectParserCacheValue
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 onEmailConfirmed
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 onListDefinedTags
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onChangeTagsListActive
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addRegisterTags
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3// phpcs:disable MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName
4
5namespace MediaWiki\MassMessage;
6
7use MediaWiki\Api\Hook\APIQuerySiteInfoStatisticsInfoHook;
8use MediaWiki\ChangeTags\Hook\ChangeTagsListActiveHook;
9use MediaWiki\ChangeTags\Hook\ListDefinedTagsHook;
10use MediaWiki\Hook\BeforePageDisplayHook;
11use MediaWiki\Hook\ParserFirstCallInitHook;
12use MediaWiki\Hook\RejectParserCacheValueHook;
13use MediaWiki\Hook\SkinTemplateNavigation__UniversalHook;
14use MediaWiki\MediaWikiServices;
15use MediaWiki\Output\OutputPage;
16use MediaWiki\Parser\ParserOutput;
17use MediaWiki\SpecialPage\SpecialPage;
18use MediaWiki\User\Hook\UserGetReservedNamesHook;
19use MediaWiki\User\User;
20use Parser;
21use ParserOptions;
22use Skin;
23use WikiPage;
24
25/**
26 * Hooks!
27 */
28
29class MassMessageHooks implements
30    ParserFirstCallInitHook,
31    APIQuerySiteInfoStatisticsInfoHook,
32    UserGetReservedNamesHook,
33    SkinTemplateNavigation__UniversalHook,
34    BeforePageDisplayHook,
35    ListDefinedTagsHook,
36    ChangeTagsListActiveHook,
37    RejectParserCacheValueHook
38{
39
40    /**
41     * Hook to load our parser function.
42     *
43     * @param Parser $parser
44     */
45    public function onParserFirstCallInit( $parser ) {
46        $parser->setFunctionHook( 'target', [ __CLASS__, 'outputParserFunction' ] );
47    }
48
49    /**
50     * Main parser function for {{#target:User talk:Example|en.wikipedia.org}}.
51     * Prepares the human facing output.
52     * Hostname is optional for local delivery.
53     *
54     * @param Parser $parser
55     * @param string $page
56     * @param string $site
57     * @return array
58     */
59    public static function outputParserFunction( Parser $parser, $page, $site = '' ) {
60        $config = MediaWikiServices::getInstance()->getMainConfig();
61
62        $parser->addTrackingCategory( 'massmessage-list-category' );
63
64        $data = MassMessage::processPFData( $page, $site );
65        if ( isset( $data['error'] ) ) {
66            return $data;
67        }
68
69        // Use a message so wikis can customize the output.
70        if ( $config->get( 'AllowGlobalMessaging' ) ) {
71            $msg = wfMessage( 'massmessage-target' )
72                ->params( $data['site'], $config->get( 'Script' ), $data['title'] )->plain();
73        } else {
74            $msg = wfMessage( 'massmessage-target-local' )->params( $data['title'] )->plain();
75        }
76
77        return [ $msg, 'noparse' => false ];
78    }
79
80    /**
81     * Reads the parser function and extracts the data from it.
82     *
83     * @param Parser $parser
84     * @param string $page
85     * @param string $site
86     * @return string
87     */
88    public static function storeDataParserFunction( Parser $parser, $page, $site = '' ) {
89        $data = MassMessage::processPFData( $page, $site );
90        if ( isset( $data['error'] ) ) {
91            // Output doesn't matter
92            return '';
93        }
94        $output = $parser->getOutput();
95        $current = $output->getExtensionData( 'massmessage-targets' );
96        if ( !$current ) {
97            $output->setExtensionData( 'massmessage-targets', [ $data ] );
98        } else {
99            $output->setExtensionData( 'massmessage-targets',
100                array_merge( $current, [ $data ] ) );
101        }
102        return '';
103    }
104
105    /**
106     * Add our username to the list of reserved ones
107     *
108     * @param array &$reservedUsernames
109     */
110    public function onUserGetReservedNames( &$reservedUsernames ) {
111        $reservedUsernames[] = MediaWikiServices::getInstance()->getMainConfig()->get( 'MassMessageAccountUsername' );
112    }
113
114    /**
115     * Add the number of queued messages to &meta=siteinfo&siprop=statistics.
116     *
117     * @param array &$result
118     */
119    public function onAPIQuerySiteInfoStatisticsInfo( &$result ) {
120        $result['queued-massmessages'] = MassMessage::getQueuedCount();
121    }
122
123    /**
124     * Override the Edit tab for delivery lists.
125     *
126     * @param \SkinTemplate $sktemplate
127     * @param array &$links
128     */
129    public function onSkinTemplateNavigation__Universal( $sktemplate, &$links ): void {
130        $title = $sktemplate->getTitle();
131        if ( $title->hasContentModel( 'MassMessageListContent' )
132            && array_key_exists( 'edit', $links['views'] )
133        ) {
134            // Get the revision being viewed, if applicable
135            $request = $sktemplate->getRequest();
136            $direction = $request->getVal( 'direction' );
137            $diff = $request->getVal( 'diff' );
138            // getInt is guaranteed to return an integer, 0 if invalid
139            $oldid = $request->getInt( 'oldid' );
140            $revisionLookup = MediaWikiServices::getInstance()->getRevisionLookup();
141            $oldRev = $revisionLookup->getRevisionById( $oldid );
142            if ( $direction === 'next' && $oldRev ) {
143                $next = $revisionLookup->getNextRevision( $oldRev );
144                $revId = $next ? $next->getId() : $oldid;
145            } elseif ( $direction === 'prev' && $oldRev ) {
146                $prev = $revisionLookup->getPreviousRevision( $oldRev );
147                $revId = $prev ? $prev->getId() : $oldid;
148            } elseif ( $diff !== null ) {
149                if ( ctype_digit( $diff ) ) {
150                    $revId = (int)$diff;
151                } elseif ( $diff === 'next' && $oldRev ) {
152                    $next = $revisionLookup->getNextRevision( $oldRev );
153                    $revId = $next ? $next->getId() : $oldid;
154                } else {
155                    // diff is 'prev' or gibberish
156                    $revId = $oldid;
157                }
158            } else {
159                $revId = $oldid;
160            }
161
162            $query = ( $revId > 0 ) ? 'oldid=' . $revId : '';
163            $links['views']['edit']['href'] = SpecialPage::getTitleFor(
164                'EditMassMessageList', $title
165            )->getFullUrl( $query );
166        }
167    }
168
169    /**
170     * Add scripts and styles.
171     *
172     * @param OutputPage $out
173     * @param Skin $skin
174     */
175    public function onBeforePageDisplay( $out, $skin ): void {
176        $title = $out->getTitle();
177        if ( $title->exists() && $title->hasContentModel( 'MassMessageListContent' ) ) {
178            $permManager = MediaWikiServices::getInstance()->getPermissionManager();
179            if ( $out->getRevisionId() === $title->getLatestRevId()
180                && $permManager->quickUserCan( 'edit', $out->getUser(), $title )
181            ) {
182                $out->addBodyClasses( 'mw-massmessage-editable' );
183            }
184        }
185    }
186
187    /**
188     * Hook: RejectParserCacheValue
189     *
190     * Reject old cache entries that don't contain our "ext.MassMessage.content"
191     * module.
192     *
193     * @param ParserOutput $parserOutput
194     * @param WikiPage $wikiPage
195     * @param ParserOptions $parserOptions
196     * @return bool
197     */
198    public function onRejectParserCacheValue( $parserOutput, $wikiPage,
199        $parserOptions
200    ): bool {
201        if ( $wikiPage->getTitle()->hasContentModel( 'MassMessageListContent' ) &&
202            !in_array( 'ext.MassMessage.content', $parserOutput->getModules() )
203        ) {
204            return false;
205        }
206
207        return true;
208    }
209
210    /**
211     * Mark the messenger account's email as confirmed in job runs (T75061).
212     *
213     * @param User $user
214     * @param bool &$confirmed
215     * @return bool
216     */
217    public static function onEmailConfirmed( User $user, &$confirmed ) {
218        if ( $user->getId() === MassMessage::getMessengerUser()->getId() ) {
219            $confirmed = true;
220            // Skip further checks
221            return false;
222        }
223        return true;
224    }
225
226    /**
227     * Register the change tag for MassMessage delivery
228     *
229     * @param array &$tags
230     */
231    public function onListDefinedTags( &$tags ) {
232        $this->addRegisterTags( $tags );
233    }
234
235    /**
236     * Register the change tag for MassMessage delivery
237     *
238     * @param array &$tags
239     */
240    public function onChangeTagsListActive( &$tags ) {
241        $this->addRegisterTags( $tags );
242    }
243
244    /**
245     * @param array &$tags
246     */
247    private function addRegisterTags( &$tags ) {
248        $tags[] = 'massmessage-delivery';
249    }
250}