Esempio n. 1
0
 /**
  * UI entry point for page deletion
  */
 public function delete()
 {
     # This code desperately needs to be totally rewritten
     $title = $this->getTitle();
     $context = $this->getContext();
     $user = $context->getUser();
     # Check permissions
     $permissionErrors = $title->getUserPermissionsErrors('delete', $user);
     if (count($permissionErrors)) {
         throw new PermissionsError('delete', $permissionErrors);
     }
     # Read-only check...
     if (wfReadOnly()) {
         throw new ReadOnlyError();
     }
     # Better double-check that it hasn't been deleted yet!
     $this->mPage->loadPageData('fromdbmaster');
     if (!$this->mPage->exists()) {
         $deleteLogPage = new LogPage('delete');
         $outputPage = $context->getOutput();
         $outputPage->setPageTitle($context->msg('cannotdelete-title', $title->getPrefixedText()));
         $outputPage->wrapWikiMsg("<div class=\"error mw-error-cannotdelete\">\n\$1\n</div>", array('cannotdelete', wfEscapeWikiText($title->getPrefixedText())));
         $outputPage->addHTML(Xml::element('h2', null, $deleteLogPage->getName()->text()));
         LogEventsList::showLogExtract($outputPage, 'delete', $title);
         return;
     }
     $request = $context->getRequest();
     $deleteReasonList = $request->getText('wpDeleteReasonList', 'other');
     $deleteReason = $request->getText('wpReason');
     if ($deleteReasonList == 'other') {
         $reason = $deleteReason;
     } elseif ($deleteReason != '') {
         // Entry from drop down menu + additional comment
         $colonseparator = wfMessage('colon-separator')->inContentLanguage()->text();
         $reason = $deleteReasonList . $colonseparator . $deleteReason;
     } else {
         $reason = $deleteReasonList;
     }
     if ($request->wasPosted() && $user->matchEditToken($request->getVal('wpEditToken'), array('delete', $this->getTitle()->getPrefixedText()))) {
         # Flag to hide all contents of the archived revisions
         $suppress = $request->getVal('wpSuppress') && $user->isAllowed('suppressrevision');
         $this->doDelete($reason, $suppress);
         WatchAction::doWatchOrUnwatch($request->getCheck('wpWatch'), $title, $user);
         return;
     }
     // Generate deletion reason
     $hasHistory = false;
     if (!$reason) {
         try {
             $reason = $this->generateReason($hasHistory);
         } catch (Exception $e) {
             # if a page is horribly broken, we still want to be able to
             # delete it. So be lenient about errors here.
             wfDebug("Error while building auto delete summary: {$e}");
             $reason = '';
         }
     }
     // If the page has a history, insert a warning
     if ($hasHistory) {
         $title = $this->getTitle();
         // The following can use the real revision count as this is only being shown for users
         // that can delete this page.
         // This, as a side-effect, also makes sure that the following query isn't being run for
         // pages with a larger history, unless the user has the 'bigdelete' right
         // (and is about to delete this page).
         $dbr = wfGetDB(DB_SLAVE);
         $revisions = $edits = (int) $dbr->selectField('revision', 'COUNT(rev_page)', array('rev_page' => $title->getArticleID()), __METHOD__);
         // @todo FIXME: i18n issue/patchwork message
         $context->getOutput()->addHTML('<strong class="mw-delete-warning-revisions">' . $context->msg('historywarning')->numParams($revisions)->parse() . $context->msg('word-separator')->escaped() . Linker::linkKnown($title, $context->msg('history')->escaped(), array(), array('action' => 'history')) . '</strong>');
         if ($title->isBigDeletion()) {
             global $wgDeleteRevisionsLimit;
             $context->getOutput()->wrapWikiMsg("<div class='error'>\n\$1\n</div>\n", array('delete-warning-toobig', $context->getLanguage()->formatNum($wgDeleteRevisionsLimit)));
         }
     }
     $this->confirmDelete($reason);
 }
Esempio n. 2
0
 /**
  * Save submitted protection form
  *
  * @return Boolean: success
  */
 function save()
 {
     global $wgRequest, $wgUser, $wgOut;
     # Permission check!
     if ($this->disabled) {
         $this->show();
         return false;
     }
     $token = $wgRequest->getVal('wpEditToken');
     if (!$wgUser->matchEditToken($token, array('protect', $this->mTitle->getPrefixedDBkey()))) {
         $this->show(array('sessionfailure'));
         return false;
     }
     # Create reason string. Use list and/or custom string.
     $reasonstr = $this->mReasonSelection;
     if ($reasonstr != 'other' && $this->mReason != '') {
         // Entry from drop down menu + additional comment
         $reasonstr .= wfMessage('colon-separator')->text() . $this->mReason;
     } elseif ($reasonstr == 'other') {
         $reasonstr = $this->mReason;
     }
     $expiry = array();
     foreach ($this->mApplicableTypes as $action) {
         $expiry[$action] = $this->getExpiry($action);
         if (empty($this->mRestrictions[$action])) {
             continue;
             // unprotected
         }
         if (!$expiry[$action]) {
             $this->show(array('protect_expiry_invalid'));
             return false;
         }
         if ($expiry[$action] < wfTimestampNow()) {
             $this->show(array('protect_expiry_old'));
             return false;
         }
     }
     $this->mCascade = $wgRequest->getBool('mwProtect-cascade');
     $status = $this->mArticle->doUpdateRestrictions($this->mRestrictions, $expiry, $this->mCascade, $reasonstr, $wgUser);
     if (!$status->isOK()) {
         $this->show($wgOut->parseInline($status->getWikiText()));
         return false;
     }
     /**
      * Give extensions a change to handle added form items
      *
      * @since 1.19 you can (and you should) return false to abort saving;
      *             you can also return an array of message name and its parameters
      */
     $errorMsg = '';
     if (!wfRunHooks('ProtectionForm::save', array($this->mArticle, &$errorMsg, $reasonstr))) {
         if ($errorMsg == '') {
             $errorMsg = array('hookaborted');
         }
     }
     if ($errorMsg != '') {
         $this->show($errorMsg);
         return false;
     }
     WatchAction::doWatchOrUnwatch($wgRequest->getCheck('mwProtectWatch'), $this->mTitle, $wgUser);
     return true;
 }
Esempio n. 3
0
 /**
  * Set a watch (or unwatch) based the based on a watchlist parameter.
  * @param string $watch Valid values: 'watch', 'unwatch', 'preferences', 'nochange'
  * @param Title $titleObj The article's title to change
  * @param string $userOption The user option to consider when $watch=preferences
  */
 protected function setWatch($watch, $titleObj, $userOption = null)
 {
     $value = $this->getWatchlistValue($watch, $titleObj, $userOption);
     if ($value === null) {
         return;
     }
     WatchAction::doWatchOrUnwatch($value, $titleObj, $this->getUser());
 }
Esempio n. 4
0
 function doSubmit()
 {
     $user = $this->getUser();
     if ($user->pingLimiter('move')) {
         throw new ThrottledError();
     }
     $ot = $this->oldTitle;
     $nt = $this->newTitle;
     # don't allow moving to pages with # in
     if (!$nt || $nt->hasFragment()) {
         $this->showForm(array(array('badtitletext')));
         return;
     }
     # Show a warning if the target file exists on a shared repo
     if ($nt->getNamespace() == NS_FILE && !($this->moveOverShared && $user->isAllowed('reupload-shared')) && !RepoGroup::singleton()->getLocalRepo()->findFile($nt) && wfFindFile($nt)) {
         $this->showForm(array(array('file-exists-sharedrepo')));
         return;
     }
     # Delete to make way if requested
     if ($this->deleteAndMove) {
         $permErrors = $nt->getUserPermissionsErrors('delete', $user);
         if (count($permErrors)) {
             # Only show the first error
             $this->showForm($permErrors);
             return;
         }
         $reason = $this->msg('delete_and_move_reason', $ot)->inContentLanguage()->text();
         // Delete an associated image if there is
         if ($nt->getNamespace() == NS_FILE) {
             $file = wfLocalFile($nt);
             $file->load(File::READ_LATEST);
             if ($file->exists()) {
                 $file->delete($reason, false, $user);
             }
         }
         $error = '';
         // passed by ref
         $page = WikiPage::factory($nt);
         $deleteStatus = $page->doDeleteArticleReal($reason, false, 0, true, $error, $user);
         if (!$deleteStatus->isGood()) {
             $this->showForm($deleteStatus->getErrorsArray());
             return;
         }
     }
     $handler = ContentHandler::getForTitle($ot);
     if (!$handler->supportsRedirects()) {
         $createRedirect = false;
     } elseif ($user->isAllowed('suppressredirect')) {
         $createRedirect = $this->leaveRedirect;
     } else {
         $createRedirect = true;
     }
     # Do the actual move.
     $mp = new MovePage($ot, $nt);
     $valid = $mp->isValidMove();
     if (!$valid->isOK()) {
         $this->showForm($valid->getErrorsArray());
         return;
     }
     $permStatus = $mp->checkPermissions($user, $this->reason);
     if (!$permStatus->isOK()) {
         $this->showForm($permStatus->getErrorsArray());
         return;
     }
     $status = $mp->move($user, $this->reason, $createRedirect);
     if (!$status->isOK()) {
         $this->showForm($status->getErrorsArray());
         return;
     }
     if ($this->getConfig()->get('FixDoubleRedirects') && $this->fixRedirects) {
         DoubleRedirectJob::fixRedirects('move', $ot, $nt);
     }
     $out = $this->getOutput();
     $out->setPageTitle($this->msg('pagemovedsub'));
     $oldLink = Linker::link($ot, null, array('id' => 'movepage-oldlink'), array('redirect' => 'no'));
     $newLink = Linker::linkKnown($nt, null, array('id' => 'movepage-newlink'));
     $oldText = $ot->getPrefixedText();
     $newText = $nt->getPrefixedText();
     if ($ot->exists()) {
         // NOTE: we assume that if the old title exists, it's because it was re-created as
         // a redirect to the new title. This is not safe, but what we did before was
         // even worse: we just determined whether a redirect should have been created,
         // and reported that it was created if it should have, without any checks.
         // Also note that isRedirect() is unreliable because of bug 37209.
         $msgName = 'movepage-moved-redirect';
     } else {
         $msgName = 'movepage-moved-noredirect';
     }
     $out->addHTML($this->msg('movepage-moved')->rawParams($oldLink, $newLink)->params($oldText, $newText)->parseAsBlock());
     $out->addWikiMsg($msgName);
     Hooks::run('SpecialMovepageAfterMove', array(&$this, &$ot, &$nt));
     # 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 (count($ot->getUserPermissionsErrors('move-subpages', $user))) {
         $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();
     $count = 1;
     foreach ($extraPages as $oldSubpage) {
         if ($ot->equals($oldSubpage) || $nt->equals($oldSubpage)) {
             # Already did this one.
             continue;
         }
         $newPageName = preg_replace('#^' . preg_quote($ot->getDBkey(), '#') . '#', StringUtils::escapeRegexReplacement($nt->getDBkey()), $oldSubpage->getDBkey());
         if ($oldSubpage->isSubpage() && ($ot->isTalkPage() xor $nt->isTalkPage())) {
             // Moving a subpage from a subject namespace to a talk namespace or vice-versa
             $newNs = $nt->getNamespace();
         } elseif ($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 = Linker::linkKnown($oldSubpage);
             $extraOutput[] = $this->msg('movepage-page-unmoved')->rawParams($oldLink)->params(Title::makeName($newNs, $newPageName))->escaped();
             continue;
         }
         # This was copy-pasted from Renameuser, bleh.
         if ($newSubpage->exists() && !$oldSubpage->isValidMoveTarget($newSubpage)) {
             $link = Linker::linkKnown($newSubpage);
             $extraOutput[] = $this->msg('movepage-page-exists')->rawParams($link)->escaped();
         } else {
             $success = $oldSubpage->moveTo($newSubpage, true, $this->reason, $createRedirect);
             if ($success === true) {
                 if ($this->fixRedirects) {
                     DoubleRedirectJob::fixRedirects('move', $oldSubpage, $newSubpage);
                 }
                 $oldLink = Linker::link($oldSubpage, null, array(), array('redirect' => 'no'));
                 $newLink = Linker::linkKnown($newSubpage);
                 $extraOutput[] = $this->msg('movepage-page-moved')->rawParams($oldLink, $newLink)->escaped();
                 ++$count;
                 $maximumMovedPages = $this->getConfig()->get('MaximumMovedPages');
                 if ($count >= $maximumMovedPages) {
                     $extraOutput[] = $this->msg('movepage-max-pages')->numParams($maximumMovedPages)->escaped();
                     break;
                 }
             } else {
                 $oldLink = Linker::linkKnown($oldSubpage);
                 $newLink = Linker::link($newSubpage);
                 $extraOutput[] = $this->msg('movepage-page-unmoved')->rawParams($oldLink, $newLink)->escaped();
             }
         }
     }
     if ($extraOutput !== array()) {
         $out->addHTML("<ul>\n<li>" . implode("</li>\n<li>", $extraOutput) . "</li>\n</ul>");
     }
     # Deal with watches (we don't watch subpages)
     WatchAction::doWatchOrUnwatch($this->watch, $ot, $user);
     WatchAction::doWatchOrUnwatch($this->watch, $nt, $user);
 }
Esempio n. 5
0
 /**
  * Fulfil the request; shows the form or deletes the file,
  * pending authentication, confirmation, etc.
  */
 public function execute()
 {
     global $wgOut, $wgRequest, $wgUser, $wgUploadMaintenance;
     $permissionErrors = $this->title->getUserPermissionsErrors('delete', $wgUser);
     if (count($permissionErrors)) {
         throw new PermissionsError('delete', $permissionErrors);
     }
     if (wfReadOnly()) {
         throw new ReadOnlyError();
     }
     if ($wgUploadMaintenance) {
         throw new ErrorPageError('filedelete-maintenance-title', 'filedelete-maintenance');
     }
     $this->setHeaders();
     $this->oldimage = $wgRequest->getText('oldimage', false);
     $token = $wgRequest->getText('wpEditToken');
     # Flag to hide all contents of the archived revisions
     $suppress = $wgRequest->getVal('wpSuppress') && $wgUser->isAllowed('suppressrevision');
     if ($this->oldimage) {
         $this->oldfile = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName($this->title, $this->oldimage);
     }
     if (!self::haveDeletableFile($this->file, $this->oldfile, $this->oldimage)) {
         $wgOut->addHTML($this->prepareMessage('filedelete-nofile'));
         $wgOut->addReturnTo($this->title);
         return;
     }
     // Perform the deletion if appropriate
     if ($wgRequest->wasPosted() && $wgUser->matchEditToken($token, $this->oldimage)) {
         $deleteReasonList = $wgRequest->getText('wpDeleteReasonList');
         $deleteReason = $wgRequest->getText('wpReason');
         if ($deleteReasonList == 'other') {
             $reason = $deleteReason;
         } elseif ($deleteReason != '') {
             // Entry from drop down menu + additional comment
             $reason = $deleteReasonList . wfMessage('colon-separator')->inContentLanguage()->text() . $deleteReason;
         } else {
             $reason = $deleteReasonList;
         }
         $status = self::doDelete($this->title, $this->file, $this->oldimage, $reason, $suppress, $wgUser);
         if (!$status->isGood()) {
             $wgOut->addHTML('<h2>' . $this->prepareMessage('filedeleteerror-short') . "</h2>\n");
             $wgOut->addWikiText('<div class="error">' . $status->getWikiText('filedeleteerror-short', 'filedeleteerror-long') . '</div>');
         }
         if ($status->ok) {
             $wgOut->setPageTitle(wfMessage('actioncomplete'));
             $wgOut->addHTML($this->prepareMessage('filedelete-success'));
             // Return to the main page if we just deleted all versions of the
             // file, otherwise go back to the description page
             $wgOut->addReturnTo($this->oldimage ? $this->title : Title::newMainPage());
             WatchAction::doWatchOrUnwatch($wgRequest->getCheck('wpWatch'), $this->title, $wgUser);
         }
         return;
     }
     $this->showForm();
     $this->showLogEntries();
 }
Esempio n. 6
0
 /**
  * Register the change of watch status
  */
 protected function updateWatchlist()
 {
     global $wgUser;
     if ($wgUser->isLoggedIn() && $this->watchthis != $wgUser->isWatched($this->mTitle, WatchedItem::IGNORE_USER_RIGHTS)) {
         $fname = __METHOD__;
         $title = $this->mTitle;
         $watch = $this->watchthis;
         // Do this in its own transaction to reduce contention...
         $dbw = wfGetDB(DB_MASTER);
         $dbw->onTransactionIdle(function () use($dbw, $title, $watch, $wgUser, $fname) {
             WatchAction::doWatchOrUnwatch($watch, $title, $wgUser);
         });
     }
 }
Esempio n. 7
0
 /**
  * Register the change of watch status
  */
 protected function updateWatchlist()
 {
     global $wgUser;
     if (!$wgUser->isLoggedIn()) {
         return;
     }
     $user = $wgUser;
     $title = $this->mTitle;
     $watch = $this->watchthis;
     // Do this in its own transaction to reduce contention...
     DeferredUpdates::addCallableUpdate(function () use($user, $title, $watch) {
         if ($watch == $user->isWatched($title, WatchedItem::IGNORE_USER_RIGHTS)) {
             return;
             // nothing to change
         }
         WatchAction::doWatchOrUnwatch($watch, $title, $user);
     });
 }