public function execute() { global $wgUser; if (!$wgUser->isLoggedIn()) { $this->dieUsage('You must be logged-in to have a watchlist', 'notloggedin'); } $params = $this->extractRequestParams(); $title = Title::newFromText($params['title']); if (!$title || $title->getNamespace() < 0) { $this->dieUsageMsg(array('invalidtitle', $params['title'])); } $article = new Article($title, 0); $res = array('title' => $title->getPrefixedText()); if ($params['unwatch']) { $res['unwatched'] = ''; $res['message'] = wfMsgExt('removedwatchtext', array('parse'), $title->getPrefixedText()); $success = WatchAction::doUnwatch($title, $wgUser); } else { $res['watched'] = ''; $res['message'] = wfMsgExt('addedwatchtext', array('parse'), $title->getPrefixedText()); $success = UnwatchAction::doWatch($title, $wgUser); } if (!$success) { $this->dieUsageMsg('hookaborted'); } $this->getResult()->addValue(null, $this->getModuleName(), $res); }
/** * @param $skin Skin * @param $result * @return string */ function formatResult($skin, $result) { global $wgContLang; $nt = Title::makeTitle($result->namespace, $result->title); $text = $wgContLang->convert($nt->getPrefixedText()); $plink = Linker::linkKnown($nt, htmlspecialchars($text)); $token = WatchAction::getWatchToken($nt, $this->getUser()); $wlink = Linker::linkKnown($nt, wfMsgHtml('watch'), array(), array('action' => 'watch', 'token' => $token)); return $this->getLanguage()->specialList($plink, $wlink); }
/** * @param Skin $skin * @param object $result Result row * @return string */ function formatResult($skin, $result) { global $wgContLang; $nt = Title::makeTitleSafe($result->namespace, $result->title); if (!$nt) { return Html::element('span', array('class' => 'mw-invalidtitle'), Linker::getInvalidTitleDescription($this->getContext(), $result->namespace, $result->title)); } $text = $wgContLang->convert($nt->getPrefixedText()); $plink = Linker::linkKnown($nt, htmlspecialchars($text)); $token = WatchAction::getWatchToken($nt, $this->getUser()); $wlink = Linker::linkKnown($nt, $this->msg('watch')->escaped(), array(), array('action' => 'watch', 'token' => $token)); return $this->getLanguage()->specialList($plink, $wlink); }
public function execute() { $user = $this->getUser(); if ( !$user->isLoggedIn() ) { $this->dieUsage( 'You must be logged-in to have a watchlist', 'notloggedin' ); } if ( !$user->isAllowed( 'editmywatchlist' ) ) { $this->dieUsage( 'You don\'t have permission to edit your watchlist', 'permissiondenied' ); } $params = $this->extractRequestParams(); $title = Title::newFromText( $params['title'] ); if ( !$title || $title->isExternal() || !$title->canExist() ) { $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) ); } $res = array( 'title' => $title->getPrefixedText() ); // Currently unnecessary, code to act as a safeguard against any change in current behavior of uselang // Copy from ApiParse $oldLang = null; if ( isset( $params['uselang'] ) && $params['uselang'] != $this->getContext()->getLanguage()->getCode() ) { $oldLang = $this->getContext()->getLanguage(); // Backup language $this->getContext()->setLanguage( Language::factory( $params['uselang'] ) ); } if ( $params['unwatch'] ) { $res['unwatched'] = ''; $res['message'] = $this->msg( 'removedwatchtext', $title->getPrefixedText() )->title( $title )->parseAsBlock(); $status = UnwatchAction::doUnwatch( $title, $user ); } else { $res['watched'] = ''; $res['message'] = $this->msg( 'addedwatchtext', $title->getPrefixedText() )->title( $title )->parseAsBlock(); $status = WatchAction::doWatch( $title, $user ); } if ( !is_null( $oldLang ) ) { $this->getContext()->setLanguage( $oldLang ); // Reset language to $oldLang } if ( !$status->isOK() ) { $this->dieStatus( $status ); } $this->getResult()->addValue( null, $this->getModuleName(), $res ); }
public function move($params) { global $wgUser; $currentUser = $wgUser; $wgUser = User::newFromId($this->createdBy); $currentPageName = $this->title->getText(); if ($params['use_regex']) { $newPageName = preg_replace("/{$params['target_str']}/U", $params['replacement_str'], $currentPageName); } else { $newPageName = str_replace($params['target_str'], $params['replacement_str'], $currentPageName); } $newTitle = Title::newFromText($newPageName, $this->title->getNamespace()); $result = $this->title->moveTo($newTitle, true, $params['edit_summary'], $params['create_redirect']); if ($result == true && $params['watch_page']) { WatchAction::doWatch($newTitle, $wgUser); } $wgUser = $currentUser; return $result; }
/** * Adds a user to watchlists of all articles defined in the * global $wgAutoFollowWatchlist variable. * @param integer $iUserId The user's ID */ public function addUserToDefaultWatchlistTask($iUserId) { global $wgAutoFollowWatchlist; if (!empty($wgAutoFollowWatchlist)) { $oUser = \User::newFromId($iUserId); $aWatchSuccess = $aWatchFail = []; foreach ($wgAutoFollowWatchlist as $sTitleText) { $oTitle = \Title::newFromText($sTitleText); if ($oTitle instanceof \Title) { \WatchAction::doWatch($oTitle, $oUser); $aWatchSuccess[] = $sTitleText; } else { $aWatchFail[] = $sTitleText; } } if (count($aWatchFail) === 0) { $this->setFlag($oUser); } $this->logResults($oUser, $aWatchSuccess, $aWatchFail); } }
function delete() { global $wgUser, $wgOut, $wgRequest; $confirm = $wgRequest->wasPosted() && $wgUser->matchEditToken($wgRequest->getVal('wpEditToken')); $reason = $wgRequest->getText('wpReason'); # This code desperately needs to be totally rewritten # Check permissions $permission_errors = $this->mTitle->getUserPermissionsErrors('mv_delete_mvd', $wgUser); if (count($permission_errors) > 0) { $wgOut->showPermissionsErrorPage($permission_errors); return; } $wgOut->setPagetitle(wfMsg('confirmdelete')); # Better double-check that it hasn't been deleted yet! $dbw = wfGetDB(DB_MASTER); $conds = $this->mTitle->pageCond(); $latest = $dbw->selectField('page', 'page_latest', $conds, __METHOD__); if ($latest === false) { $wgOut->showFatalError(wfMsg('cannotdelete')); return; } if ($confirm) { $this->doDelete($reason); if ($wgRequest->getCheck('wpWatch')) { WatchAction::doWatch($this->mTitle, $wgUser); } elseif ($this->mTitle->userIsWatching()) { WatchAction::doUnwatch($this->mTitle, $wgUser); } return; } // Generate deletion reason $hasHistory = false; $reason = $this->generateReason($hasHistory); // If the page has a history, insert a warning if ($hasHistory && !$confirm) { $skin = $wgUser->getSkin(); $wgOut->addHTML('<strong>' . wfMsg('historywarning') . ' ' . $skin->historyLink() . '</strong>'); } return $this->confirmDelete('', $reason); }
/** * Really perform the upload. Stores the file in the local repo, watches * if necessary and runs the UploadComplete hook. * * @param $comment * @param $pageText * @param $watch * @param $user User * * @return Status indicating the whether the upload succeeded. */ public function performUpload($comment, $pageText, $watch, $user) { wfProfileIn(__METHOD__); $status = $this->getLocalFile()->upload($this->mTempPath, $comment, $pageText, File::DELETE_SOURCE, $this->mFileProps, false, $user); if ($status->isGood()) { if ($watch) { WatchAction::doWatch($this->getLocalFile()->getTitle(), $user, WatchedItem::IGNORE_USER_RIGHTS); } wfRunHooks('UploadComplete', array(&$this)); } wfProfileOut(__METHOD__); return $status; }
/** * a structured array of links usually used for the tabs in a skin * * There are 4 standard sections * namespaces: Used for namespace tabs like special, page, and talk namespaces * views: Used for primary page views like read, edit, history * actions: Used for most extra page actions like deletion, protection, etc... * variants: Used to list the language variants for the page * * Each section's value is a key/value array of links for that section. * The links themselves have these common keys: * - class: The css classes to apply to the tab * - text: The text to display on the tab * - href: The href for the tab to point to * - rel: An optional rel= for the tab's link * - redundant: If true the tab will be dropped in skins using content_actions * this is useful for tabs like "Read" which only have meaning in skins that * take special meaning from the grouped structure of content_navigation * * Views also have an extra key which can be used: * - primary: If this is not true skins like vector may try to hide the tab * when the user has limited space in their browser window * * content_navigation using code also expects these ids to be present on the * links, however these are usually automatically generated by SkinTemplate * itself and are not necessary when using a hook. The only things these may * matter to are people modifying content_navigation after it's initial creation: * - id: A "preferred" id, most skins are best off outputting this preferred * id for best compatibility. * - tooltiponly: This is set to true for some tabs in cases where the system * believes that the accesskey should not be added to the tab. * * @return array */ protected function buildContentNavigationUrls() { global $wgDisableLangConversion; // Display tabs for the relevant title rather than always the title itself $title = $this->getRelevantTitle(); $onPage = $title->equals($this->getTitle()); $out = $this->getOutput(); $request = $this->getRequest(); $user = $this->getUser(); $content_navigation = array('namespaces' => array(), 'views' => array(), 'actions' => array(), 'variants' => array()); // parameters $action = $request->getVal('action', 'view'); $userCanRead = $title->quickUserCan('read', $user); $preventActiveTabs = false; Hooks::run('SkinTemplatePreventOtherActiveTabs', array(&$this, &$preventActiveTabs)); // Checks if page is some kind of content if ($title->canExist()) { // Gets page objects for the related namespaces $subjectPage = $title->getSubjectPage(); $talkPage = $title->getTalkPage(); // Determines if this is a talk page $isTalk = $title->isTalkPage(); // Generates XML IDs from namespace names $subjectId = $title->getNamespaceKey(''); if ($subjectId == 'main') { $talkId = 'talk'; } else { $talkId = "{$subjectId}_talk"; } $skname = $this->skinname; // Adds namespace links $subjectMsg = array("nstab-{$subjectId}"); if ($subjectPage->isMainPage()) { array_unshift($subjectMsg, 'mainpage-nstab'); } $content_navigation['namespaces'][$subjectId] = $this->tabAction($subjectPage, $subjectMsg, !$isTalk && !$preventActiveTabs, '', $userCanRead); $content_navigation['namespaces'][$subjectId]['context'] = 'subject'; $content_navigation['namespaces'][$talkId] = $this->tabAction($talkPage, array("nstab-{$talkId}", 'talk'), $isTalk && !$preventActiveTabs, '', $userCanRead); $content_navigation['namespaces'][$talkId]['context'] = 'talk'; if ($userCanRead) { $isForeignFile = $title->inNamespace(NS_FILE) && $this->canUseWikiPage() && $this->getWikiPage() instanceof WikiFilePage && !$this->getWikiPage()->isLocal(); // Adds view view link if ($title->exists() || $isForeignFile) { $content_navigation['views']['view'] = $this->tabAction($isTalk ? $talkPage : $subjectPage, array("{$skname}-view-view", 'view'), $onPage && ($action == 'view' || $action == 'purge'), '', true); // signal to hide this from simple content_actions $content_navigation['views']['view']['redundant'] = true; } // If it is a non-local file, show a link to the file in its own repository if ($isForeignFile) { $file = $this->getWikiPage()->getFile(); $content_navigation['views']['view-foreign'] = array('class' => '', 'text' => wfMessageFallback("{$skname}-view-foreign", 'view-foreign')->setContext($this->getContext())->params($file->getRepo()->getDisplayName())->text(), 'href' => $file->getDescriptionUrl(), 'primary' => false); } // Checks if user can edit the current page if it exists or create it otherwise if ($title->quickUserCan('edit', $user) && ($title->exists() || $title->quickUserCan('create', $user))) { // Builds CSS class for talk page links $isTalkClass = $isTalk ? ' istalk' : ''; // Whether the user is editing the page $isEditing = $onPage && ($action == 'edit' || $action == 'submit'); // Whether to show the "Add a new section" tab // Checks if this is a current rev of talk page and is not forced to be hidden $showNewSection = !$out->forceHideNewSectionLink() && ($isTalk && $this->isRevisionCurrent() || $out->showNewSectionLink()); $section = $request->getVal('section'); if ($title->exists() || $title->getNamespace() == NS_MEDIAWIKI && $title->getDefaultMessageText() !== false) { $msgKey = $isForeignFile ? 'edit-local' : 'edit'; } else { $msgKey = $isForeignFile ? 'create-local' : 'create'; } $content_navigation['views']['edit'] = array('class' => ($isEditing && ($section !== 'new' || !$showNewSection) ? 'selected' : '') . $isTalkClass, 'text' => wfMessageFallback("{$skname}-view-{$msgKey}", $msgKey)->setContext($this->getContext())->text(), 'href' => $title->getLocalURL($this->editUrlOptions()), 'primary' => !$isForeignFile); // section link if ($showNewSection) { // Adds new section link //$content_navigation['actions']['addsection'] $content_navigation['views']['addsection'] = array('class' => $isEditing && $section == 'new' ? 'selected' : false, 'text' => wfMessageFallback("{$skname}-action-addsection", 'addsection')->setContext($this->getContext())->text(), 'href' => $title->getLocalURL('action=edit§ion=new')); } // Checks if the page has some kind of viewable content } elseif ($title->hasSourceText()) { // Adds view source view link $content_navigation['views']['viewsource'] = array('class' => $onPage && $action == 'edit' ? 'selected' : false, 'text' => wfMessageFallback("{$skname}-action-viewsource", 'viewsource')->setContext($this->getContext())->text(), 'href' => $title->getLocalURL($this->editUrlOptions()), 'primary' => true); } // Checks if the page exists if ($title->exists()) { // Adds history view link $content_navigation['views']['history'] = array('class' => $onPage && $action == 'history' ? 'selected' : false, 'text' => wfMessageFallback("{$skname}-view-history", 'history_short')->setContext($this->getContext())->text(), 'href' => $title->getLocalURL('action=history')); if ($title->quickUserCan('delete', $user)) { $content_navigation['actions']['delete'] = array('class' => $onPage && $action == 'delete' ? 'selected' : false, 'text' => wfMessageFallback("{$skname}-action-delete", 'delete')->setContext($this->getContext())->text(), 'href' => $title->getLocalURL('action=delete')); } if ($title->quickUserCan('move', $user)) { $moveTitle = SpecialPage::getTitleFor('Movepage', $title->getPrefixedDBkey()); $content_navigation['actions']['move'] = array('class' => $this->getTitle()->isSpecial('Movepage') ? 'selected' : false, 'text' => wfMessageFallback("{$skname}-action-move", 'move')->setContext($this->getContext())->text(), 'href' => $moveTitle->getLocalURL()); } } else { // article doesn't exist or is deleted if ($user->isAllowed('deletedhistory')) { $n = $title->isDeleted(); if ($n) { $undelTitle = SpecialPage::getTitleFor('Undelete', $title->getPrefixedDBkey()); // If the user can't undelete but can view deleted // history show them a "View .. deleted" tab instead. $msgKey = $user->isAllowed('undelete') ? 'undelete' : 'viewdeleted'; $content_navigation['actions']['undelete'] = array('class' => $this->getTitle()->isSpecial('Undelete') ? 'selected' : false, 'text' => wfMessageFallback("{$skname}-action-{$msgKey}", "{$msgKey}_short")->setContext($this->getContext())->numParams($n)->text(), 'href' => $undelTitle->getLocalURL()); } } } if ($title->quickUserCan('protect', $user) && $title->getRestrictionTypes() && MWNamespace::getRestrictionLevels($title->getNamespace(), $user) !== array('')) { $mode = $title->isProtected() ? 'unprotect' : 'protect'; $content_navigation['actions'][$mode] = array('class' => $onPage && $action == $mode ? 'selected' : false, 'text' => wfMessageFallback("{$skname}-action-{$mode}", $mode)->setContext($this->getContext())->text(), 'href' => $title->getLocalURL("action={$mode}")); } // Checks if the user is logged in if ($this->loggedin && $user->isAllowedAll('viewmywatchlist', 'editmywatchlist')) { /** * The following actions use messages which, if made particular to * the any specific skins, would break the Ajax code which makes this * action happen entirely inline. OutputPage::getJSVars * defines a set of messages in a javascript object - and these * messages are assumed to be global for all skins. Without making * a change to that procedure these messages will have to remain as * the global versions. */ $mode = $user->isWatched($title) ? 'unwatch' : 'watch'; $token = WatchAction::getWatchToken($title, $user, $mode); $content_navigation['actions'][$mode] = array('class' => $onPage && ($action == 'watch' || $action == 'unwatch') ? 'selected' : false, 'text' => $this->msg($mode)->text(), 'href' => $title->getLocalURL(array('action' => $mode, 'token' => $token))); } } Hooks::run('SkinTemplateNavigation', array(&$this, &$content_navigation)); if ($userCanRead && !$wgDisableLangConversion) { $pageLang = $title->getPageLanguage(); // Gets list of language variants $variants = $pageLang->getVariants(); // Checks that language conversion is enabled and variants exist // And if it is not in the special namespace if (count($variants) > 1) { // Gets preferred variant (note that user preference is // only possible for wiki content language variant) $preferred = $pageLang->getPreferredVariant(); if (Action::getActionName($this) === 'view') { $params = $request->getQueryValues(); unset($params['title']); } else { $params = array(); } // Loops over each variant foreach ($variants as $code) { // Gets variant name from language code $varname = $pageLang->getVariantname($code); // Appends variant link $content_navigation['variants'][] = array('class' => $code == $preferred ? 'selected' : false, 'text' => $varname, 'href' => $title->getLocalURL(array('variant' => $code) + $params), 'lang' => wfBCP47($code), 'hreflang' => wfBCP47($code)); } } } } else { // If it's not content, it's got to be a special page $content_navigation['namespaces']['special'] = array('class' => 'selected', 'text' => $this->msg('nstab-special')->text(), 'href' => $request->getRequestURL(), 'context' => 'subject'); Hooks::run('SkinTemplateNavigation::SpecialPage', array(&$this, &$content_navigation)); } // Equiv to SkinTemplateContentActions Hooks::run('SkinTemplateNavigation::Universal', array(&$this, &$content_navigation)); // Setup xml ids and tooltip info foreach ($content_navigation as $section => &$links) { foreach ($links as $key => &$link) { $xmlID = $key; if (isset($link['context']) && $link['context'] == 'subject') { $xmlID = 'ca-nstab-' . $xmlID; } elseif (isset($link['context']) && $link['context'] == 'talk') { $xmlID = 'ca-talk'; } elseif ($section == 'variants') { $xmlID = 'ca-varlang-' . $xmlID; } else { $xmlID = 'ca-' . $xmlID; } $link['id'] = $xmlID; } } # We don't want to give the watch tab an accesskey if the # page is being edited, because that conflicts with the # accesskey on the watch checkbox. We also don't want to # give the edit tab an accesskey, because that's fairly # superfluous and conflicts with an accesskey (Ctrl-E) often # used for editing in Safari. if (in_array($action, array('edit', 'submit'))) { if (isset($content_navigation['views']['edit'])) { $content_navigation['views']['edit']['tooltiponly'] = true; } if (isset($content_navigation['actions']['watch'])) { $content_navigation['actions']['watch']['tooltiponly'] = true; } if (isset($content_navigation['actions']['unwatch'])) { $content_navigation['actions']['unwatch']['tooltiponly'] = true; } } return $content_navigation; }
/** * Stop watching a page * @return bool true on successful unwatch * @deprecated since 1.18 */ public function doUnwatch() { wfDeprecated(__METHOD__, '1.18'); return WatchAction::doUnwatch($this->getTitle(), $this->getContext()->getUser()); }
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); }
/** * Commit the change of watch status */ protected function commitWatch() { global $wgUser; if ($this->watchthis xor $this->mTitle->userIsWatching()) { $dbw = wfGetDB(DB_MASTER); $dbw->begin(); if ($this->watchthis) { WatchAction::doWatch($this->mTitle, $wgUser); } else { WatchAction::doUnwatch($this->mTitle, $wgUser); } $dbw->commit(); } }
function watchThisPage() { global $wgOut, $wgUser; ++$this->mWatchLinkNum; // Cache $title = $this->getSkin()->getTitle(); if ($wgOut->isArticleRelated()) { if ($wgUser->isWatched($title)) { $text = wfMessage('unwatchthispage')->text(); $query = array('action' => 'unwatch', 'token' => UnwatchAction::getUnwatchToken($title, $wgUser)); $id = 'mw-unwatch-link' . $this->mWatchLinkNum; } else { $text = wfMessage('watchthispage')->text(); $query = array('action' => 'watch', 'token' => WatchAction::getWatchToken($title, $wgUser)); $id = 'mw-watch-link' . $this->mWatchLinkNum; } $s = Linker::linkKnown($title, $text, array('id' => $id), $query); } else { $s = wfMessage('notanarticle')->text(); } return $s; }
/** * Stop watching a page * @return bool true on successful unwatch * @deprecated since 1.18 */ public function doUnwatch() { global $wgUser; wfDeprecated(__METHOD__, '1.18'); return WatchAction::doUnwatch($this->getTitle(), $wgUser); }
/** * @param $thread Thread */ function topLevelThreadCommands($thread) { $commands = array(); $commands['history'] = array('label' => wfMessage('history_short')->parse(), 'href' => self::permalinkUrl($thread, 'thread_history'), 'enabled' => true); if ($this->user->isAllowed('move')) { $move_href = SpecialPage::getTitleFor('MoveThread', $thread->title()->getPrefixedText())->getLocalURL(); $commands['move'] = array('label' => wfMessage('lqt-movethread')->parse(), 'href' => $move_href, 'enabled' => true); } if ($this->user->isAllowed('protect')) { $protect_href = $thread->title()->getLocalURL('action=protect'); // Check if it's already protected if (!$thread->title()->isProtected()) { $label = wfMessage('protect')->parse(); } else { $label = wfMessage('unprotect')->parse(); } $commands['protect'] = array('label' => $label, 'href' => $protect_href, 'enabled' => true); } if (!$this->user->isAnon() && !$thread->title()->userIsWatching()) { $commands['watch'] = array('label' => wfMessage('watch')->parse(), 'href' => self::permalinkUrlWithQuery($thread, array('action' => 'watch', 'token' => WatchAction::getWatchToken($thread->title(), $this->user, 'watch'))), 'enabled' => true); } elseif (!$this->user->isAnon()) { $commands['unwatch'] = array('label' => wfMessage('unwatch')->parse(), 'href' => self::permalinkUrlWithQuery($thread, array('action' => 'unwatch', 'token' => WatchAction::getWatchToken($thread->title(), $this->user, 'unwatch'))), 'enabled' => true); } if (LqtDispatch::isLqtPage($thread->getTitle())) { $summarizeUrl = self::permalinkUrl($thread, 'summarize', $thread->id()); $commands['summarize'] = array('label' => wfMessage('lqt_summarize_link')->parse(), 'href' => $summarizeUrl, 'enabled' => true); } Hooks::run('LiquidThreadsTopLevelCommands', array($thread, &$commands)); return $commands; }
/** * 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; }
static function create($root, $article, $superthread = null, $type = Threads::TYPE_NORMAL, $subject = '', $summary = '', $bump = null, $signature = null) { $thread = new Thread(null); if (!in_array($type, self::$VALID_TYPES)) { throw new MWException(__METHOD__ . ": invalid change type {$type}."); } if ($superthread) { $change_type = Threads::CHANGE_REPLY_CREATED; } else { $change_type = Threads::CHANGE_NEW_THREAD; } global $wgUser; $thread->setAuthor($wgUser); if (is_object($root)) { $thread->setRoot($root); } else { $thread->setRootId($root); } $thread->setSuperthread($superthread); $thread->setArticle($article); $thread->setSubject($subject); $thread->setType($type); if (!is_null($signature)) { $thread->setSignature($signature); } $thread->insert(); if ($superthread) { $superthread->addReply($thread); $superthread->commitRevision($change_type, $thread, $summary, $bump); } else { $hthread = ThreadRevision::create($thread, $change_type); } // Create talk page Threads::createTalkpageIfNeeded($article); // Notifications NewMessages::writeMessageStateForUpdatedThread($thread, $change_type, $wgUser); if ($wgUser->getOption('lqt-watch-threads', false)) { WatchAction::doWatch($thread->topmostThread()->root()->getTitle(), $wgUser); } return $thread; }
/** * 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); }); } }
/** * 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); }); }
/** * Really perform the upload. Stores the file in the local repo, watches * if necessary and runs the UploadComplete hook. * * @param string $comment * @param string $pageText * @param bool $watch Whether the file page should be added to user's watchlist. * (This doesn't check $user's permissions.) * @param User $user * @param string[] $tags Change tags to add to the log entry and page revision. * (This doesn't check $user's permissions.) * @return Status Indicating the whether the upload succeeded. */ public function performUpload($comment, $pageText, $watch, $user, $tags = []) { $this->getLocalFile()->load(File::READ_LATEST); $props = $this->mFileProps; $error = null; Hooks::run('UploadVerifyUpload', [$this, $user, $props, $comment, $pageText, &$error]); if ($error) { if (!is_array($error)) { $error = [$error]; } return call_user_func_array('Status::newFatal', $error); } $status = $this->getLocalFile()->upload($this->mTempPath, $comment, $pageText, File::DELETE_SOURCE, $props, false, $user, $tags); if ($status->isGood()) { if ($watch) { WatchAction::doWatch($this->getLocalFile()->getTitle(), $user, User::IGNORE_USER_RIGHTS); } Hooks::run('UploadComplete', [&$this]); $this->postProcessUpload(); } return $status; }
/** * Really delete the file * * @param $title Title object * @param $file File object * @param $oldimage String: archive name * @param $reason String: reason of the deletion * @param $suppress Boolean: whether to mark all deleted versions as restricted */ public static function doDelete(&$title, &$file, &$oldimage, $reason, $suppress) { global $wgUser; $article = null; $status = Status::newFatal('error'); if ($oldimage) { $status = $file->deleteOld($oldimage, $reason, $suppress); if ($status->ok) { // Need to do a log item $log = new LogPage('delete'); $logComment = wfMsgForContent('deletedrevision', $oldimage); if (trim($reason) != '') { $logComment .= wfMsgForContent('colon-separator') . $reason; } $log->addEntry('delete', $title, $logComment); } } else { $id = $title->getArticleID(Title::GAID_FOR_UPDATE); $article = new Article($title); $dbw = wfGetDB(DB_MASTER); try { // delete the associated article first if ($article->doDeleteArticle($reason, $suppress, $id, false)) { global $wgRequest; if ($wgRequest->getCheck('wpWatch') && $wgUser->isLoggedIn()) { WatchAction::doWatch($title, $wgUser); } elseif ($title->userIsWatching()) { WatchAction::doUnwatch($title, $wgUser); } $status = $file->delete($reason, $suppress); if ($status->ok) { $dbw->commit(); } else { $dbw->rollback(); } } } catch (MWException $e) { // rollback before returning to prevent UI from displaying incorrect "View or restore N deleted edits?" $dbw->rollback(); throw $e; } } if ($status->isGood()) { wfRunHooks('FileDeleteComplete', array(&$file, &$oldimage, &$article, &$wgUser, &$reason)); } return $status; }
/** * 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()); }
/** * 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(); }
/** * Register the change of watch status */ protected function updateWatchlist() { global $wgUser; if ($wgUser->isLoggedIn() && $this->watchthis != $wgUser->isWatched($this->mTitle)) { $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) { $dbw->begin($fname); if ($watch) { WatchAction::doWatch($title, $wgUser); } else { WatchAction::doUnwatch($title, $wgUser); } $dbw->commit($fname); }); } }
/** * 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); }
/** * Set a watch (or unwatch) based the based on a watchlist parameter. * @param $watch String Valid values: 'watch', 'unwatch', 'preferences', 'nochange' * @param $titleObj Title the article's title to change * @param $userOption String 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; } $user = $this->getUser(); if ($value) { WatchAction::doWatch($titleObj, $user); } else { WatchAction::doUnwatch($titleObj, $user); } }
private function watchTitle(Title $title, User $user, array $params, $compatibilityMode = false) { if (!$title->isWatchable()) { return array('title' => $title->getPrefixedText(), 'watchable' => 0); } $res = array('title' => $title->getPrefixedText()); if ($params['unwatch']) { $status = UnwatchAction::doUnwatch($title, $user); $res['unwatched'] = $status->isOK(); if ($status->isOK()) { $res['message'] = $this->msg('removedwatchtext', $title->getPrefixedText())->title($title)->parseAsBlock(); } } else { $status = WatchAction::doWatch($title, $user); $res['watched'] = $status->isOK(); if ($status->isOK()) { $res['message'] = $this->msg('addedwatchtext', $title->getPrefixedText())->title($title)->parseAsBlock(); } } if (!$status->isOK()) { if ($compatibilityMode) { $this->dieStatus($status); } $res['error'] = $this->getErrorFromStatus($status); } return $res; }
/** * Given the form data, actually implement a block. This is also called from ApiBlock. * * @param array $data * @param IContextSource $context * @return bool|string */ public static function processForm(array $data, IContextSource $context) { global $wgBlockAllowsUTEdit, $wgHideUserContribLimit, $wgContLang; $performer = $context->getUser(); // Handled by field validator callback // self::validateTargetField( $data['Target'] ); # This might have been a hidden field or a checkbox, so interesting data # can come from it $data['Confirm'] = !in_array($data['Confirm'], array('', '0', null, false), true); /** @var User $target */ list($target, $type) = self::getTargetAndType($data['Target']); if ($type == Block::TYPE_USER) { $user = $target; $target = $user->getName(); $userId = $user->getId(); # Give admins a heads-up before they go and block themselves. Much messier # to do this for IPs, but it's pretty unlikely they'd ever get the 'block' # permission anyway, although the code does allow for it. # Note: Important to use $target instead of $data['Target'] # since both $data['PreviousTarget'] and $target are normalized # but $data['target'] gets overridden by (non-normalized) request variable # from previous request. if ($target === $performer->getName() && ($data['PreviousTarget'] !== $target || !$data['Confirm'])) { return array('ipb-blockingself', 'ipb-confirmaction'); } } elseif ($type == Block::TYPE_RANGE) { $userId = 0; } elseif ($type == Block::TYPE_IP) { $target = $target->getName(); $userId = 0; } else { # This should have been caught in the form field validation return array('badipaddress'); } if (strlen($data['Expiry']) == 0 || strlen($data['Expiry']) > 50 || !self::parseExpiryInput($data['Expiry'])) { return array('ipb_expiry_invalid'); } if (!isset($data['DisableEmail'])) { $data['DisableEmail'] = false; } # If the user has done the form 'properly', they won't even have been given the # option to suppress-block unless they have the 'hideuser' permission if (!isset($data['HideUser'])) { $data['HideUser'] = false; } if ($data['HideUser']) { if (!$performer->isAllowed('hideuser')) { # this codepath is unreachable except by a malicious user spoofing forms, # or by race conditions (user has hideuser and block rights, loads block form, # and loses hideuser rights before submission); so need to fail completely # rather than just silently disable hiding return array('badaccess-group0'); } # Recheck params here... if ($type != Block::TYPE_USER) { $data['HideUser'] = false; # IP users should not be hidden } elseif (!wfIsInfinity($data['Expiry'])) { # Bad expiry. return array('ipb_expiry_temp'); } elseif ($wgHideUserContribLimit !== false && $user->getEditCount() > $wgHideUserContribLimit) { # Typically, the user should have a handful of edits. # Disallow hiding users with many edits for performance. return array(array('ipb_hide_invalid', Message::numParam($wgHideUserContribLimit))); } elseif (!$data['Confirm']) { return array('ipb-confirmhideuser', 'ipb-confirmaction'); } } # Create block object. $block = new Block(); $block->setTarget($target); $block->setBlocker($performer); # Truncate reason for whole multibyte characters $block->mReason = $wgContLang->truncate($data['Reason'][0], 255); $block->mExpiry = self::parseExpiryInput($data['Expiry']); $block->prevents('createaccount', $data['CreateAccount']); $block->prevents('editownusertalk', !$wgBlockAllowsUTEdit || $data['DisableUTEdit']); $block->prevents('sendemail', $data['DisableEmail']); $block->isHardblock($data['HardBlock']); $block->isAutoblocking($data['AutoBlock']); $block->mHideName = $data['HideUser']; $reason = array('hookaborted'); if (!Hooks::run('BlockIp', array(&$block, &$performer, &$reason))) { return $reason; } # Try to insert block. Is there a conflicting block? $status = $block->insert(); if (!$status) { # Indicates whether the user is confirming the block and is aware of # the conflict (did not change the block target in the meantime) $blockNotConfirmed = !$data['Confirm'] || array_key_exists('PreviousTarget', $data) && $data['PreviousTarget'] !== $target; # Special case for API - bug 32434 $reblockNotAllowed = array_key_exists('Reblock', $data) && !$data['Reblock']; # Show form unless the user is already aware of this... if ($blockNotConfirmed || $reblockNotAllowed) { return array(array('ipb_already_blocked', $block->getTarget())); # Otherwise, try to update the block... } else { # This returns direct blocks before autoblocks/rangeblocks, since we should # be sure the user is blocked by now it should work for our purposes $currentBlock = Block::newFromTarget($target); if ($block->equals($currentBlock)) { return array(array('ipb_already_blocked', $block->getTarget())); } # If the name was hidden and the blocking user cannot hide # names, then don't allow any block changes... if ($currentBlock->mHideName && !$performer->isAllowed('hideuser')) { return array('cant-see-hidden-user'); } $currentBlock->isHardblock($block->isHardblock()); $currentBlock->prevents('createaccount', $block->prevents('createaccount')); $currentBlock->mExpiry = $block->mExpiry; $currentBlock->isAutoblocking($block->isAutoblocking()); $currentBlock->mHideName = $block->mHideName; $currentBlock->prevents('sendemail', $block->prevents('sendemail')); $currentBlock->prevents('editownusertalk', $block->prevents('editownusertalk')); $currentBlock->mReason = $block->mReason; $status = $currentBlock->update(); $logaction = 'reblock'; # Unset _deleted fields if requested if ($currentBlock->mHideName && !$data['HideUser']) { RevisionDeleteUser::unsuppressUserName($target, $userId); } # If hiding/unhiding a name, this should go in the private logs if ((bool) $currentBlock->mHideName) { $data['HideUser'] = true; } } } else { $logaction = 'block'; } Hooks::run('BlockIpComplete', array($block, $performer)); # Set *_deleted fields if requested if ($data['HideUser']) { RevisionDeleteUser::suppressUserName($target, $userId); } # Can't watch a rangeblock if ($type != Block::TYPE_RANGE && $data['Watch']) { WatchAction::doWatch(Title::makeTitle(NS_USER, $target), $performer, WatchedItem::IGNORE_USER_RIGHTS); } # Block constructor sanitizes certain block options on insert $data['BlockEmail'] = $block->prevents('sendemail'); $data['AutoBlock'] = $block->isAutoblocking(); # Prepare log parameters $logParams = array(); $logParams['5::duration'] = $data['Expiry']; $logParams['6::flags'] = self::blockLogFlags($data, $type); # Make log entry, if the name is hidden, put it in the suppression log $log_type = $data['HideUser'] ? 'suppress' : 'block'; $logEntry = new ManualLogEntry($log_type, $logaction); $logEntry->setTarget(Title::makeTitle(NS_USER, $target)); $logEntry->setComment($data['Reason'][0]); $logEntry->setPerformer($performer); $logEntry->setParameters($logParams); # Relate log ID to block IDs (bug 25763) $blockIds = array_merge(array($status['id']), $status['autoIds']); $logEntry->setRelations(array('ipb_id' => $blockIds)); $logId = $logEntry->insert(); $logEntry->publish($logId); # Report to the user return true; }
/** * UserLoginComplete hook handler * @see https://www.mediawiki.org/wiki/Manual:Hooks/UserLoginComplete * * Used here to handle watchlist actions made by anons to be handled after * login or account creation. * * @param User $currentUser * @param string $injected_html * @return bool */ public static function onUserLoginComplete(&$currentUser, &$injected_html) { $context = MobileContext::singleton(); if (!$context->shouldDisplayMobileView()) { return true; } // If 'watch' is set from the login form, watch the requested article $watch = $context->getRequest()->getVal('watch'); if (!is_null($watch)) { $title = Title::newFromText($watch); // protect against watching special pages (these cannot be watched!) if (!is_null($title) && !$title->isSpecialPage()) { WatchAction::doWatch($title, $currentUser); } } return true; }
private function watchTitle(Title $title, User $user, array $params, $compatibilityMode = false) { if (!$title->isWatchable()) { return array('title' => $title->getPrefixedText(), 'watchable' => 0); } $res = array('title' => $title->getPrefixedText()); // Currently unnecessary, code to act as a safeguard against any change // in current behavior of uselang. // Copy from ApiParse $oldLang = null; if (isset($params['uselang']) && $params['uselang'] != $this->getContext()->getLanguage()->getCode()) { $oldLang = $this->getContext()->getLanguage(); // Backup language $this->getContext()->setLanguage(Language::factory($params['uselang'])); } if ($params['unwatch']) { $status = UnwatchAction::doUnwatch($title, $user); if ($status->isOK()) { $res['unwatched'] = ''; $res['message'] = $this->msg('removedwatchtext', $title->getPrefixedText())->title($title)->parseAsBlock(); } } else { $status = WatchAction::doWatch($title, $user); if ($status->isOK()) { $res['watched'] = ''; $res['message'] = $this->msg('addedwatchtext', $title->getPrefixedText())->title($title)->parseAsBlock(); } } if (!is_null($oldLang)) { $this->getContext()->setLanguage($oldLang); // Reset language to $oldLang } if (!$status->isOK()) { if ($compatibilityMode) { $this->dieStatus($status); } $res['error'] = $this->getErrorFromStatus($status); } return $res; }