MediaWiki master
ApiDelete.php
Go to the documentation of this file.
1<?php
32
39class ApiDelete extends ApiBase {
40
42
43 private RepoGroup $repoGroup;
44 private DeletePageFactory $deletePageFactory;
45
54 public function __construct(
55 ApiMain $mainModule,
56 $moduleName,
57 RepoGroup $repoGroup,
58 WatchlistManager $watchlistManager,
59 UserOptionsLookup $userOptionsLookup,
60 DeletePageFactory $deletePageFactory
61 ) {
62 parent::__construct( $mainModule, $moduleName );
63 $this->repoGroup = $repoGroup;
64 $this->deletePageFactory = $deletePageFactory;
65
66 // Variables needed in ApiWatchlistTrait trait
67 $this->watchlistExpiryEnabled = $this->getConfig()->get( MainConfigNames::WatchlistExpiry );
68 $this->watchlistMaxDuration =
69 $this->getConfig()->get( MainConfigNames::WatchlistExpiryMaxDuration );
70 $this->watchlistManager = $watchlistManager;
71 $this->userOptionsLookup = $userOptionsLookup;
72 }
73
81 public function execute() {
83
85
86 $pageObj = $this->getTitleOrPageId( $params, 'fromdbmaster' );
87 $titleObj = $pageObj->getTitle();
88 $this->getErrorFormatter()->setContextTitle( $titleObj );
89 if ( !$pageObj->exists() &&
90 // @phan-suppress-next-line PhanUndeclaredMethod
91 !( $titleObj->getNamespace() === NS_FILE && self::canDeleteFile( $pageObj->getFile() ) )
92 ) {
93 $this->dieWithError( 'apierror-missingtitle' );
94 }
95
96 $reason = $params['reason'];
97 $user = $this->getUser();
98
99 $tags = $params['tags'] ?: [];
100
101 if ( $titleObj->getNamespace() === NS_FILE ) {
102 $status = $this->deleteFile(
103 $pageObj,
104 $params['oldimage'],
105 $reason,
106 false,
107 $tags,
108 $params['deletetalk']
109 );
110 // TODO What kind of non-fatal errors should we expect here?
111 $wasScheduled = $status->isOK() && $status->getValue() === false;
112 } else {
113 $status = $this->delete( $pageObj, $reason, $tags, $params['deletetalk'] );
114 $wasScheduled = $status->isGood() && $status->getValue() === false;
115 }
116
117 if ( !$status->isOK() ) {
118 $this->dieStatus( $status );
119 }
120
121 if ( $wasScheduled ) {
122 $this->addWarning( [ 'delete-scheduled', $titleObj->getPrefixedText() ] );
123 }
124
125 // Deprecated parameters
126 if ( $params['watch'] ) {
127 $watch = 'watch';
128 } elseif ( $params['unwatch'] ) {
129 $watch = 'unwatch';
130 } else {
131 $watch = $params['watchlist'];
132 }
133
134 $watchlistExpiry = $this->getExpiryFromParams( $params );
135 $this->setWatch( $watch, $titleObj, $user, 'watchdeletion', $watchlistExpiry );
136
137 $r = [
138 'title' => $titleObj->getPrefixedText(),
139 'reason' => $reason,
140 ];
141
142 // TODO: We could expose additional information (scheduled and log ID) about the status of the talk page
143 // deletion.
144 if ( $wasScheduled ) {
145 $r['scheduled'] = true;
146 } else {
147 // Scheduled deletions don't currently have a log entry available at this point
148 $r['logid'] = $status->value;
149 }
150 $this->getResult()->addValue( null, $this->getModuleName(), $r );
151 }
152
165 private function delete( WikiPage $page, &$reason, array $tags, bool $deleteTalk ): StatusValue {
166 $title = $page->getTitle();
167
168 // Auto-generate a summary, if necessary
169 if ( $reason === null ) {
170 $reason = $page->getAutoDeleteReason();
171 if ( $reason === false ) {
172 // Should be reachable only if the page has no revisions
173 return Status::newFatal( 'cannotdelete', $title->getPrefixedText() ); // @codeCoverageIgnore
174 }
175 }
176
177 $deletePage = $this->deletePageFactory->newDeletePage( $page, $this->getAuthority() );
178 if ( $deleteTalk ) {
179 $checkStatus = $deletePage->canProbablyDeleteAssociatedTalk();
180 if ( !$checkStatus->isGood() ) {
181 foreach ( $checkStatus->getErrors() as $error ) {
182 $this->addWarning( $error );
183 }
184 } else {
185 $deletePage->setDeleteAssociatedTalk( true );
186 }
187 }
188 $deletionStatus = $deletePage->setTags( $tags )->deleteIfAllowed( $reason );
189 if ( $deletionStatus->isGood() ) {
190 $deletionStatus->value = $deletePage->deletionsWereScheduled()[DeletePage::PAGE_BASE]
191 ? false
192 : $deletePage->getSuccessfulDeletionsIDs()[DeletePage::PAGE_BASE];
193 }
194 return $deletionStatus;
195 }
196
201 protected static function canDeleteFile( File $file ) {
202 return $file->exists() && $file->isLocal() && !$file->getRedirected();
203 }
204
214 private function deleteFile(
215 WikiPage $page,
216 $oldimage,
217 &$reason,
218 bool $suppress,
219 array $tags,
220 bool $deleteTalk
221 ) {
222 $title = $page->getTitle();
223
224 // @phan-suppress-next-line PhanUndeclaredMethod There's no right typehint for it
225 $file = $page->getFile();
226 if ( !self::canDeleteFile( $file ) ) {
227 return $this->delete( $page, $reason, $tags, $deleteTalk );
228 }
229
230 // Check that the user is allowed to carry out the deletion
231 $this->checkTitleUserPermissions( $page->getTitle(), 'delete' );
232 if ( $tags ) {
233 // If change tagging was requested, check that the user is allowed to tag,
234 // and the tags are valid
235 $tagStatus = ChangeTags::canAddTagsAccompanyingChange( $tags, $this->getAuthority() );
236 if ( !$tagStatus->isOK() ) {
237 $this->dieStatus( $tagStatus );
238 }
239 }
240
241 if ( $oldimage ) {
242 if ( !FileDeleteForm::isValidOldSpec( $oldimage ) ) {
243 return Status::newFatal( 'invalidoldimage' );
244 }
245 $oldfile = $this->repoGroup->getLocalRepo()->newFromArchiveName( $title, $oldimage );
246 if ( !$oldfile->exists() || !$oldfile->isLocal() || $oldfile->getRedirected() ) {
247 return Status::newFatal( 'nodeleteablefile' );
248 }
249 }
250
251 if ( $reason === null ) { // Log and RC don't like null reasons
252 $reason = '';
253 }
254
255 return FileDeleteForm::doDelete(
256 $title,
257 $file,
258 $oldimage,
259 $reason,
260 $suppress,
261 $this->getUser(),
262 $tags,
263 $deleteTalk
264 );
265 }
266
267 public function mustBePosted() {
268 return true;
269 }
270
271 public function isWriteMode() {
272 return true;
273 }
274
275 public function getAllowedParams() {
276 $params = [
277 'title' => null,
278 'pageid' => [
279 ParamValidator::PARAM_TYPE => 'integer'
280 ],
281 'reason' => null,
282 'tags' => [
283 ParamValidator::PARAM_TYPE => 'tags',
284 ParamValidator::PARAM_ISMULTI => true,
285 ],
286 'deletetalk' => false,
287 'watch' => [
288 ParamValidator::PARAM_DEFAULT => false,
289 ParamValidator::PARAM_DEPRECATED => true,
290 ],
291 ];
292
293 // Params appear in the docs in the order they are defined,
294 // which is why this is here and not at the bottom.
295 $params += $this->getWatchlistParams();
296
297 return $params + [
298 'unwatch' => [
299 ParamValidator::PARAM_DEFAULT => false,
300 ParamValidator::PARAM_DEPRECATED => true,
301 ],
302 'oldimage' => null,
303 ];
304 }
305
306 public function needsToken() {
307 return 'csrf';
308 }
309
310 protected function getExamplesMessages() {
311 $title = Title::newMainPage()->getPrefixedText();
312 $mp = rawurlencode( $title );
313
314 return [
315 "action=delete&title={$mp}&token=123ABC"
316 => 'apihelp-delete-example-simple',
317 "action=delete&title={$mp}&token=123ABC&reason=Preparing%20for%20move"
318 => 'apihelp-delete-example-reason',
319 ];
320 }
321
322 public function getHelpUrls() {
323 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Delete';
324 }
325}
getUser()
getAuthority()
getExpiryFromParams(array $params)
Get formatted expiry from the given parameters, or null if no expiry was provided.
setWatch(string $watch, Title $title, User $user, ?string $userOption=null, ?string $expiry=null)
Set a watch (or unwatch) based the based on a watchlist parameter.
getWatchlistParams(array $watchOptions=[])
Get additional allow params specific to watchlisting.
const NS_FILE
Definition Defines.php:70
array $params
The job parameters.
This abstract class implements many basic API functions, and is the base of all API classes.
Definition ApiBase.php:64
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1533
getErrorFormatter()
Definition ApiBase.php:682
getResult()
Get the result object.
Definition ApiBase.php:671
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:811
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition ApiBase.php:1451
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:532
getTitleOrPageId( $params, $load=false)
Attempts to load a WikiPage object from a title or pageid parameter, if possible.
Definition ApiBase.php:1098
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition ApiBase.php:1589
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition ApiBase.php:1381
API module that facilitates deleting pages.
Definition ApiDelete.php:39
__construct(ApiMain $mainModule, $moduleName, RepoGroup $repoGroup, WatchlistManager $watchlistManager, UserOptionsLookup $userOptionsLookup, DeletePageFactory $deletePageFactory)
Definition ApiDelete.php:54
execute()
Extracts the title and reason from the request parameters and invokes the local delete() function wit...
Definition ApiDelete.php:81
needsToken()
Returns the token type this module requires in order to execute.
getExamplesMessages()
Returns usage examples for this module.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
getHelpUrls()
Return links to more detailed help pages about the module.
static canDeleteFile(File $file)
isWriteMode()
Indicates whether this module requires write mode.
mustBePosted()
Indicates whether this module must be called with a POST request.
This is the main API class, used for both external and internal processing.
Definition ApiMain.php:65
static canAddTagsAccompanyingChange(array $tags, Authority $performer=null, $checkBlock=true)
Is it OK to allow the user to apply all the specified tags at the same time as they edit/make the cha...
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition File.php:73
isLocal()
Returns true if the file comes from the local file repository.
Definition File.php:2031
exists()
Returns true if file exists in the repository.
Definition File.php:1015
getRedirected()
Definition File.php:2419
A class containing constants representing the names of configuration variables.
Backend logic for performing a page delete action.
File deletion user interface.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54
Represents a title within MediaWiki.
Definition Title.php:78
Provides access to user options.
Prioritized list of file repositories.
Definition RepoGroup.php:30
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Base representation for an editable wiki page.
Definition WikiPage.php:79
getAutoDeleteReason(&$hasHistory=false)
Auto-generates a deletion reason.
getTitle()
Get the title object of the article.
Definition WikiPage.php:260
Service for formatting and validating API parameters.
trait ApiWatchlistTrait
An ApiWatchlistTrait adds class properties and convenience methods for APIs that allow you to watch a...
Service for page delete actions.