Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
65.57% |
40 / 61 |
|
12.50% |
1 / 8 |
CRAP | |
0.00% |
0 / 1 |
ApiReadingListsCreateEntry | |
65.57% |
40 / 61 |
|
12.50% |
1 / 8 |
17.88 | |
0.00% |
0 / 1 |
execute | |
92.00% |
23 / 25 |
|
0.00% |
0 / 1 |
5.01 | |||
getAllowedParams | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
1 | |||
getExtendedDescription | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getHelpUrls | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
getExamplesMessages | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
2 | |||
isWriteMode | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
mustBePosted | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isInternal | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\ReadingLists\Api; |
4 | |
5 | use ApiBase; |
6 | use MediaWiki\Extension\ReadingLists\ReadingListRepository; |
7 | use MediaWiki\Title\Title; |
8 | use Wikimedia\ParamValidator\ParamValidator; |
9 | |
10 | /** |
11 | * API module for all write operations. |
12 | * Each operation (command) is implemented as a submodule. |
13 | */ |
14 | class 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 | } |