Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.77% covered (success)
96.77%
30 / 31
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiQueryNextSuggestedTaskType
96.77% covered (success)
96.77%
30 / 31
75.00% covered (warning)
75.00%
3 / 4
7
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
3
 mustBePosted
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isInternal
n/a
0 / 0
n/a
0 / 0
1
 getAllowedParams
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace GrowthExperiments\Api;
4
5use GrowthExperiments\LevelingUp\LevelingUpManager;
6use GrowthExperiments\NewcomerTasks\ConfigurationLoader\ConfigurationLoader;
7use GrowthExperiments\UserImpact\UserImpactLookup;
8use MediaWiki\Api\ApiQuery;
9use MediaWiki\Api\ApiQueryBase;
10use Wikimedia\ParamValidator\ParamValidator;
11
12/**
13 * API module for interacting with the LevelingUpManager, for suggesting new task types to eligible
14 * users. {@see LevelingUpManager}
15 */
16class ApiQueryNextSuggestedTaskType extends ApiQueryBase {
17
18    private LevelingUpManager $levelingUpManager;
19    private ConfigurationLoader $configurationLoader;
20    private UserImpactLookup $userImpactLookup;
21
22    public function __construct(
23        ApiQuery $queryModule,
24        string $moduleName,
25        ConfigurationLoader $configurationLoader,
26        LevelingUpManager $levelingUpManager,
27        UserImpactLookup $userImpactLookup
28    ) {
29        parent::__construct( $queryModule, $moduleName, 'gnstt' );
30        $this->levelingUpManager = $levelingUpManager;
31        $this->configurationLoader = $configurationLoader;
32        $this->userImpactLookup = $userImpactLookup;
33    }
34
35    /**
36     * @inheritDoc
37     */
38    public function execute() {
39        if ( !$this->getUser()->isNamed() ) {
40            $this->dieWithError( 'apierror-mustbeloggedin-generic' );
41        }
42        $params = $this->extractRequestParams();
43        $this->getResult()->addValue(
44            'query',
45            $this->getModuleName(),
46            $this->levelingUpManager->suggestNewTaskTypeForUser(
47                $this->getUser(),
48                $params['activetasktype'],
49                true
50            )
51        );
52        $userImpact = $this->userImpactLookup->getUserImpact( $this->getUser() );
53        // User impact should definitely exist, but it's typed to potentially return null, so check to be sure.
54        if ( $userImpact ) {
55            // For instrumentation, export the edit count by task type data to the client-side.
56            // We can also use this to implement the "only show every Nth edit" rule when the
57            // user makes multiple edits to an article without reloading the page.
58            // This should logically be in a separate API module, but doesn't seem worth the boilerplate
59            // until there is a use case separate from the "try next task type" workflow.
60            $this->getResult()->addValue(
61                'query',
62                'editcountbytasktype',
63                $userImpact->getEditCountByTaskType()
64            );
65        }
66    }
67
68    /** @inheritDoc */
69    public function mustBePosted() {
70        return true;
71    }
72
73    /**
74     * @inheritDoc
75     * @codeCoverageIgnore
76     */
77    public function isInternal() {
78        return true;
79    }
80
81    /**
82     * @inheritDoc
83     */
84    public function getAllowedParams() {
85        $taskTypes = $this->configurationLoader->getTaskTypes();
86        return [
87            'activetasktype' => [
88                ParamValidator::PARAM_TYPE => array_keys( $taskTypes ),
89                ParamValidator::PARAM_REQUIRED => true,
90            ]
91        ];
92    }
93}