Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
25.53% covered (danger)
25.53%
24 / 94
22.22% covered (danger)
22.22%
2 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
HelpPanel
25.53% covered (danger)
25.53%
24 / 94
22.22% covered (danger)
22.22%
2 / 9
427.86
0.00% covered (danger)
0.00%
0 / 1
 getHelpPanelCtaButton
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
 getHelpPanelLinks
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
56
 shouldShowHelpPanelToUser
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 shouldShowHelpPanel
88.24% covered (warning)
88.24%
15 / 17
0.00% covered (danger)
0.00%
0 / 1
8.10
 shouldShowForReadingMode
15.38% covered (danger)
15.38%
2 / 13
0.00% covered (danger)
0.00%
0 / 1
36.69
 isHelpPanelEnabled
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getHelpDeskTitle
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
2.03
 getUserEmailConfigVars
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 isSuggestedEditRequest
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace GrowthExperiments;
4
5use GrowthExperiments\Config\GrowthConfigLoaderStaticTrait;
6use GrowthExperiments\HelpPanel\HelpPanelButton;
7use GrowthExperiments\HomepageModules\SuggestedEdits;
8use MediaWiki\Config\Config;
9use MediaWiki\Config\ConfigException;
10use MediaWiki\Html\Html;
11use MediaWiki\Language\RawMessage;
12use MediaWiki\MediaWikiServices;
13use MediaWiki\Output\OutputPage;
14use MediaWiki\Request\WebRequest;
15use MediaWiki\Title\Title;
16use MediaWiki\User\User;
17use MediaWiki\User\UserIdentity;
18use MessageLocalizer;
19use OOUI\Tag;
20
21class HelpPanel {
22    use GrowthConfigLoaderStaticTrait;
23
24    public const HELPDESK_QUESTION_TAG = 'help panel question';
25
26    /**
27     * @return Tag
28     * @throws ConfigException
29     */
30    public static function getHelpPanelCtaButton( Config $wikiConfig ) {
31        $helpdeskTitle = self::getHelpDeskTitle(
32            $wikiConfig
33        );
34        $btnWidgetArr = [
35            'label' => wfMessage( 'growthexperiments-help-panel-cta-button-text' )->text(),
36        ];
37        if ( $helpdeskTitle ) {
38            $btnWidgetArr['href'] = $helpdeskTitle->getLinkURL();
39        }
40        return ( new Tag( 'div' ) )
41            ->addClasses( [ 'mw-ge-help-panel-cta' ] )
42            ->appendContent( new HelpPanelButton( $btnWidgetArr ) );
43    }
44
45    /**
46     * @param MessageLocalizer $ml
47     * @param Config $wikiConfig
48     * @return array Links that should appear in the help panel. Exported to JS as wgGEHelpPanelLinks.
49     */
50    public static function getHelpPanelLinks(
51        MessageLocalizer $ml,
52        Config $wikiConfig
53    ) {
54        if ( !self::isHelpPanelEnabled() ) {
55            return [];
56        }
57
58        $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
59
60        $helpPanelLinks = Html::openElement( 'ul', [ 'class' => 'mw-ge-help-panel-links' ] );
61        foreach ( $wikiConfig->get( 'GEHelpPanelLinks' ) as $link ) {
62            $link = (array)$link;
63            if ( !isset( $link[ 'title' ] ) ) {
64                continue;
65            }
66            $title = Title::newFromText( $link['title'] );
67            if ( $title ) {
68                $helpPanelLinks .= Html::rawElement(
69                    'li',
70                    [],
71                    $linkRenderer->makePreloadedLink( $title, $link['text'], '',
72                        [ 'target' => '_blank', 'data-link-id' => $link['id'] ?? '' ] )
73                );
74            }
75        }
76        $helpPanelLinks .= Html::closeElement( 'ul' );
77
78        $helpDeskTitle = self::getHelpDeskTitle( $wikiConfig );
79        $helpDeskLink = $helpDeskTitle ? $linkRenderer->makePreloadedLink(
80            $helpDeskTitle,
81            $ml->msg( 'growthexperiments-help-panel-community-help-desk-text' )->text(),
82            '',
83            [ 'target' => '_blank', 'data-link-id' => 'help-desk' ]
84        ) : null;
85
86        $viewMoreTitle = Title::newFromText( $wikiConfig->get( 'GEHelpPanelViewMoreTitle' ) );
87        $viewMoreLink = $viewMoreTitle ? $linkRenderer->makePreloadedLink(
88            $viewMoreTitle,
89            $ml->msg( 'growthexperiments-help-panel-editing-help-links-widget-view-more-link' )
90                ->text(),
91            '',
92            [ 'target' => '_blank', 'data-link-id' => 'view-more' ]
93        ) : null;
94
95        return [
96            'helpPanelLinks' => $helpPanelLinks,
97            'helpDeskLink' => $helpDeskLink,
98            'viewMoreLink' => $viewMoreLink
99        ];
100    }
101
102    /**
103     * Whether to show the help panel to a particular user.
104     *
105     * @param UserIdentity $user
106     * @return bool
107     */
108    public static function shouldShowHelpPanelToUser( UserIdentity $user ) {
109        if ( !self::isHelpPanelEnabled() ) {
110            return false;
111        }
112
113        $userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
114        return (bool)$userOptionsLookup->getOption( $user, HelpPanelHooks::HELP_PANEL_PREFERENCES_TOGGLE );
115    }
116
117    /**
118     * Check if we should show help panel to user.
119     *
120     * @return bool
121     * @throws ConfigException
122     */
123    public static function shouldShowHelpPanel(
124        OutputPage $out, bool $checkAction = true,
125        ?Config $config = null, ?Config $wikiConfig = null
126    ): bool {
127        $config ??= self::getGrowthConfig();
128        $wikiConfig ??= self::getGrowthWikiConfig();
129
130        if ( !self::isHelpPanelEnabled( $config ) ) {
131            return false;
132        }
133
134        if ( !$out->getUser()->isNamed() ) {
135            return false;
136        }
137
138        if ( $checkAction ) {
139            $action = $out->getRequest()->getVal( 'action', 'view' );
140            if ( !in_array( $action, [ 'edit', 'submit' ] ) &&
141                !self::shouldShowForReadingMode( $out, $action, $wikiConfig ) ) {
142                return false;
143            }
144        }
145
146        if ( self::isSuggestedEditRequest( $out->getRequest() ) ) {
147            return true;
148        }
149
150        if ( in_array( $out->getTitle()->getNamespace(),
151            $wikiConfig->get( 'GEHelpPanelExcludedNamespaces' ) ) ) {
152            return false;
153        }
154
155        return self::shouldShowHelpPanelToUser( $out->getUser() );
156    }
157
158    /**
159     * If action=view, check if we are in allowed namespace.
160     *
161     * Note that views to talk titles will perform a look up for the subject title namespace,
162     * so specifying 4 (NS_PROJECT) as a namespace for which to enable help panel reading mode
163     * will also result in enabling 5 (NS_PROJECT_TALK) as an additional namespace.
164     *
165     * @throws ConfigException
166     */
167    public static function shouldShowForReadingMode(
168        OutputPage $out, string $action,
169        Config $wikiConfig
170    ): bool {
171        if ( $action !== 'view' ) {
172            return false;
173        }
174        $title = $out->getTitle();
175        if ( !$title ) {
176            return false;
177        }
178        if ( $title->isMainPage() ) {
179            // kowiki uses a Wikipedia namespace page as its Main_Page.
180            return false;
181        }
182        if ( $title->inNamespaces( NS_MAIN, NS_TALK ) &&
183            SuggestedEdits::isGuidanceEnabled( $out->getContext() ) &&
184            HomepageHooks::getClickId( $out->getContext() ) ) {
185            return true;
186        }
187        return in_array( $title->getSubjectPage()->getNamespace(),
188                   $wikiConfig->get( 'GEHelpPanelReadingModeNamespaces' ) );
189    }
190
191    /**
192     * @return bool
193     */
194    public static function isHelpPanelEnabled( ?Config $config = null ) {
195        $config ??= MediaWikiServices::getInstance()->getMainConfig();
196        return $config->get( 'GEHelpPanelEnabled' );
197    }
198
199    /**
200     * Get the help desk title and expand the templates and magic words it may contain
201     *
202     * @param Config $wikiConfig
203     * @return null|Title
204     * @throws ConfigException
205     */
206    public static function getHelpDeskTitle( Config $wikiConfig ) {
207        $helpdeskTitle = $wikiConfig->get( 'GEHelpPanelHelpDeskTitle' );
208        if ( $helpdeskTitle === null ) {
209            return null;
210        }
211
212        // RawMessage is used here to expand magic words like {{#time:o}} - see T213186, T224224
213        $msg = new RawMessage( $helpdeskTitle );
214        return Title::newFromText( $msg->inContentLanguage()->text() );
215    }
216
217    /**
218     * Get the config vars needed to properly display the user email status
219     * in the question poster dialog used in the Help Panel as well as the
220     * Help and Mentorship modules.
221     *
222     * @param User $user
223     * @return array
224     */
225    public static function getUserEmailConfigVars( User $user ) {
226        return [
227            'wgGEHelpPanelUserEmail' => $user->getEmail(),
228            'wgGEHelpPanelUserEmailConfirmed' => $user->isEmailConfirmed(),
229        ];
230    }
231
232    /** Check if the request is from Special:Homepage to a Suggested Edit article.
233     *
234     * @param WebRequest $request
235     * @return bool
236     */
237    private static function isSuggestedEditRequest( WebRequest $request ): bool {
238        return $request->getBool( 'gesuggestededit' );
239    }
240}