Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialImpact
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 6
420
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDescription
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isIncludable
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
210
 prefixSearchSubpages
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace GrowthExperiments\Specials;
4
5use GrowthExperiments\DashboardModule\IDashboardModule;
6use GrowthExperiments\Homepage\HomepageModuleRegistry;
7use GrowthExperiments\HomepageModules\NewImpact;
8use MediaWiki\Html\Html;
9use MediaWiki\SpecialPage\SpecialPage;
10use MediaWiki\User\UserFactory;
11use MediaWiki\User\UserNamePrefixSearch;
12use MediaWiki\User\UserNameUtils;
13
14class SpecialImpact extends SpecialPage {
15
16    private UserFactory $userFactory;
17    private UserNameUtils $userNameUtils;
18    private UserNamePrefixSearch $userNamePrefixSearch;
19    private HomepageModuleRegistry $homepageModuleRegistry;
20
21    /**
22     * @param UserFactory $userFactory
23     * @param UserNameUtils $userNameUtils
24     * @param UserNamePrefixSearch $userNamePrefixSearch
25     * @param HomepageModuleRegistry $homepageModuleRegistry
26     */
27    public function __construct(
28        UserFactory $userFactory,
29        UserNameUtils $userNameUtils,
30        UserNamePrefixSearch $userNamePrefixSearch,
31        HomepageModuleRegistry $homepageModuleRegistry
32    ) {
33        parent::__construct( 'Impact' );
34        $this->userFactory = $userFactory;
35        $this->userNameUtils = $userNameUtils;
36        $this->userNamePrefixSearch = $userNamePrefixSearch;
37        $this->homepageModuleRegistry = $homepageModuleRegistry;
38    }
39
40    /** @inheritDoc */
41    protected function getGroupName() {
42        return 'growth-tools';
43    }
44
45    /**
46     * @inheritDoc
47     */
48    public function getDescription() {
49        return $this->msg( 'growthexperiments-specialimpact-title' );
50    }
51
52    /**
53     * @inheritDoc
54     */
55    public function isIncludable(): bool {
56        return $this->getConfig()->get( 'GEUseNewImpactModule' ) === true;
57    }
58
59    /**
60     * Render the impact module in following conditions:
61     *
62     * - user is logged out, $par must be a valid username
63     * - user is logged-in, $par is not set
64     * - user is logged-in, $par is set to a valid username
65     *
66     * Error if:
67     *
68     * - user is logged-in, $par is set to an invalid username
69     * - user is logged-out and $par is not supplied
70     *
71     * @param string|null $par
72     * @return void
73     */
74    public function execute( $par ) {
75        parent::execute( $par );
76        $impactUser = $this->getUser();
77        // If an argument was supplied, attempt to load a user.
78        if ( $par ) {
79            $impactUser = $this->userFactory->newFromName( $par );
80        }
81        $out = $this->getContext()->getOutput();
82        // Error out in the following scenarios:
83        // If we don't have a user (logged-in or from argument) then error out.
84        // If the impact user is hidden and the requesting does not have the permission to see it.
85        // If the page is being included and the user is hidden since it will get cached and users without
86        // the hideuser permission could get the cached result.
87        if ( !$impactUser || !$impactUser->getId() ||
88            ( $impactUser->isHidden() &&
89                ( !$this->getAuthority()->isAllowed( 'hideuser' ) || $this->including() ) )
90        ) {
91            $out->addHTML( Html::element( 'p', [ 'class' => 'error' ], $this->msg(
92                'growthexperiments-specialimpact-invalid-username'
93            )->text() ) );
94            return;
95        }
96        // If the page is included and no user parameter ($par) is informed error out to prevent misunderstandings of
97        // {{Special:Impact}} usage.
98        if ( $this->including() && !$par ) {
99            $out->addHTML( Html::element( 'p', [ 'class' => 'error' ], $this->msg(
100                'growthexperiments-specialimpact-invalid-inclusion-without-username'
101            )->text() ) );
102            return;
103        }
104        $out->enableOOUI();
105        $impact = $this->homepageModuleRegistry->get( 'impact', $this->getContext() );
106        // If an argument was supplied and passed user validation, set the relevant user to the informed by.
107        if ( $par && $impact instanceof NewImpact ) {
108            $impact->setUserDataIsFor( $impactUser );
109        }
110        $configVarName = 'specialimpact';
111        if ( $this->including() ) {
112            $configVarName .= ':included';
113        }
114        $out->addJsConfigVars( $configVarName, [
115            // Load the impact data from the client when the page is included and the user has edits, so we don't need
116            // to reduce the expiry of the page in the parser cache.
117            'impact' => $this->including() && $impactUser->getEditCount() ?
118                null :
119                $impact->getJsData( IDashboardModule::RENDER_DESKTOP )
120        ] );
121        $out->addHTML( $impact->render( IDashboardModule::RENDER_DESKTOP ) );
122    }
123
124    /** @inheritDoc */
125    public function prefixSearchSubpages( $search, $limit, $offset ) {
126        $search = $this->userNameUtils->getCanonical( $search );
127        if ( !$search ) {
128            // No prefix suggestion for invalid user
129            return [];
130        }
131        // Autocomplete subpage as user list - public to allow caching
132        return $this->userNamePrefixSearch
133            ->search( UserNamePrefixSearch::AUDIENCE_PUBLIC, $search, $limit, $offset );
134    }
135}