5 * Created on Jun 30, 2007
7 * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@gmail.com
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * http://www.gnu.org/copyleft/gpl.html
27 if ( !defined( 'MEDIAWIKI' ) ) {
28 // Eclipse helper - will be ignored in production
29 require_once( "ApiBase.php" );
33 * API module that facilitates deleting pages. The API equivalent of action=delete.
34 * Requires API write mode to be enabled.
38 class ApiDelete
extends ApiBase
{
40 public function __construct( $main, $action ) {
41 parent
::__construct( $main, $action );
45 * Extracts the title, token, and reason from the request parameters and invokes
46 * the local delete() function with these as arguments. It does not make use of
47 * the delete function specified by Article.php. If the deletion succeeds, the
48 * details of the article deleted and the reason for deletion are added to the
51 public function execute() {
52 $params = $this->extractRequestParams();
54 $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
56 if ( isset( $params['title'] ) ) {
57 $titleObj = Title
::newFromText( $params['title'] );
59 $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
61 } elseif ( isset( $params['pageid'] ) ) {
62 $titleObj = Title
::newFromID( $params['pageid'] );
64 $this->dieUsageMsg( array( 'nosuchpageid', $params['pageid'] ) );
67 if ( !$titleObj->exists() ) {
68 $this->dieUsageMsg( array( 'notanarticle' ) );
71 $reason = ( isset( $params['reason'] ) ?
$params['reason'] : null );
72 if ( $titleObj->getNamespace() == NS_FILE
) {
73 $retval = self
::deleteFile( $params['token'], $titleObj, $params['oldimage'], $reason, false );
74 if ( count( $retval ) ) {
75 $this->dieUsageMsg( reset( $retval ) ); // We don't care about multiple errors, just report one of them
78 $articleObj = new Article( $titleObj );
79 $retval = self
::delete( $articleObj, $params['token'], $reason );
81 if ( count( $retval ) ) {
82 $this->dieUsageMsg( reset( $retval ) ); // We don't care about multiple errors, just report one of them
85 // Deprecated parameters
86 if ( $params['watch'] ) {
88 } elseif ( $params['unwatch'] ) {
91 $watch = $params['watchlist'];
93 $this->setWatch( $watch, $titleObj, 'watchdeletion' );
96 $r = array( 'title' => $titleObj->getPrefixedText(), 'reason' => $reason );
97 $this->getResult()->addValue( null, $this->getModuleName(), $r );
102 * @param &$title Title
103 * @param $token String
105 private static function getPermissionsError( &$title, $token ) {
109 $errors = $title->getUserPermissionsErrors( 'delete', $wgUser );
110 if ( count( $errors ) > 0 ) {
118 * We have our own delete() function, since Article.php's implementation is split in two phases
120 * @param $article Article object to work on
121 * @param $token String: delete token (same as edit token)
122 * @param $reason String: reason for the deletion. Autogenerated if NULL
123 * @return Title::getUserPermissionsErrors()-like array
125 public static function delete( &$article, $token, &$reason = null ) {
127 if ( $article->isBigDeletion() && !$wgUser->isAllowed( 'bigdelete' ) ) {
128 global $wgDeleteRevisionsLimit;
129 return array( array( 'delete-toobig', $wgDeleteRevisionsLimit ) );
131 $title = $article->getTitle();
132 $errors = self
::getPermissionsError( $title, $token );
133 if ( count( $errors ) ) {
137 // Auto-generate a summary, if necessary
138 if ( is_null( $reason ) ) {
139 // Need to pass a throwaway variable because generateReason expects
142 $reason = $article->generateReason( $hasHistory );
143 if ( $reason === false ) {
144 return array( array( 'cannotdelete' ) );
149 if ( !wfRunHooks( 'ArticleDelete', array( &$article, &$wgUser, &$reason, &$error ) ) ) {
150 return array( array( 'hookaborted', $error ) );
153 // Luckily, Article.php provides a reusable delete function that does the hard work for us
154 if ( $article->doDeleteArticle( $reason ) ) {
155 wfRunHooks( 'ArticleDeleteComplete', array( &$article, &$wgUser, $reason, $article->getId() ) );
158 return array( array( 'cannotdelete', $article->mTitle
->getPrefixedText() ) );
167 * @param $suppress bool
168 * @return \type|array|Title
170 public static function deleteFile( $token, &$title, $oldimage, &$reason = null, $suppress = false ) {
171 $errors = self
::getPermissionsError( $title, $token );
172 if ( count( $errors ) ) {
176 if ( $oldimage && !FileDeleteForm
::isValidOldSpec( $oldimage ) ) {
177 return array( array( 'invalidoldimage' ) );
180 $file = wfFindFile( $title, array( 'ignoreRedirect' => true ) );
184 $oldfile = RepoGroup
::singleton()->getLocalRepo()->newFromArchiveName( $title, $oldimage );
187 if ( !FileDeleteForm
::haveDeletableFile( $file, $oldfile, $oldimage ) ) {
188 return self
::delete( new Article( $title ), $token, $reason );
190 if ( is_null( $reason ) ) { // Log and RC don't like null reasons
193 $status = FileDeleteForm
::doDelete( $title, $file, $oldimage, $reason, $suppress );
195 if ( !$status->isGood() ) {
196 return array( array( 'cannotdelete', $title->getPrefixedText() ) );
202 public function mustBePosted() {
206 public function isWriteMode() {
210 public function getAllowedParams() {
214 ApiBase
::PARAM_TYPE
=> 'integer'
219 ApiBase
::PARAM_DFLT
=> false,
220 ApiBase
::PARAM_DEPRECATED
=> true,
222 'watchlist' => array(
223 ApiBase
::PARAM_DFLT
=> 'preferences',
224 ApiBase
::PARAM_TYPE
=> array(
232 ApiBase
::PARAM_DFLT
=> false,
233 ApiBase
::PARAM_DEPRECATED
=> true,
239 public function getParamDescription() {
240 $p = $this->getModulePrefix();
242 'title' => "Title of the page you want to delete. Cannot be used together with {$p}pageid",
243 'pageid' => "Page ID of the page you want to delete. Cannot be used together with {$p}title",
244 'token' => 'A delete token previously retrieved through prop=info',
245 'reason' => 'Reason for the deletion. If not set, an automatically generated reason will be used',
246 'watch' => 'Add the page to your watchlist',
247 'watchlist' => 'Unconditionally add or remove the page from your watchlist, use preferences or do not change watch',
248 'unwatch' => 'Remove the page from your watchlist',
249 'oldimage' => 'The name of the old image to delete as provided by iiprop=archivename'
253 public function getDescription() {
254 return 'Delete a page';
257 public function getPossibleErrors() {
258 return array_merge( parent
::getPossibleErrors(), array(
259 array( 'code' => 'missingparam', 'info' => 'One of the parameters title, pageid is required' ),
260 array( 'code' => 'invalidparammix', 'info' => 'The parameters title, pageid can not be used together' ),
261 array( 'invalidtitle', 'title' ),
262 array( 'nosuchpageid', 'pageid' ),
263 array( 'notanarticle' ),
264 array( 'hookaborted', 'error' ),
268 public function needsToken() {
272 public function getTokenSalt() {
276 protected function getExamples() {
278 'api.php?action=delete&title=Main%20Page&token=123ABC',
279 'api.php?action=delete&title=Main%20Page&token=123ABC&reason=Preparing%20for%20move'
283 public function getVersion() {
284 return __CLASS__
. ': $Id$';