Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
65.57% covered (warning)
65.57%
40 / 61
12.50% covered (danger)
12.50%
1 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiReadingListsCreateEntry
65.57% covered (warning)
65.57%
40 / 61
12.50% covered (danger)
12.50%
1 / 8
17.88
0.00% covered (danger)
0.00%
0 / 1
 execute
92.00% covered (success)
92.00%
23 / 25
0.00% covered (danger)
0.00%
0 / 1
5.01
 getAllowedParams
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 getExtendedDescription
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getHelpUrls
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getExamplesMessages
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 isWriteMode
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 mustBePosted
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isInternal
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Extension\ReadingLists\Api;
4
5use ApiBase;
6use MediaWiki\Extension\ReadingLists\ReadingListRepository;
7use MediaWiki\Title\Title;
8use Wikimedia\ParamValidator\ParamValidator;
9
10/**
11 * API module for all write operations.
12 * Each operation (command) is implemented as a submodule.
13 */
14class ApiReadingListsCreateEntry extends ApiBase {
15
16    use ApiTrait;
17
18    /** @var string API module prefix */
19    private static $prefix = '';
20
21    /**
22     * Entry point for executing the module
23     * @inheritDoc
24     */
25    public function execute() {
26        $params = $this->extractRequestParams();
27        $listId = $this->getParameter( 'list' );
28        $this->requireOnlyOneParameter( $params, 'project', 'batch' );
29        $this->requireOnlyOneParameter( $params, 'title', 'batch' );
30
31        $repository = $this->getReadingListRepository( $this->getUser() );
32        if ( isset( $params['project'] ) ) {
33            // Lists can contain titles from other wikis, and we have no idea of the exact title
34            // validation rules used there; but in practice it's unlikely the rules would differ,
35            // and allowing things like <> or # in the title could result in vulnerabilities in
36            // clients that assume they are getting something sane. So let's validate anyway.
37            // We do not normalize, that would contain too much local logic (e.g. title case), and
38            // clients are expected to submit already normalized titles (that they got from the API)
39            // anyway.
40            if ( !Title::newFromText( $params['title'] ) ) {
41                $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
42            }
43
44            $entry = $repository->addListEntry( $listId, $params['project'], $params['title'] );
45            $entryData = $this->getListEntryFromRow( $entry );
46            $this->getResult()->addValue( null, $this->getModuleName(),
47                [ 'id' => $entry->rle_id, 'entry' => $entryData ] );
48        } else {
49            $entryIds = $entryData = [];
50            foreach ( $this->getBatchOps( $params['batch'] ) as $op ) {
51                $this->requireAtLeastOneBatchParameter( $op, 'project' );
52                $this->requireAtLeastOneBatchParameter( $op, 'title' );
53                if ( !Title::newFromText( $op['title'] ) ) {
54                    $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $op['title'] ) ] );
55                }
56                $entry = $repository->addListEntry( $listId, $op['project'], $op['title'] );
57                $entryIds[] = $entry->rle_id;
58                $entryData[] = $this->getListEntryFromRow( $entry );
59            }
60            $this->getResult()->addValue( null, $this->getModuleName(),
61                [ 'ids' => $entryIds, 'entries' => $entryData ] );
62            $this->getResult()->addIndexedTagName( [ $this->getModuleName(), 'ids' ], 'id' );
63            $this->getResult()->addIndexedTagName( [ $this->getModuleName(), 'entries' ], 'entry' );
64        }
65    }
66
67    /**
68     * @inheritDoc
69     */
70    protected function getAllowedParams() {
71        return [
72            'list' => [
73                ParamValidator::PARAM_TYPE => 'integer',
74                ParamValidator::PARAM_REQUIRED => true,
75            ],
76            'project' => [
77                ParamValidator::PARAM_TYPE => 'string',
78                self::PARAM_MAX_BYTES => ReadingListRepository::$fieldLength['rlp_project'],
79            ],
80            'title' => [
81                ParamValidator::PARAM_TYPE => 'string',
82                self::PARAM_MAX_BYTES => ReadingListRepository::$fieldLength['rle_title'],
83            ],
84            'batch' => [
85                ParamValidator::PARAM_TYPE => 'string',
86            ]
87        ];
88    }
89
90    /**
91     * @inheritDoc
92     */
93    protected function getExtendedDescription() {
94        $limit = $this->getConfig()->get( 'ReadingListsMaxEntriesPerList' );
95        return $this->msg( 'apihelp-readinglists+createentry-extended-description', $limit );
96    }
97
98    /**
99     * @inheritDoc
100     */
101    public function getHelpUrls() {
102        return [
103            'https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:ReadingLists#API',
104        ];
105    }
106
107    /**
108     * @inheritDoc
109     */
110    protected function getExamplesMessages() {
111        $batch = wfArrayToCgi( [ 'batch' => json_encode( [
112            [ 'project' => 'https://en.wikipedia.org', 'title' => 'Dog' ],
113            [ 'project' => 'https://en.wikipedia.org', 'title' => 'Cat' ],
114        ] ) ] );
115        return [
116            'action=readinglists&command=createentry&list=33&'
117                . 'project=https%3A%2F%2Fen.wikipedia.org&title=Dog&token=123ABC'
118                => 'apihelp-readinglists+createentry-example-1',
119            "action=readinglists&command=createentry&list=33&$batch&token=123ABC"
120                => 'apihelp-readinglists+createentry-example-2',
121        ];
122    }
123
124    // The parent module already enforces these but they make documentation nicer.
125
126    /**
127     * @inheritDoc
128     */
129    public function isWriteMode() {
130        return true;
131    }
132
133    /**
134     * @inheritDoc
135     */
136    public function mustBePosted() {
137        return true;
138    }
139
140    /**
141     * @inheritDoc
142     */
143    public function isInternal() {
144        // ReadingLists API is still experimental
145        return true;
146    }
147
148}