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