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) { $this->dieUsageMsg(array('invalidtitle', $params['title'])); } $article = new Article($title); $res = array('title' => $title->getPrefixedText()); if ($params['unwatch']) { $res['unwatched'] = ''; $success = $article->doUnwatch(); } else { $res['watched'] = ''; $success = $article->doWatch(); } if (!$success) { $this->dieUsageMsg(array('hookaborted')); } $this->getResult()->addValue(null, $this->getModuleName(), $res); }
/** * Called for AJAX watch/unwatch requests. * @param $pagename Prefixed title string for page to watch/unwatch * @param $watch String 'w' to watch, 'u' to unwatch * @return String '<w#>' or '<u#>' on successful watch or unwatch, * respectively, followed by an HTML message to display in the alert box; or * '<err#>' on error */ function wfAjaxWatch($pagename = "", $watch = "") { if (wfReadOnly()) { // redirect to action=(un)watch, which will display the database lock // message return '<err#>'; } if ('w' !== $watch && 'u' !== $watch) { return '<err#>'; } $watch = 'w' === $watch; $title = Title::newFromDBkey($pagename); if (!$title) { // Invalid title return '<err#>'; } $article = new Article($title); $watching = $title->userIsWatching(); if ($watch) { if (!$watching) { $dbw = wfGetDB(DB_MASTER); $dbw->begin(); $ok = $article->doWatch(); $dbw->commit(); } } else { if ($watching) { $dbw = wfGetDB(DB_MASTER); $dbw->begin(); $ok = $article->doUnwatch(); $dbw->commit(); } } // Something stopped the change if (isset($ok) && !$ok) { return '<err#>'; } if ($watch) { return '<w#>' . wfMsgExt('addedwatchtext', array('parse'), $title->getPrefixedText()); } else { return '<u#>' . wfMsgExt('removedwatchtext', array('parse'), $title->getPrefixedText()); } }
/** * 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); $error = ''; $dbw = wfGetDB(DB_MASTER); try { if (wfRunHooks('ArticleDelete', array(&$article, &$wgUser, &$reason, &$error))) { // delete the associated article first if ($article->doDeleteArticle($reason, $suppress, $id, false)) { global $wgRequest; if ($wgRequest->getCheck('wpWatch') && $wgUser->isLoggedIn()) { $article->doWatch(); } elseif ($title->userIsWatching()) { $article->doUnwatch(); } $status = $file->delete($reason, $suppress); if ($status->ok) { $dbw->commit(); wfRunHooks('ArticleDeleteComplete', array(&$article, &$wgUser, $reason, $id)); } 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; }
public function execute() { global $wgUser, $wgRestrictionTypes, $wgRestrictionLevels; $params = $this->extractRequestParams(); $titleObj = NULL; if (!isset($params['title'])) { $this->dieUsageMsg(array('missingparam', 'title')); } if (!isset($params['token'])) { $this->dieUsageMsg(array('missingparam', 'token')); } if (empty($params['protections'])) { $this->dieUsageMsg(array('missingparam', 'protections')); } if (!$wgUser->matchEditToken($params['token'])) { $this->dieUsageMsg(array('sessionfailure')); } $titleObj = Title::newFromText($params['title']); if (!$titleObj) { $this->dieUsageMsg(array('invalidtitle', $params['title'])); } $errors = $titleObj->getUserPermissionsErrors('protect', $wgUser); if ($errors) { // We don't care about multiple errors, just report one of them $this->dieUsageMsg(reset($errors)); } $expiry = (array) $params['expiry']; if (count($expiry) != count($params['protections'])) { if (count($expiry) == 1) { $expiry = array_fill(0, count($params['protections']), $expiry[0]); } else { $this->dieUsageMsg(array('toofewexpiries', count($expiry), count($params['protections']))); } } $protections = array(); $expiryarray = array(); $resultProtections = array(); foreach ($params['protections'] as $i => $prot) { $p = explode('=', $prot); $protections[$p[0]] = $p[1] == 'all' ? '' : $p[1]; if ($titleObj->exists() && $p[0] == 'create') { $this->dieUsageMsg(array('create-titleexists')); } if (!$titleObj->exists() && $p[0] != 'create') { $this->dieUsageMsg(array('missingtitles-createonly')); } if (!in_array($p[0], $wgRestrictionTypes) && $p[0] != 'create') { $this->dieUsageMsg(array('protect-invalidaction', $p[0])); } if (!in_array($p[1], $wgRestrictionLevels) && $p[1] != 'all') { $this->dieUsageMsg(array('protect-invalidlevel', $p[1])); } if (in_array($expiry[$i], array('infinite', 'indefinite', 'never'))) { $expiryarray[$p[0]] = Block::infinity(); } else { $exp = strtotime($expiry[$i]); if ($exp < 0 || $exp == false) { $this->dieUsageMsg(array('invalidexpiry', $expiry[$i])); } $exp = wfTimestamp(TS_MW, $exp); if ($exp < wfTimestampNow()) { $this->dieUsageMsg(array('pastexpiry', $expiry[$i])); } $expiryarray[$p[0]] = $exp; } $resultProtections[] = array($p[0] => $protections[$p[0]], 'expiry' => $expiryarray[$p[0]] == Block::infinity() ? 'infinite' : wfTimestamp(TS_ISO_8601, $expiryarray[$p[0]])); } $cascade = $params['cascade']; $articleObj = new Article($titleObj); if ($params['watch']) { $articleObj->doWatch(); } if ($titleObj->exists()) { $ok = $articleObj->updateRestrictions($protections, $params['reason'], $cascade, $expiryarray); } else { $ok = $titleObj->updateTitleProtection($protections['create'], $params['reason'], $expiryarray['create']); } if (!$ok) { // This is very weird. Maybe the article was deleted or the user was blocked/desysopped in the meantime? // Just throw an unknown error in this case, as it's very likely to be a race condition $this->dieUsageMsg(array()); } $res = array('title' => $titleObj->getPrefixedText(), 'reason' => $params['reason']); if ($cascade) { $res['cascade'] = ''; } $res['protections'] = $resultProtections; $this->getResult()->setIndexedTagName($res['protections'], 'protection'); $this->getResult()->addValue(null, $this->getModuleName(), $res); }
public static function doDelete(&$title, &$file, &$oldimage, $reason, $suppress) { $article = null; 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 .= ": {$reason}"; } $log->addEntry('delete', $title, $logComment); } } else { $status = $file->delete($reason, $suppress); if ($status->ok) { $id = $title->getArticleID(GAID_FOR_UPDATE); // Need to delete the associated article $article = new Article($title); if (wfRunHooks('ArticleDelete', array(&$article, &$wgUser, &$reason))) { if ($article->doDeleteArticle($reason, $suppress, $id)) { global $wgRequest; if ($wgRequest->getCheck('wpWatch')) { $article->doWatch(); } elseif ($title->userIsWatching()) { $article->doUnwatch(); } wfRunHooks('ArticleDeleteComplete', array(&$article, &$wgUser, $reason, $id)); } } } } if ($status->isGood()) { wfRunHooks('FileDeleteComplete', array(&$file, &$oldimage, &$article, &$wgUser, &$reason)); } return $status; }
/** * Run a replaceText job * @return boolean success */ function run() { wfProfileIn( __METHOD__ ); if ( is_null( $this->title ) ) { $this->error = "replaceText: Invalid title"; wfProfileOut( __METHOD__ ); return false; } if ( array_key_exists( 'move_page', $this->params ) ) { global $wgUser; $actual_user = $wgUser; $wgUser = User::newFromId( $this->params['user_id'] ); $cur_page_name = $this->title->getText(); if ( $this->params['use_regex'] ) { $new_page_name = preg_replace( "/".$this->params['target_str']."/U", $this->params['replacement_str'], $cur_page_name ); } else { $new_page_name = str_replace( $this->params['target_str'], $this->params['replacement_str'], $cur_page_name ); } $new_title = Title::newFromText( $new_page_name, $this->title->getNamespace() ); $reason = $this->params['edit_summary']; $create_redirect = $this->params['create_redirect']; $this->title->moveTo( $new_title, true, $reason, $create_redirect ); if ( $this->params['watch_page'] ) { if ( class_exists( 'WatchAction' ) ) { // Class was added in MW 1.19 WatchAction::doWatch( $new_title, $wgUser ); } elseif ( class_exists( 'Action' ) ) { // Class was added in MW 1.18 Action::factory( 'watch', new Article( $new_title, 0 ) )->execute(); } else { $article = new Article( $new_title, 0 ); $article->doWatch(); } } $wgUser = $actual_user; } else { $article = new Article( $this->title, 0 ); if ( !$article ) { $this->error = 'replaceText: Article not found "' . $this->title->getPrefixedDBkey() . '"'; wfProfileOut( __METHOD__ ); return false; } wfProfileIn( __METHOD__ . '-replace' ); $article_text = $article->fetchContent(); $target_str = $this->params['target_str']; $replacement_str = $this->params['replacement_str']; $num_matches; if ( $this->params['use_regex'] ) { $new_text = preg_replace( '/'.$target_str.'/U', $replacement_str, $article_text, -1, $num_matches ); } else { $new_text = str_replace( $target_str, $replacement_str, $article_text, $num_matches ); } // if there's at least one replacement, modify the page, // using the passed-in edit summary if ( $num_matches > 0 ) { // change global $wgUser variable to the one // specified by the job only for the extent of // this replacement global $wgUser; $actual_user = $wgUser; $wgUser = User::newFromId( $this->params['user_id'] ); $edit_summary = $this->params['edit_summary']; $flags = EDIT_MINOR; if ( $wgUser->isAllowed( 'bot' ) ) $flags |= EDIT_FORCE_BOT; $article->doEdit( $new_text, $edit_summary, $flags ); $wgUser = $actual_user; } wfProfileOut( __METHOD__ . '-replace' ); } wfProfileOut( __METHOD__ ); return true; }
/** * This is the meaty bit -- restores archived revisions of the given page * to the cur/old tables. If the page currently exists, all revisions will * be stuffed into old, otherwise the most recent will go into cur. * * @param array $timestamps Pass an empty array to restore all revisions, otherwise list the ones to undelete. * @param string $comment * @param array $fileVersions * * @return int number of revisions restored */ private function undeleteRevisions($timestamps) { global $wgParser, $wgDBtype; $fname = __CLASS__ . '::' . __FUNCTION__; $restoreAll = empty($timestamps); $dbw =& wfGetDB(DB_MASTER); extract($dbw->tableNames('page', 'archive')); # Does this page already exist? We'll have to update it... $article = new Article($this->title); $options = $wgDBtype == 'postgres' ? '' : 'FOR UPDATE'; $page = $dbw->selectRow('page', array('page_id', 'page_latest'), array('page_namespace' => $this->title->getNamespace(), 'page_title' => $this->title->getDBkey()), $fname, $options); if ($page) { # Page already exists. Import the history, and if necessary # we'll update the latest revision field in the record. $newid = 0; $pageId = $page->page_id; $previousRevId = $page->page_latest; } else { # Have to create a new article... $newid = $article->insertOn($dbw); $pageId = $newid; $previousRevId = 0; } if ($restoreAll) { $oldones = '1 = 1'; # All revisions... } else { $oldts = implode(',', array_map(array(&$dbw, 'addQuotes'), array_map(array(&$dbw, 'timestamp'), $timestamps))); $oldones = "ar_timestamp IN ( {$oldts} )"; } /** * Restore each revision... */ $result = $dbw->select('archive', array('ar_rev_id', 'ar_text', 'ar_comment', 'ar_user', 'ar_user_text', 'ar_timestamp', 'ar_minor_edit', 'ar_flags', 'ar_text_id'), array('ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), $oldones), $fname, array('ORDER BY' => 'ar_timestamp')); if ($dbw->numRows($result) < count($timestamps)) { wfDebug("{$fname}: couldn't find all requested rows\n"); return false; } $revision = null; $newRevId = $previousRevId; $restored = 0; while ($row = $dbw->fetchObject($result)) { if ($row->ar_text_id) { // Revision was deleted in 1.5+; text is in // the regular text table, use the reference. // Specify null here so the so the text is // dereferenced for page length info if needed. $revText = null; } else { // Revision was deleted in 1.4 or earlier. // Text is squashed into the archive row, and // a new text table entry will be created for it. $revText = Revision::getRevisionText($row, 'ar_'); } $revision = new Revision(array('page' => $pageId, 'id' => $row->ar_rev_id, 'text' => $revText, 'comment' => $row->ar_comment, 'user' => $row->ar_user, 'user_text' => $row->ar_user_text, 'timestamp' => $row->ar_timestamp, 'minor_edit' => $row->ar_minor_edit, 'text_id' => $row->ar_text_id)); $newRevId = $revision->insertOn($dbw); $restored++; } if ($revision) { # FIXME: Update latest if newer as well... if ($newid) { # FIXME: update article count if changed... $article->updateRevisionOn($dbw, $revision, $previousRevId); # Finally, clean up the link tables $options = new ParserOptions(); $parserOutput = $wgParser->parse($revision->getText(), $this->title, $options, true, true, $newRevId); $u = new LinksUpdate($this->title, $parserOutput); $u->doUpdate(); #TODO: SearchUpdate, etc. } // WERELATE: watch article global $wgUser; $watchthis = false; if ($newid) { Article::onArticleCreate($this->title); $watchthis = $wgUser->getOption('watchcreations') || $wgUser->getOption('watchdefault'); } else { Article::onArticleEdit($this->title); $watchthis = $wgUser->getOption('watchdefault'); } if ($watchthis && !$article->getTitle()->userIsWatching()) { $article->doWatch(); } } else { # Something went terribly wrong! } # Now that it's safely stored, take it out of the archive $dbw->delete('archive', array('ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), $oldones), $fname); return $restored; }
/** * Called for AJAX watch/unwatch requests. * @param $pageID Integer ID of the page to be watched/unwatched * @param $watch String 'w' to watch, 'u' to unwatch * @return String '<w#>' or '<u#>' on successful watch or unwatch, respectively, or '<err#>' on error (invalid XML in case we want to add HTML sometime) */ function wfAjaxWatch($pageID = "", $watch = "") { if (wfReadOnly()) { return '<err#>'; } // redirect to action=(un)watch, which will display the database lock message if ('w' !== $watch && 'u' !== $watch || !is_numeric($pageID)) { return '<err#>'; } $watch = 'w' === $watch; $pageID = intval($pageID); $title = Title::newFromID($pageID); if (!$title) { return '<err#>'; } $article = new Article($title); $watching = $title->userIsWatching(); if ($watch) { if (!$watching) { $dbw =& wfGetDB(DB_MASTER); $dbw->begin(); $article->doWatch(); $dbw->commit(); } } else { if ($watching) { $dbw =& wfGetDB(DB_MASTER); $dbw->begin(); $article->doUnwatch(); $dbw->commit(); } } return $watch ? '<w#>' : '<u#>'; }
/** * 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; } $articleObj = new Article($titleObj); if ($value) { $articleObj->doWatch(); } else { $articleObj->doUnwatch(); } }