Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.74% covered (success)
90.74%
49 / 54
57.14% covered (warning)
57.14%
4 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiHelpPanelPostQuestion
90.74% covered (success)
90.74%
49 / 54
57.14% covered (warning)
57.14%
4 / 7
11.10
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 execute
95.24% covered (success)
95.24%
20 / 21
0.00% covered (danger)
0.00%
0 / 1
4
 getQuestionPoster
72.73% covered (warning)
72.73%
8 / 11
0.00% covered (danger)
0.00%
0 / 1
2.08
 needsToken
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isInternal
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAllowedParams
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 isWriteMode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace GrowthExperiments\Api;
4
5use ApiBase;
6use ApiMain;
7use ApiUsageException;
8use GrowthExperiments\HelpPanel\QuestionPoster\QuestionPoster;
9use GrowthExperiments\HelpPanel\QuestionPoster\QuestionPosterFactory;
10use UserNotLoggedIn;
11use Wikimedia\ParamValidator\ParamValidator;
12use Wikimedia\ParamValidator\TypeDef\StringDef;
13
14class ApiHelpPanelPostQuestion extends ApiBase {
15
16    public const API_PARAM_BODY = 'body';
17    public const API_PARAM_SOURCE = 'source';
18    public const API_PARAM_RELEVANT_TITLE = 'relevanttitle';
19
20    /** API name => [ source, target ] using the respective QuestionPosterFactory constants */
21    private const QUESTION_POSTER_TYPES = [
22        'helpdesk' =>
23            [ QuestionPosterFactory::SOURCE_HELP_PANEL, QuestionPosterFactory::TARGET_HELPDESK ],
24        'mentor-homepage' =>
25            [ QuestionPosterFactory::SOURCE_MENTORSHIP_MODULE, QuestionPosterFactory::TARGET_MENTOR_TALK ],
26        'mentor-helppanel' =>
27            [ QuestionPosterFactory::SOURCE_HELP_PANEL, QuestionPosterFactory::TARGET_MENTOR_TALK ],
28        // old names (FIXME remove once not in use)
29        'helppanel' =>
30            [ QuestionPosterFactory::SOURCE_HELP_PANEL, QuestionPosterFactory::TARGET_HELPDESK ],
31        'homepage-mentorship' =>
32            [ QuestionPosterFactory::SOURCE_MENTORSHIP_MODULE, QuestionPosterFactory::TARGET_MENTOR_TALK ],
33    ];
34
35    /**
36     * @var QuestionPosterFactory
37     */
38    private $questionPosterFactory;
39
40    /**
41     * @param ApiMain $mainModule
42     * @param string $moduleName
43     * @param QuestionPosterFactory $questionPosterFactory
44     */
45    public function __construct(
46        ApiMain $mainModule,
47        $moduleName,
48        QuestionPosterFactory $questionPosterFactory
49    ) {
50        parent::__construct( $mainModule, $moduleName );
51        $this->questionPosterFactory = $questionPosterFactory;
52    }
53
54    /**
55     * Save help panel question post.
56     */
57    public function execute() {
58        $params = $this->extractRequestParams();
59        $questionPoster = $this->getQuestionPoster(
60            $params[self::API_PARAM_SOURCE],
61            $params[self::API_PARAM_BODY],
62            $params[self::API_PARAM_RELEVANT_TITLE] ?? ''
63        );
64
65        if ( $params[self::API_PARAM_RELEVANT_TITLE] ) {
66            $status = $questionPoster->validateRelevantTitle();
67            if ( !$status->isGood() ) {
68                $this->dieStatus( $status );
69            }
70        }
71
72        $status = $questionPoster->submit();
73        if ( !$status->isGood() ) {
74            $this->dieStatus( $status );
75        }
76
77        $result = [
78            'result' => 'success',
79            'revision' => $questionPoster->getRevisionId(),
80            'isfirstedit' => (int)$questionPoster->isFirstEdit(),
81            'viewquestionurl' => $questionPoster->getResultUrl(),
82            'source' => $params[self::API_PARAM_SOURCE]
83        ];
84
85        $this->getResult()->addValue( null, $this->getModuleName(), $result );
86    }
87
88    /**
89     * @param string $source
90     * @param string $body
91     * @param string|null $relevantTitle
92     * @return QuestionPoster
93     * @throws ApiUsageException
94     */
95    private function getQuestionPoster( $source, $body, $relevantTitle ): QuestionPoster {
96        $questionPosterType = self::QUESTION_POSTER_TYPES[$source];
97        try {
98            return $this->questionPosterFactory->getQuestionPoster(
99                $questionPosterType[0],
100                $questionPosterType[1],
101                $this->getContext(),
102                $body,
103                $relevantTitle ?? ''
104            );
105        } catch ( UserNotLoggedIn $e ) {
106            throw ApiUsageException::newWithMessage( $this,
107                'apierror-mustbeloggedin-helppanelquestionposter', 'notloggedin' );
108        }
109    }
110
111    /**
112     * @inheritDoc
113     */
114    public function needsToken() {
115        return 'csrf';
116    }
117
118    /** @inheritDoc */
119    public function isInternal() {
120        // For use by the question poster dialog only. All functionality available via core APIs.
121        return true;
122    }
123
124    /**
125     * @inheritDoc
126     */
127    public function getAllowedParams() {
128        return [
129            self::API_PARAM_BODY => [
130                ParamValidator::PARAM_REQUIRED => true,
131                ParamValidator::PARAM_TYPE => 'string',
132                StringDef::PARAM_MAX_CHARS => 2000,
133            ],
134            self::API_PARAM_SOURCE => [
135                ParamValidator::PARAM_REQUIRED => false,
136                ParamValidator::PARAM_TYPE => array_keys( self::QUESTION_POSTER_TYPES ),
137                ParamValidator::PARAM_DEFAULT => 'helpdesk',
138                ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
139            ],
140            self::API_PARAM_RELEVANT_TITLE => [
141                ParamValidator::PARAM_REQUIRED => false,
142                ParamValidator::PARAM_TYPE => 'string',
143            ],
144        ];
145    }
146
147    /**
148     * @inheritDoc
149     */
150    public function isWriteMode() {
151        return true;
152    }
153}