/** * Extracts the title, token, and reason from the request parameters and invokes * the local delete() function with these as arguments. It does not make use of * the delete function specified by Article.php. If the deletion succeeds, the * details of the article deleted and the reason for deletion are added to the * result object. */ public function execute() { global $wgUser; $params = $this->extractRequestParams(); $this->requireOnlyOneParameter($params, 'title', 'pageid'); if (!isset($params['token'])) { $this->dieUsageMsg(array('missingparam', 'token')); } if (isset($params['title'])) { $titleObj = Title::newFromText($params['title']); if (!$titleObj) { $this->dieUsageMsg(array('invalidtitle', $params['title'])); } } else { if (isset($params['pageid'])) { $titleObj = Title::newFromID($params['pageid']); if (!$titleObj) { $this->dieUsageMsg(array('nosuchpageid', $params['pageid'])); } } } if (!$titleObj->exists()) { $this->dieUsageMsg(array('notanarticle')); } $reason = isset($params['reason']) ? $params['reason'] : NULL; if ($titleObj->getNamespace() == NS_FILE) { $retval = self::deleteFile($params['token'], $titleObj, $params['oldimage'], $reason, false); if (count($retval)) { // We don't care about multiple errors, just report one of them $this->dieUsageMsg(reset($retval)); } } else { $articleObj = new Article($titleObj); if ($articleObj->isBigDeletion() && !$wgUser->isAllowed('bigdelete')) { global $wgDeleteRevisionsLimit; $this->dieUsageMsg(array('delete-toobig', $wgDeleteRevisionsLimit)); } $retval = self::delete($articleObj, $params['token'], $reason); if (count($retval)) { // We don't care about multiple errors, just report one of them $this->dieUsageMsg(reset($retval)); } if ($params['watch'] || $wgUser->getOption('watchdeletion')) { $articleObj->doWatch(); } else { if ($params['unwatch']) { $articleObj->doUnwatch(); } } } $r = array('title' => $titleObj->getPrefixedText(), 'reason' => $reason); $this->getResult()->addValue(null, $this->getModuleName(), $r); }
function doSubmit() { global $wgOut, $wgUser, $wgMaximumMovedPages, $wgLang; global $wgFixDoubleRedirects; if ($wgUser->pingLimiter('move')) { $wgOut->rateLimited(); return; } $ot = $this->oldTitle; $nt = $this->newTitle; # Delete to make way if requested if ($wgUser->isAllowed('delete') && $this->deleteAndMove) { $article = new Article($nt); # Disallow deletions of big articles $bigHistory = $article->isBigDeletion(); if ($bigHistory && !$nt->userCan('bigdelete')) { global $wgDeleteRevisionsLimit; $this->showForm(array('delete-toobig', $wgLang->formatNum($wgDeleteRevisionsLimit))); return; } // Delete an associated image if there is $file = wfLocalFile($nt); if ($file->exists()) { $file->delete(wfMsgForContent('delete_and_move_reason'), false); } // This may output an error message and exit $article->doDelete(wfMsgForContent('delete_and_move_reason')); } # don't allow moving to pages with # in if (!$nt || $nt->getFragment() != '') { $this->showForm('badtitletext'); return; } # Show a warning if the target file exists on a shared repo if ($nt->getNamespace() == NS_FILE && !($this->moveOverShared && $wgUser->isAllowed('reupload-shared')) && !RepoGroup::singleton()->getLocalRepo()->findFile($nt) && wfFindFile($nt)) { $this->showForm(array('file-exists-sharedrepo')); return; } if ($wgUser->isAllowed('suppressredirect')) { $createRedirect = $this->leaveRedirect; } else { $createRedirect = true; } # Do the actual move. $error = $ot->moveTo($nt, true, $this->reason, $createRedirect); if ($error !== true) { # @todo FIXME: Show all the errors in a list, not just the first one $this->showForm(reset($error)); return; } if ($wgFixDoubleRedirects && $this->fixRedirects) { DoubleRedirectJob::fixRedirects('move', $ot, $nt); } wfRunHooks('SpecialMovepageAfterMove', array(&$this, &$ot, &$nt)); $wgOut->setPagetitle(wfMsg('pagemovedsub')); $oldUrl = $ot->getFullUrl('redirect=no'); $newUrl = $nt->getFullUrl(); $oldText = $ot->getPrefixedText(); $newText = $nt->getPrefixedText(); $oldLink = "<span class='plainlinks'>[{$oldUrl} {$oldText}]</span>"; $newLink = "<span class='plainlinks'>[{$newUrl} {$newText}]</span>"; $msgName = $createRedirect ? 'movepage-moved-redirect' : 'movepage-moved-noredirect'; $wgOut->addWikiMsg('movepage-moved', $oldLink, $newLink, $oldText, $newText); $wgOut->addWikiMsg($msgName); # Now we move extra pages we've been asked to move: subpages and talk # pages. First, if the old page or the new page is a talk page, we # can't move any talk pages: cancel that. if ($ot->isTalkPage() || $nt->isTalkPage()) { $this->moveTalk = false; } if (!$ot->userCan('move-subpages')) { $this->moveSubpages = false; } # Next make a list of id's. This might be marginally less efficient # than a more direct method, but this is not a highly performance-cri- # tical code path and readable code is more important here. # # Note: this query works nicely on MySQL 5, but the optimizer in MySQL # 4 might get confused. If so, consider rewriting as a UNION. # # If the target namespace doesn't allow subpages, moving with subpages # would mean that you couldn't move them back in one operation, which # is bad. # @todo FIXME: A specific error message should be given in this case. // @todo FIXME: Use Title::moveSubpages() here $dbr = wfGetDB(DB_MASTER); if ($this->moveSubpages && (MWNamespace::hasSubpages($nt->getNamespace()) || $this->moveTalk && MWNamespace::hasSubpages($nt->getTalkPage()->getNamespace()))) { $conds = array('page_title' . $dbr->buildLike($ot->getDBkey() . '/', $dbr->anyString()) . ' OR page_title = ' . $dbr->addQuotes($ot->getDBkey())); $conds['page_namespace'] = array(); if (MWNamespace::hasSubpages($nt->getNamespace())) { $conds['page_namespace'][] = $ot->getNamespace(); } if ($this->moveTalk && MWNamespace::hasSubpages($nt->getTalkPage()->getNamespace())) { $conds['page_namespace'][] = $ot->getTalkPage()->getNamespace(); } } elseif ($this->moveTalk) { $conds = array('page_namespace' => $ot->getTalkPage()->getNamespace(), 'page_title' => $ot->getDBkey()); } else { # Skip the query $conds = null; } $extraPages = array(); if (!is_null($conds)) { $extraPages = TitleArray::newFromResult($dbr->select('page', array('page_id', 'page_namespace', 'page_title'), $conds, __METHOD__)); } $extraOutput = array(); $skin = $this->getSkin(); $count = 1; foreach ($extraPages as $oldSubpage) { if ($ot->equals($oldSubpage)) { # Already did this one. continue; } $newPageName = preg_replace('#^' . preg_quote($ot->getDBkey(), '#') . '#', StringUtils::escapeRegexReplacement($nt->getDBkey()), $oldSubpage->getDBkey()); if ($oldSubpage->isTalkPage()) { $newNs = $nt->getTalkPage()->getNamespace(); } else { $newNs = $nt->getSubjectPage()->getNamespace(); } # Bug 14385: we need makeTitleSafe because the new page names may # be longer than 255 characters. $newSubpage = Title::makeTitleSafe($newNs, $newPageName); if (!$newSubpage) { $oldLink = $skin->linkKnown($oldSubpage); $extraOutput[] = wfMsgHtml('movepage-page-unmoved', $oldLink, htmlspecialchars(Title::makeName($newNs, $newPageName))); continue; } # This was copy-pasted from Renameuser, bleh. if ($newSubpage->exists() && !$oldSubpage->isValidMoveTarget($newSubpage)) { $link = $skin->linkKnown($newSubpage); $extraOutput[] = wfMsgHtml('movepage-page-exists', $link); } else { $success = $oldSubpage->moveTo($newSubpage, true, $this->reason, $createRedirect); if ($success === true) { if ($this->fixRedirects) { DoubleRedirectJob::fixRedirects('move', $oldSubpage, $newSubpage); } $oldLink = $skin->linkKnown($oldSubpage, null, array(), array('redirect' => 'no')); $newLink = $skin->linkKnown($newSubpage); $extraOutput[] = wfMsgHtml('movepage-page-moved', $oldLink, $newLink); ++$count; if ($count >= $wgMaximumMovedPages) { $extraOutput[] = wfMsgExt('movepage-max-pages', array('parsemag', 'escape'), $wgLang->formatNum($wgMaximumMovedPages)); break; } } else { $oldLink = $skin->linkKnown($oldSubpage); $newLink = $skin->link($newSubpage); $extraOutput[] = wfMsgHtml('movepage-page-unmoved', $oldLink, $newLink); } } } if ($extraOutput !== array()) { $wgOut->addHTML("<ul>\n<li>" . implode("</li>\n<li>", $extraOutput) . "</li>\n</ul>"); } # Deal with watches (we don't watch subpages) if ($this->watch && $wgUser->isLoggedIn()) { $wgUser->addWatch($ot); $wgUser->addWatch($nt); } else { $wgUser->removeWatch($ot); $wgUser->removeWatch($nt); } # Re-clear the file redirect cache, which may have been polluted by # parsing in messages above. See CR r56745. # @todo FIXME: Needs a more robust solution inside FileRepo. if ($ot->getNamespace() == NS_FILE) { RepoGroup::singleton()->getLocalRepo()->invalidateImageRedirect($ot); } }
/** * We have our own delete() function, since Article.php's implementation is split in two phases * * @param Article $article - Article object to work on * @param string $token - Delete token (same as edit token) * @param string $reason - Reason for the deletion. Autogenerated if NULL * @return Title::getUserPermissionsErrors()-like array */ public static function delete(&$article, $token, &$reason = null) { global $wgUser; if ($article->isBigDeletion() && !$wgUser->isAllowed('bigdelete')) { global $wgDeleteRevisionsLimit; return array(array('delete-toobig', $wgDeleteRevisionsLimit)); } $title = $article->getTitle(); $errors = self::getPermissionsError($title, $token); if (count($errors)) { return $errors; } // Auto-generate a summary, if necessary if (is_null($reason)) { // Need to pass a throwaway variable because generateReason expects // a reference $hasHistory = false; $reason = $article->generateReason($hasHistory); if ($reason === false) { return array(array('cannotdelete')); } } $error = ''; if (!wfRunHooks('ArticleDelete', array(&$article, &$wgUser, &$reason, $error))) { $this->dieUsageMsg(array('hookaborted', $error)); } // Luckily, Article.php provides a reusable delete function that does the hard work for us if ($article->doDeleteArticle($reason)) { wfRunHooks('ArticleDeleteComplete', array(&$article, &$wgUser, $reason, $article->getId())); return array(); } return array(array('cannotdelete', $article->mTitle->getPrefixedText())); }