ApiDelete.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <?php
  2. /*
  3. * Created on Jun 30, 2007
  4. * API for MediaWiki 1.8+
  5. *
  6. * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. * http://www.gnu.org/copyleft/gpl.html
  22. */
  23. if (!defined('MEDIAWIKI')) {
  24. // Eclipse helper - will be ignored in production
  25. require_once ("ApiBase.php");
  26. }
  27. /**
  28. * API module that facilitates deleting pages. The API eqivalent of action=delete.
  29. * Requires API write mode to be enabled.
  30. *
  31. * @ingroup API
  32. */
  33. class ApiDelete extends ApiBase {
  34. public function __construct($main, $action) {
  35. parent :: __construct($main, $action);
  36. }
  37. /**
  38. * Extracts the title, token, and reason from the request parameters and invokes
  39. * the local delete() function with these as arguments. It does not make use of
  40. * the delete function specified by Article.php. If the deletion succeeds, the
  41. * details of the article deleted and the reason for deletion are added to the
  42. * result object.
  43. */
  44. public function execute() {
  45. global $wgUser;
  46. $params = $this->extractRequestParams();
  47. $this->requireOnlyOneParameter($params, 'title', 'pageid');
  48. if(!isset($params['token']))
  49. $this->dieUsageMsg(array('missingparam', 'token'));
  50. if(isset($params['title']))
  51. {
  52. $titleObj = Title::newFromText($params['title']);
  53. if(!$titleObj)
  54. $this->dieUsageMsg(array('invalidtitle', $params['title']));
  55. }
  56. else if(isset($params['pageid']))
  57. {
  58. $titleObj = Title::newFromID($params['pageid']);
  59. if(!$titleObj)
  60. $this->dieUsageMsg(array('nosuchpageid', $params['pageid']));
  61. }
  62. if(!$titleObj->exists())
  63. $this->dieUsageMsg(array('notanarticle'));
  64. $reason = (isset($params['reason']) ? $params['reason'] : NULL);
  65. if ($titleObj->getNamespace() == NS_FILE) {
  66. $retval = self::deleteFile($params['token'], $titleObj, $params['oldimage'], $reason, false);
  67. if(count($retval))
  68. // We don't care about multiple errors, just report one of them
  69. $this->dieUsageMsg(reset($retval));
  70. } else {
  71. $articleObj = new Article($titleObj);
  72. if($articleObj->isBigDeletion() && !$wgUser->isAllowed('bigdelete')) {
  73. global $wgDeleteRevisionsLimit;
  74. $this->dieUsageMsg(array('delete-toobig', $wgDeleteRevisionsLimit));
  75. }
  76. $retval = self::delete($articleObj, $params['token'], $reason);
  77. if(count($retval))
  78. // We don't care about multiple errors, just report one of them
  79. $this->dieUsageMsg(reset($retval));
  80. if($params['watch'] || $wgUser->getOption('watchdeletion'))
  81. $articleObj->doWatch();
  82. else if($params['unwatch'])
  83. $articleObj->doUnwatch();
  84. }
  85. $r = array('title' => $titleObj->getPrefixedText(), 'reason' => $reason);
  86. $this->getResult()->addValue(null, $this->getModuleName(), $r);
  87. }
  88. private static function getPermissionsError(&$title, $token) {
  89. global $wgUser;
  90. // Check permissions
  91. $errors = $title->getUserPermissionsErrors('delete', $wgUser);
  92. if (count($errors) > 0) return $errors;
  93. // Check token
  94. if(!$wgUser->matchEditToken($token))
  95. return array(array('sessionfailure'));
  96. return array();
  97. }
  98. /**
  99. * We have our own delete() function, since Article.php's implementation is split in two phases
  100. *
  101. * @param Article $article - Article object to work on
  102. * @param string $token - Delete token (same as edit token)
  103. * @param string $reason - Reason for the deletion. Autogenerated if NULL
  104. * @return Title::getUserPermissionsErrors()-like array
  105. */
  106. public static function delete(&$article, $token, &$reason = NULL)
  107. {
  108. global $wgUser;
  109. $title = $article->getTitle();
  110. $errors = self::getPermissionsError($title, $token);
  111. if (count($errors)) return $errors;
  112. // Auto-generate a summary, if necessary
  113. if(is_null($reason))
  114. {
  115. # Need to pass a throwaway variable because generateReason expects
  116. # a reference
  117. $hasHistory = false;
  118. $reason = $article->generateReason($hasHistory);
  119. if($reason === false)
  120. return array(array('cannotdelete'));
  121. }
  122. $error = '';
  123. if (!wfRunHooks('ArticleDelete', array(&$article, &$wgUser, &$reason, $error)))
  124. $this->dieUsageMsg(array('hookaborted', $error));
  125. // Luckily, Article.php provides a reusable delete function that does the hard work for us
  126. if($article->doDeleteArticle($reason)) {
  127. wfRunHooks('ArticleDeleteComplete', array(&$article, &$wgUser, $reason, $article->getId()));
  128. return array();
  129. }
  130. return array(array('cannotdelete', $article->mTitle->getPrefixedText()));
  131. }
  132. public static function deleteFile($token, &$title, $oldimage, &$reason = NULL, $suppress = false)
  133. {
  134. $errors = self::getPermissionsError($title, $token);
  135. if (count($errors)) return $errors;
  136. if( $oldimage && !FileDeleteForm::isValidOldSpec($oldimage) )
  137. return array(array('invalidoldimage'));
  138. $file = wfFindFile($title, false, FileRepo::FIND_IGNORE_REDIRECT);
  139. $oldfile = false;
  140. if( $oldimage )
  141. $oldfile = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $title, $oldimage );
  142. if( !FileDeleteForm::haveDeletableFile($file, $oldfile, $oldimage) )
  143. return array(array('nofile'));
  144. if (is_null($reason)) # Log and RC don't like null reasons
  145. $reason = '';
  146. $status = FileDeleteForm::doDelete( $title, $file, $oldimage, $reason, $suppress );
  147. if( !$status->isGood() )
  148. return array(array('cannotdelete', $title->getPrefixedText()));
  149. return array();
  150. }
  151. public function mustBePosted() { return true; }
  152. public function isWriteMode() {
  153. return true;
  154. }
  155. public function getAllowedParams() {
  156. return array (
  157. 'title' => null,
  158. 'pageid' => array(
  159. ApiBase::PARAM_TYPE => 'integer'
  160. ),
  161. 'token' => null,
  162. 'reason' => null,
  163. 'watch' => false,
  164. 'unwatch' => false,
  165. 'oldimage' => null
  166. );
  167. }
  168. public function getParamDescription() {
  169. return array (
  170. 'title' => 'Title of the page you want to delete. Cannot be used together with pageid',
  171. 'pageid' => 'Page ID of the page you want to delete. Cannot be used together with title',
  172. 'token' => 'A delete token previously retrieved through prop=info',
  173. 'reason' => 'Reason for the deletion. If not set, an automatically generated reason will be used.',
  174. 'watch' => 'Add the page to your watchlist',
  175. 'unwatch' => 'Remove the page from your watchlist',
  176. 'oldimage' => 'The name of the old image to delete as provided by iiprop=archivename'
  177. );
  178. }
  179. public function getDescription() {
  180. return array(
  181. 'Delete a page.'
  182. );
  183. }
  184. protected function getExamples() {
  185. return array (
  186. 'api.php?action=delete&title=Main%20Page&token=123ABC',
  187. 'api.php?action=delete&title=Main%20Page&token=123ABC&reason=Preparing%20for%20move'
  188. );
  189. }
  190. public function getVersion() {
  191. return __CLASS__ . ': $Id: ApiDelete.php 48122 2009-03-07 12:58:41Z catrope $';
  192. }
  193. }