Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
80.51% |
95 / 118 |
|
50.00% |
4 / 8 |
CRAP | |
0.00% |
0 / 1 |
ApiRevisionDelete | |
80.51% |
95 / 118 |
|
50.00% |
4 / 8 |
35.23 | |
0.00% |
0 / 1 |
execute | |
84.38% |
54 / 64 |
|
0.00% |
0 / 1 |
20.38 | |||
extractStatusInfo | |
80.00% |
8 / 10 |
|
0.00% |
0 / 1 |
4.13 | |||
mustBePosted | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isWriteMode | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getAllowedParams | |
100.00% |
30 / 30 |
|
100.00% |
1 / 1 |
1 | |||
needsToken | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getExamplesMessages | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
getHelpUrls | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * Copyright © 2013 Wikimedia Foundation and contributors |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | * @since 1.23 |
22 | */ |
23 | |
24 | use MediaWiki\Revision\RevisionRecord; |
25 | use MediaWiki\Status\Status; |
26 | use MediaWiki\Title\Title; |
27 | use Wikimedia\ParamValidator\ParamValidator; |
28 | |
29 | /** |
30 | * API interface to RevDel. The API equivalent of Special:RevisionDelete. |
31 | * Requires API write mode to be enabled. |
32 | * |
33 | * @ingroup API |
34 | */ |
35 | class ApiRevisionDelete extends ApiBase { |
36 | |
37 | public function execute() { |
38 | $this->useTransactionalTimeLimit(); |
39 | |
40 | $params = $this->extractRequestParams(); |
41 | $user = $this->getUser(); |
42 | $this->checkUserRightsAny( RevisionDeleter::getRestriction( $params['type'] ) ); |
43 | |
44 | if ( !$params['ids'] ) { |
45 | $this->dieWithError( [ 'apierror-paramempty', 'ids' ], 'paramempty_ids' ); |
46 | } |
47 | |
48 | // Check if user can add tags |
49 | if ( $params['tags'] ) { |
50 | $ableToTag = ChangeTags::canAddTagsAccompanyingChange( $params['tags'], $this->getAuthority() ); |
51 | if ( !$ableToTag->isOK() ) { |
52 | $this->dieStatus( $ableToTag ); |
53 | } |
54 | } |
55 | |
56 | $hide = $params['hide'] ?: []; |
57 | $show = $params['show'] ?: []; |
58 | if ( array_intersect( $hide, $show ) ) { |
59 | $this->dieWithError( 'apierror-revdel-mutuallyexclusive', 'badparams' ); |
60 | } elseif ( !$hide && !$show ) { |
61 | $this->dieWithError( 'apierror-revdel-paramneeded', 'badparams' ); |
62 | } |
63 | $bits = [ |
64 | 'content' => RevisionDeleter::getRevdelConstant( $params['type'] ), |
65 | 'comment' => RevisionRecord::DELETED_COMMENT, |
66 | 'user' => RevisionRecord::DELETED_USER, |
67 | ]; |
68 | $bitfield = []; |
69 | foreach ( $bits as $key => $bit ) { |
70 | if ( in_array( $key, $hide ) ) { |
71 | $bitfield[$bit] = 1; |
72 | } elseif ( in_array( $key, $show ) ) { |
73 | $bitfield[$bit] = 0; |
74 | } else { |
75 | $bitfield[$bit] = -1; |
76 | } |
77 | } |
78 | |
79 | if ( $params['suppress'] === 'yes' ) { |
80 | $this->checkUserRightsAny( 'suppressrevision' ); |
81 | $bitfield[RevisionRecord::DELETED_RESTRICTED] = 1; |
82 | } elseif ( $params['suppress'] === 'no' ) { |
83 | $bitfield[RevisionRecord::DELETED_RESTRICTED] = 0; |
84 | } else { |
85 | $bitfield[RevisionRecord::DELETED_RESTRICTED] = -1; |
86 | } |
87 | |
88 | $targetObj = null; |
89 | if ( $params['target'] ) { |
90 | $targetObj = Title::newFromText( $params['target'] ); |
91 | } |
92 | $targetObj = RevisionDeleter::suggestTarget( $params['type'], $targetObj, $params['ids'] ); |
93 | if ( $targetObj === null ) { |
94 | $this->dieWithError( [ 'apierror-revdel-needtarget' ], 'needtarget' ); |
95 | } |
96 | |
97 | // TODO: replace use of PermissionManager |
98 | if ( $this->getPermissionManager()->isBlockedFrom( $user, $targetObj ) ) { |
99 | // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Block is checked and not null |
100 | $this->dieBlocked( $user->getBlock() ); |
101 | } |
102 | |
103 | $list = RevisionDeleter::createList( |
104 | $params['type'], $this->getContext(), $targetObj, $params['ids'] |
105 | ); |
106 | $status = $list->setVisibility( [ |
107 | 'value' => $bitfield, |
108 | 'comment' => $params['reason'] ?? '', |
109 | 'perItemStatus' => true, |
110 | 'tags' => $params['tags'] |
111 | ] ); |
112 | |
113 | $result = $this->getResult(); |
114 | $data = $this->extractStatusInfo( $status ); |
115 | $data['target'] = $targetObj->getFullText(); |
116 | $data['items'] = []; |
117 | |
118 | foreach ( $status->getValue()['itemStatuses'] as $id => $s ) { |
119 | $data['items'][$id] = $this->extractStatusInfo( $s ); |
120 | $data['items'][$id]['id'] = $id; |
121 | } |
122 | |
123 | $list->reloadFromPrimary(); |
124 | for ( $item = $list->reset(); $list->current(); $item = $list->next() ) { |
125 | $data['items'][$item->getId()] += $item->getApiData( $this->getResult() ); |
126 | } |
127 | |
128 | $data['items'] = array_values( $data['items'] ); |
129 | ApiResult::setIndexedTagName( $data['items'], 'i' ); |
130 | $result->addValue( null, $this->getModuleName(), $data ); |
131 | } |
132 | |
133 | private function extractStatusInfo( Status $status ) { |
134 | $ret = [ |
135 | 'status' => $status->isOK() ? 'Success' : 'Fail', |
136 | ]; |
137 | |
138 | $errors = $this->getErrorFormatter()->arrayFromStatus( $status, 'error' ); |
139 | if ( $errors ) { |
140 | $ret['errors'] = $errors; |
141 | } |
142 | $warnings = $this->getErrorFormatter()->arrayFromStatus( $status, 'warning' ); |
143 | if ( $warnings ) { |
144 | $ret['warnings'] = $warnings; |
145 | } |
146 | |
147 | return $ret; |
148 | } |
149 | |
150 | public function mustBePosted() { |
151 | return true; |
152 | } |
153 | |
154 | public function isWriteMode() { |
155 | return true; |
156 | } |
157 | |
158 | public function getAllowedParams() { |
159 | return [ |
160 | 'type' => [ |
161 | ParamValidator::PARAM_TYPE => RevisionDeleter::getTypes(), |
162 | ParamValidator::PARAM_REQUIRED => true |
163 | ], |
164 | 'target' => null, |
165 | 'ids' => [ |
166 | ParamValidator::PARAM_ISMULTI => true, |
167 | ParamValidator::PARAM_REQUIRED => true |
168 | ], |
169 | 'hide' => [ |
170 | ParamValidator::PARAM_TYPE => [ 'content', 'comment', 'user' ], |
171 | ParamValidator::PARAM_ISMULTI => true, |
172 | ], |
173 | 'show' => [ |
174 | ParamValidator::PARAM_TYPE => [ 'content', 'comment', 'user' ], |
175 | ParamValidator::PARAM_ISMULTI => true, |
176 | ], |
177 | 'suppress' => [ |
178 | ParamValidator::PARAM_TYPE => [ 'yes', 'no', 'nochange' ], |
179 | ParamValidator::PARAM_DEFAULT => 'nochange', |
180 | ], |
181 | 'reason' => [ |
182 | ParamValidator::PARAM_TYPE => 'string' |
183 | ], |
184 | 'tags' => [ |
185 | ParamValidator::PARAM_TYPE => 'tags', |
186 | ParamValidator::PARAM_ISMULTI => true, |
187 | ], |
188 | ]; |
189 | } |
190 | |
191 | public function needsToken() { |
192 | return 'csrf'; |
193 | } |
194 | |
195 | protected function getExamplesMessages() { |
196 | $title = Title::newMainPage()->getPrefixedText(); |
197 | $mp = rawurlencode( $title ); |
198 | |
199 | return [ |
200 | "action=revisiondelete&target={$mp}&type=revision&ids=12345&" . |
201 | 'hide=content&token=123ABC' |
202 | => 'apihelp-revisiondelete-example-revision', |
203 | 'action=revisiondelete&type=logging&ids=67890&hide=content|comment|user&' . |
204 | 'reason=BLP%20violation&token=123ABC' |
205 | => 'apihelp-revisiondelete-example-log', |
206 | ]; |
207 | } |
208 | |
209 | public function getHelpUrls() { |
210 | return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Revisiondelete'; |
211 | } |
212 | } |