function tagProxyChange($recentChange)
 {
     global $wgTagProxyActions, $wgUser;
     if ($wgTagProxyActions && self::isProxy(wfGetIP()) && !$wgUser->isAllowed('notagproxychanges')) {
         ChangeTags::addTags('proxy', $recentChange->mAttribs['rc_id'], $recentChange->mAttribs['rc_this_oldid'], $recentChange->mAttribs['rc_logid']);
     }
     return true;
 }
 public function execute()
 {
     global $wgVisualEditorNamespaces, $wgVisualEditorUseChangeTagging;
     $user = $this->getUser();
     $params = $this->extractRequestParams();
     $page = Title::newFromText($params['page']);
     if (!$page) {
         $this->dieUsageMsg('invalidtitle', $params['page']);
     }
     if (!in_array($page->getNamespace(), $wgVisualEditorNamespaces)) {
         $this->dieUsage("VisualEditor is not enabled in namespace " . $page->getNamespace(), 'novenamespace');
     }
     $parserParams = array();
     if (isset($params['oldwt'])) {
         $parserParams['oldwt'] = $params['oldwt'];
     } else {
         if (isset($params['oldid'])) {
             $parserParams['oldid'] = $params['oldid'];
         }
     }
     if ($params['cachekey'] !== null) {
         $wikitext = $this->trySerializationCache($params['cachekey']);
         if (!is_string($wikitext)) {
             $this->dieUsage('No cached serialization found with that key', 'badcachekey');
         }
     } else {
         $wikitext = $this->postHTML($page, $params['html'], $parserParams);
         if ($wikitext === false) {
             $this->dieUsage('Error contacting the Parsoid server', 'parsoidserver');
         }
     }
     $saveresult = $this->saveWikitext($page, $wikitext, $params);
     $editStatus = $saveresult['edit']['result'];
     // Error
     if ($editStatus !== 'Success') {
         $result = array('result' => 'error', 'edit' => $saveresult['edit']);
         // Success
     } else {
         if (isset($saveresult['edit']['newrevid']) && $wgVisualEditorUseChangeTagging) {
             ChangeTags::addTags('visualeditor', null, intval($saveresult['edit']['newrevid']), null);
             if ($params['needcheck']) {
                 ChangeTags::addTags('visualeditor-needcheck', null, intval($saveresult['edit']['newrevid']), null);
             }
         }
         // Return result of parseWikitext instead of saveWikitext so that the
         // frontend can update the page rendering without a refresh.
         $result = $this->parseWikitext($page, $params['useskin']);
         if ($result === false) {
             $this->dieUsage('Error contacting the Parsoid server', 'parsoidserver');
         }
         $result['isRedirect'] = $page->isRedirect();
         if (isset($saveresult['edit']['newrevid'])) {
             $result['newrevid'] = intval($saveresult['edit']['newrevid']);
         }
         $result['result'] = 'success';
     }
     $this->getResult()->addValue(null, $this->getModuleName(), $result);
 }
 /**
  * @desc Mark all edits made via mobile skin with a mobileedit tag
  *
  * @param $article
  * @param $user
  * @param $text
  * @param $summary
  * @param $minoredit
  * @param $watchthis
  * @param $sectionanchor
  * @param $flags
  * @param $revision Revision
  * @param $status
  * @param $baseRevId
  */
 public static function onArticleSaveComplete(&$article, &$user, $text, $summary, $minoredit, $watchthis, $sectionanchor, &$flags, $revision, &$status, $baseRevId)
 {
     $app = F::app();
     //Add Mobile Edit tag when an article was saved via mobile skin
     if ($app->checkSkin('wikiamobile') && !is_null($revision)) {
         ChangeTags::addTags('mobileedit', null, $revision->getId(), null);
     }
     return true;
 }
 protected function addTags($items, $dry)
 {
     $count = count($items);
     if (!$count) {
         $this->output("No revisions to tag\n");
         return;
     }
     if ($dry) {
         $this->output("{$count} revisions would be tagged\n");
         return;
     }
     $this->output("{$count} rows are tagged\n");
     foreach ($items as $item) {
         list($row, $revId) = $item;
         ChangeTags::addTags('contenttranslation', null, $revId, null, FormatJson::encode(array('from' => $row->translation_source_language, 'to' => $row->translation_target_language)));
     }
 }
Example #5
0
 public function execute()
 {
     $this->useTransactionalTimeLimit();
     $user = $this->getUser();
     $params = $this->extractRequestParams();
     // WikiPage::doRollback needs a Web UI token, so get one of those if we
     // validated based on an API rollback token.
     $token = $params['token'];
     if ($user->matchEditToken($token, 'rollback', $this->getRequest())) {
         $token = $this->getUser()->getEditToken($this->getWebUITokenSalt($params), $this->getRequest());
     }
     $titleObj = $this->getRbTitle($params);
     $pageObj = WikiPage::factory($titleObj);
     $summary = $params['summary'];
     $details = array();
     // If change tagging was requested, check that the user is allowed to tag,
     // and the tags are valid
     if (count($params['tags'])) {
         $tagStatus = ChangeTags::canAddTagsAccompanyingChange($params['tags'], $user);
         if (!$tagStatus->isOK()) {
             $this->dieStatus($tagStatus);
         }
     }
     $retval = $pageObj->doRollback($this->getRbUser($params), $summary, $token, $params['markbot'], $details, $user);
     if ($retval) {
         // We don't care about multiple errors, just report one of them
         $this->dieUsageMsg(reset($retval));
     }
     $watch = 'preferences';
     if (isset($params['watchlist'])) {
         $watch = $params['watchlist'];
     }
     // Watch pages
     $this->setWatch($watch, $titleObj, 'watchrollback');
     if (count($params['tags'])) {
         ChangeTags::addTags($params['tags'], null, intval($details['newid']), null, null);
     }
     $info = array('title' => $titleObj->getPrefixedText(), 'pageid' => intval($details['current']->getPage()), 'summary' => $details['summary'], 'revid' => intval($details['newid']), 'old_revid' => intval($details['current']->getID()), 'last_revid' => intval($details['target']->getID()));
     $this->getResult()->addValue(null, $this->getModuleName(), $info);
 }
 public function execute()
 {
     $user = $this->getUser();
     $params = $this->extractRequestParams();
     $page = Title::newFromText($params['page']);
     if (!$page) {
         $this->dieUsageMsg('invalidtitle', $params['page']);
     }
     $availableNamespaces = $this->veConfig->get('VisualEditorAvailableNamespaces');
     if (!isset($availableNamespaces[$page->getNamespace()]) || !$availableNamespaces[$page->getNamespace()]) {
         $this->dieUsage("VisualEditor is not enabled in namespace " . $page->getNamespace(), 'novenamespace');
     }
     $parserParams = array();
     if (isset($params['oldid'])) {
         $parserParams['oldid'] = $params['oldid'];
     }
     $html = $params['html'];
     if (substr($html, 0, 11) === 'rawdeflate,') {
         $html = gzinflate(base64_decode(substr($html, 11)));
     }
     if ($params['cachekey'] !== null) {
         $wikitext = $this->trySerializationCache($params['cachekey']);
         if (!is_string($wikitext)) {
             $this->dieUsage('No cached serialization found with that key', 'badcachekey');
         }
     } else {
         $wikitext = $this->postHTML($page, $html, $parserParams, $params['etag']);
         if ($wikitext === false) {
             $this->dieUsage('Error contacting the Parsoid/RESTbase server', 'docserver');
         }
     }
     $saveresult = $this->saveWikitext($page, $wikitext, $params);
     $editStatus = $saveresult['edit']['result'];
     // Error
     if ($editStatus !== 'Success') {
         $result = array('result' => 'error', 'edit' => $saveresult['edit']);
         if (isset($saveresult['edit']['spamblacklist'])) {
             $matches = explode('|', $saveresult['edit']['spamblacklist']);
             $matcheslist = $this->getLanguage()->listToText($matches);
             $result['edit']['sberrorparsed'] = $this->msg('spamprotectiontext')->parse() . ' ' . $this->msg('spamprotectionmatch', $matcheslist)->parse();
         }
         // Success
     } else {
         if (isset($saveresult['edit']['newrevid'])) {
             $newRevId = intval($saveresult['edit']['newrevid']);
             if ($this->veConfig->get('VisualEditorUseChangeTagging')) {
                 // Defer till after the RC row is inserted
                 // @TODO: doEditContent should let callers specify desired tags
                 DeferredUpdates::addCallableUpdate(function () use($newRevId) {
                     ChangeTags::addTags('visualeditor', null, $newRevId, null);
                 });
             }
         } else {
             $newRevId = $page->getLatestRevId();
         }
         // Return result of parseWikitext instead of saveWikitext so that the
         // frontend can update the page rendering without a refresh.
         $result = $this->parseWikitext($page, $newRevId);
         if ($result === false) {
             $this->dieUsage('Error contacting the Parsoid/RESTBase server', 'docserver');
         }
         $result['isRedirect'] = $page->isRedirect();
         if (class_exists('FlaggablePageView')) {
             $view = FlaggablePageView::singleton();
             // Defeat !$this->isPageView( $request ) || $request->getVal( 'oldid' ) check in setPageContent
             $view->getContext()->setRequest(new DerivativeRequest($this->getRequest(), array('diff' => null, 'oldid' => '', 'action' => 'view') + $this->getRequest()->getValues()));
             // The two parameters here are references but we don't care
             // about what FlaggedRevs does with them.
             $outputDone = null;
             $useParserCache = null;
             $view->setPageContent($outputDone, $useParserCache);
             $view->displayTag();
         }
         $result['contentSub'] = $this->getOutput()->getSubtitle();
         $lang = $this->getLanguage();
         if (isset($saveresult['edit']['newtimestamp'])) {
             $ts = $saveresult['edit']['newtimestamp'];
             $result['lastModified'] = array('date' => $lang->userDate($ts, $user), 'time' => $lang->userTime($ts, $user));
         }
         if (isset($saveresult['edit']['newrevid'])) {
             $result['newrevid'] = intval($saveresult['edit']['newrevid']);
         }
         $result['result'] = 'success';
     }
     $this->getResult()->addValue(null, $this->getModuleName(), $result);
 }
Example #7
0
 /**
  * Makes an entry in the database corresponding to page creation
  * Note: the title object must be loaded with the new id using resetArticleID()
  *
  * @param string $timestamp
  * @param Title $title
  * @param bool $minor
  * @param User $user
  * @param string $comment
  * @param bool $bot
  * @param string $ip
  * @param int $size
  * @param int $newId
  * @param int $patrol
  * @param array $tags
  * @return RecentChange
  */
 public static function notifyNew($timestamp, &$title, $minor, &$user, $comment, $bot, $ip = '', $size = 0, $newId = 0, $patrol = 0, $tags = array())
 {
     $rc = new RecentChange();
     $rc->mTitle = $title;
     $rc->mPerformer = $user;
     $rc->mAttribs = array('rc_timestamp' => $timestamp, 'rc_namespace' => $title->getNamespace(), 'rc_title' => $title->getDBkey(), 'rc_type' => RC_NEW, 'rc_source' => self::SRC_NEW, 'rc_minor' => $minor ? 1 : 0, 'rc_cur_id' => $title->getArticleID(), 'rc_user' => $user->getId(), 'rc_user_text' => $user->getName(), 'rc_comment' => $comment, 'rc_this_oldid' => $newId, 'rc_last_oldid' => 0, 'rc_bot' => $bot ? 1 : 0, 'rc_ip' => self::checkIPAddress($ip), 'rc_patrolled' => intval($patrol), 'rc_new' => 1, 'rc_old_len' => 0, 'rc_new_len' => $size, 'rc_deleted' => 0, 'rc_logid' => 0, 'rc_log_type' => null, 'rc_log_action' => '', 'rc_params' => '');
     $rc->mExtra = array('prefixedDBkey' => $title->getPrefixedDBkey(), 'lastTimestamp' => 0, 'oldSize' => 0, 'newSize' => $size, 'pageStatus' => 'created');
     DeferredUpdates::addCallableUpdate(function () use($rc, $tags) {
         $rc->save();
         if ($rc->mAttribs['rc_patrolled']) {
             PatrolLog::record($rc, true, $rc->getPerformer());
         }
         if (count($tags)) {
             ChangeTags::addTags($tags, $rc->mAttribs['rc_id'], $rc->mAttribs['rc_this_oldid'], null, null);
         }
     });
     return $rc;
 }
 /**
  * Attempt submission (no UI)
  *
  * @param array $result Array to add statuses to, currently with the
  *   possible keys:
  *   - spam (string): Spam string from content if any spam is detected by
  *     matchSpamRegex.
  *   - sectionanchor (string): Section anchor for a section save.
  *   - nullEdit (boolean): Set if doEditContent is OK.  True if null edit,
  *     false otherwise.
  *   - redirect (bool): Set if doEditContent is OK. True if resulting
  *     revision is a redirect.
  * @param bool $bot True if edit is being made under the bot right.
  *
  * @return Status Status object, possibly with a message, but always with
  *   one of the AS_* constants in $status->value,
  *
  * @todo FIXME: This interface is TERRIBLE, but hard to get rid of due to
  *   various error display idiosyncrasies. There are also lots of cases
  *   where error metadata is set in the object and retrieved later instead
  *   of being returned, e.g. AS_CONTENT_TOO_BIG and
  *   AS_BLOCKED_PAGE_FOR_USER. All that stuff needs to be cleaned up some
  * time.
  */
 function internalAttemptSave(&$result, $bot = false)
 {
     global $wgUser, $wgRequest, $wgParser, $wgMaxArticleSize;
     global $wgContentHandlerUseDB;
     $status = Status::newGood();
     if (!Hooks::run('EditPage::attemptSave', array($this))) {
         wfDebug("Hook 'EditPage::attemptSave' aborted article saving\n");
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR;
         return $status;
     }
     $spam = $wgRequest->getText('wpAntispam');
     if ($spam !== '') {
         wfDebugLog('SimpleAntiSpam', $wgUser->getName() . ' editing "' . $this->mTitle->getPrefixedText() . '" submitted bogus field "' . $spam . '"');
         $status->fatal('spamprotectionmatch', false);
         $status->value = self::AS_SPAM_ERROR;
         return $status;
     }
     try {
         # Construct Content object
         $textbox_content = $this->toEditContent($this->textbox1);
     } catch (MWContentSerializationException $ex) {
         $status->fatal('content-failed-to-parse', $this->contentModel, $this->contentFormat, $ex->getMessage());
         $status->value = self::AS_PARSE_ERROR;
         return $status;
     }
     # Check image redirect
     if ($this->mTitle->getNamespace() == NS_FILE && $textbox_content->isRedirect() && !$wgUser->isAllowed('upload')) {
         $code = $wgUser->isAnon() ? self::AS_IMAGE_REDIRECT_ANON : self::AS_IMAGE_REDIRECT_LOGGED;
         $status->setResult(false, $code);
         return $status;
     }
     # Check for spam
     $match = self::matchSummarySpamRegex($this->summary);
     if ($match === false && $this->section == 'new') {
         # $wgSpamRegex is enforced on this new heading/summary because, unlike
         # regular summaries, it is added to the actual wikitext.
         if ($this->sectiontitle !== '') {
             # This branch is taken when the API is used with the 'sectiontitle' parameter.
             $match = self::matchSpamRegex($this->sectiontitle);
         } else {
             # This branch is taken when the "Add Topic" user interface is used, or the API
             # is used with the 'summary' parameter.
             $match = self::matchSpamRegex($this->summary);
         }
     }
     if ($match === false) {
         $match = self::matchSpamRegex($this->textbox1);
     }
     if ($match !== false) {
         $result['spam'] = $match;
         $ip = $wgRequest->getIP();
         $pdbk = $this->mTitle->getPrefixedDBkey();
         $match = str_replace("\n", '', $match);
         wfDebugLog('SpamRegex', "{$ip} spam regex hit [[{$pdbk}]]: \"{$match}\"");
         $status->fatal('spamprotectionmatch', $match);
         $status->value = self::AS_SPAM_ERROR;
         return $status;
     }
     if (!Hooks::run('EditFilter', array($this, $this->textbox1, $this->section, &$this->hookError, $this->summary))) {
         # Error messages etc. could be handled within the hook...
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR;
         return $status;
     } elseif ($this->hookError != '') {
         # ...or the hook could be expecting us to produce an error
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR_EXPECTED;
         return $status;
     }
     if ($wgUser->isBlockedFrom($this->mTitle, false)) {
         // Auto-block user's IP if the account was "hard" blocked
         $wgUser->spreadAnyEditBlock();
         # Check block state against master, thus 'false'.
         $status->setResult(false, self::AS_BLOCKED_PAGE_FOR_USER);
         return $status;
     }
     $this->kblength = (int) (strlen($this->textbox1) / 1024);
     if ($this->kblength > $wgMaxArticleSize) {
         // Error will be displayed by showEditForm()
         $this->tooBig = true;
         $status->setResult(false, self::AS_CONTENT_TOO_BIG);
         return $status;
     }
     if (!$wgUser->isAllowed('edit')) {
         if ($wgUser->isAnon()) {
             $status->setResult(false, self::AS_READ_ONLY_PAGE_ANON);
             return $status;
         } else {
             $status->fatal('readonlytext');
             $status->value = self::AS_READ_ONLY_PAGE_LOGGED;
             return $status;
         }
     }
     $changingContentModel = false;
     if ($this->contentModel !== $this->mTitle->getContentModel()) {
         if (!$wgContentHandlerUseDB) {
             $status->fatal('editpage-cannot-use-custom-model');
             $status->value = self::AS_CANNOT_USE_CUSTOM_MODEL;
             return $status;
         } elseif (!$wgUser->isAllowed('editcontentmodel')) {
             $status->setResult(false, self::AS_NO_CHANGE_CONTENT_MODEL);
             return $status;
         }
         $changingContentModel = true;
         $oldContentModel = $this->mTitle->getContentModel();
     }
     if ($this->changeTags) {
         $changeTagsStatus = ChangeTags::canAddTagsAccompanyingChange($this->changeTags, $wgUser);
         if (!$changeTagsStatus->isOK()) {
             $changeTagsStatus->value = self::AS_CHANGE_TAG_ERROR;
             return $changeTagsStatus;
         }
     }
     if (wfReadOnly()) {
         $status->fatal('readonlytext');
         $status->value = self::AS_READ_ONLY_PAGE;
         return $status;
     }
     if ($wgUser->pingLimiter() || $wgUser->pingLimiter('linkpurge', 0)) {
         $status->fatal('actionthrottledtext');
         $status->value = self::AS_RATE_LIMITED;
         return $status;
     }
     # If the article has been deleted while editing, don't save it without
     # confirmation
     if ($this->wasDeletedSinceLastEdit() && !$this->recreate) {
         $status->setResult(false, self::AS_ARTICLE_WAS_DELETED);
         return $status;
     }
     # Load the page data from the master. If anything changes in the meantime,
     # we detect it by using page_latest like a token in a 1 try compare-and-swap.
     $this->mArticle->loadPageData('fromdbmaster');
     $new = !$this->mArticle->exists();
     if ($new) {
         // Late check for create permission, just in case *PARANOIA*
         if (!$this->mTitle->userCan('create', $wgUser)) {
             $status->fatal('nocreatetext');
             $status->value = self::AS_NO_CREATE_PERMISSION;
             wfDebug(__METHOD__ . ": no create permission\n");
             return $status;
         }
         // Don't save a new page if it's blank or if it's a MediaWiki:
         // message with content equivalent to default (allow empty pages
         // in this case to disable messages, see bug 50124)
         $defaultMessageText = $this->mTitle->getDefaultMessageText();
         if ($this->mTitle->getNamespace() === NS_MEDIAWIKI && $defaultMessageText !== false) {
             $defaultText = $defaultMessageText;
         } else {
             $defaultText = '';
         }
         if (!$this->allowBlankArticle && $this->textbox1 === $defaultText) {
             $this->blankArticle = true;
             $status->fatal('blankarticle');
             $status->setResult(false, self::AS_BLANK_ARTICLE);
             return $status;
         }
         if (!$this->runPostMergeFilters($textbox_content, $status, $wgUser)) {
             return $status;
         }
         $content = $textbox_content;
         $result['sectionanchor'] = '';
         if ($this->section == 'new') {
             if ($this->sectiontitle !== '') {
                 // Insert the section title above the content.
                 $content = $content->addSectionHeader($this->sectiontitle);
             } elseif ($this->summary !== '') {
                 // Insert the section title above the content.
                 $content = $content->addSectionHeader($this->summary);
             }
             $this->summary = $this->newSectionSummary($result['sectionanchor']);
         }
         $status->value = self::AS_SUCCESS_NEW_ARTICLE;
     } else {
         # not $new
         # Article exists. Check for edit conflict.
         $this->mArticle->clear();
         # Force reload of dates, etc.
         $timestamp = $this->mArticle->getTimestamp();
         wfDebug("timestamp: {$timestamp}, edittime: {$this->edittime}\n");
         if ($timestamp != $this->edittime) {
             $this->isConflict = true;
             if ($this->section == 'new') {
                 if ($this->mArticle->getUserText() == $wgUser->getName() && $this->mArticle->getComment() == $this->newSectionSummary()) {
                     // Probably a duplicate submission of a new comment.
                     // This can happen when squid resends a request after
                     // a timeout but the first one actually went through.
                     wfDebug(__METHOD__ . ": duplicate new section submission; trigger edit conflict!\n");
                 } else {
                     // New comment; suppress conflict.
                     $this->isConflict = false;
                     wfDebug(__METHOD__ . ": conflict suppressed; new section\n");
                 }
             } elseif ($this->section == '' && Revision::userWasLastToEdit(DB_MASTER, $this->mTitle->getArticleID(), $wgUser->getId(), $this->edittime)) {
                 # Suppress edit conflict with self, except for section edits where merging is required.
                 wfDebug(__METHOD__ . ": Suppressing edit conflict, same user.\n");
                 $this->isConflict = false;
             }
         }
         // If sectiontitle is set, use it, otherwise use the summary as the section title.
         if ($this->sectiontitle !== '') {
             $sectionTitle = $this->sectiontitle;
         } else {
             $sectionTitle = $this->summary;
         }
         $content = null;
         if ($this->isConflict) {
             wfDebug(__METHOD__ . ": conflict! getting section '{$this->section}' for time '{$this->edittime}'" . " (article time '{$timestamp}')\n");
             $content = $this->mArticle->replaceSectionContent($this->section, $textbox_content, $sectionTitle, $this->edittime);
         } else {
             wfDebug(__METHOD__ . ": getting section '{$this->section}'\n");
             $content = $this->mArticle->replaceSectionContent($this->section, $textbox_content, $sectionTitle);
         }
         if (is_null($content)) {
             wfDebug(__METHOD__ . ": activating conflict; section replace failed.\n");
             $this->isConflict = true;
             $content = $textbox_content;
             // do not try to merge here!
         } elseif ($this->isConflict) {
             # Attempt merge
             if ($this->mergeChangesIntoContent($content)) {
                 // Successful merge! Maybe we should tell the user the good news?
                 $this->isConflict = false;
                 wfDebug(__METHOD__ . ": Suppressing edit conflict, successful merge.\n");
             } else {
                 $this->section = '';
                 $this->textbox1 = ContentHandler::getContentText($content);
                 wfDebug(__METHOD__ . ": Keeping edit conflict, failed merge.\n");
             }
         }
         if ($this->isConflict) {
             $status->setResult(false, self::AS_CONFLICT_DETECTED);
             return $status;
         }
         if (!$this->runPostMergeFilters($content, $status, $wgUser)) {
             return $status;
         }
         if ($this->section == 'new') {
             // Handle the user preference to force summaries here
             if (!$this->allowBlankSummary && trim($this->summary) == '') {
                 $this->missingSummary = true;
                 $status->fatal('missingsummary');
                 // or 'missingcommentheader' if $section == 'new'. Blegh
                 $status->value = self::AS_SUMMARY_NEEDED;
                 return $status;
             }
             // Do not allow the user to post an empty comment
             if ($this->textbox1 == '') {
                 $this->missingComment = true;
                 $status->fatal('missingcommenttext');
                 $status->value = self::AS_TEXTBOX_EMPTY;
                 return $status;
             }
         } elseif (!$this->allowBlankSummary && !$content->equals($this->getOriginalContent($wgUser)) && !$content->isRedirect() && md5($this->summary) == $this->autoSumm) {
             $this->missingSummary = true;
             $status->fatal('missingsummary');
             $status->value = self::AS_SUMMARY_NEEDED;
             return $status;
         }
         # All's well
         $sectionanchor = '';
         if ($this->section == 'new') {
             $this->summary = $this->newSectionSummary($sectionanchor);
         } elseif ($this->section != '') {
             # Try to get a section anchor from the section source, redirect
             # to edited section if header found.
             # XXX: Might be better to integrate this into Article::replaceSection
             # for duplicate heading checking and maybe parsing.
             $hasmatch = preg_match("/^ *([=]{1,6})(.*?)(\\1) *\\n/i", $this->textbox1, $matches);
             # We can't deal with anchors, includes, html etc in the header for now,
             # headline would need to be parsed to improve this.
             if ($hasmatch && strlen($matches[2]) > 0) {
                 $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText($matches[2]);
             }
         }
         $result['sectionanchor'] = $sectionanchor;
         // Save errors may fall down to the edit form, but we've now
         // merged the section into full text. Clear the section field
         // so that later submission of conflict forms won't try to
         // replace that into a duplicated mess.
         $this->textbox1 = $this->toEditText($content);
         $this->section = '';
         $status->value = self::AS_SUCCESS_UPDATE;
     }
     if (!$this->allowSelfRedirect && $content->isRedirect() && $content->getRedirectTarget()->equals($this->getTitle())) {
         // If the page already redirects to itself, don't warn.
         $currentTarget = $this->getCurrentContent()->getRedirectTarget();
         if (!$currentTarget || !$currentTarget->equals($this->getTitle())) {
             $this->selfRedirect = true;
             $status->fatal('selfredirect');
             $status->value = self::AS_SELF_REDIRECT;
             return $status;
         }
     }
     // Check for length errors again now that the section is merged in
     $this->kblength = (int) (strlen($this->toEditText($content)) / 1024);
     if ($this->kblength > $wgMaxArticleSize) {
         $this->tooBig = true;
         $status->setResult(false, self::AS_MAX_ARTICLE_SIZE_EXCEEDED);
         return $status;
     }
     $flags = EDIT_AUTOSUMMARY | ($new ? EDIT_NEW : EDIT_UPDATE) | ($this->minoredit && !$this->isNew ? EDIT_MINOR : 0) | ($bot ? EDIT_FORCE_BOT : 0);
     $doEditStatus = $this->mArticle->doEditContent($content, $this->summary, $flags, false, $wgUser, $content->getDefaultFormat());
     if (!$doEditStatus->isOK()) {
         // Failure from doEdit()
         // Show the edit conflict page for certain recognized errors from doEdit(),
         // but don't show it for errors from extension hooks
         $errors = $doEditStatus->getErrorsArray();
         if (in_array($errors[0][0], array('edit-gone-missing', 'edit-conflict', 'edit-already-exists'))) {
             $this->isConflict = true;
             // Destroys data doEdit() put in $status->value but who cares
             $doEditStatus->value = self::AS_END;
         }
         return $doEditStatus;
     }
     $result['nullEdit'] = $doEditStatus->hasMessage('edit-no-change');
     if ($result['nullEdit']) {
         // We don't know if it was a null edit until now, so increment here
         $wgUser->pingLimiter('linkpurge');
     }
     $result['redirect'] = $content->isRedirect();
     $this->updateWatchlist();
     if ($this->changeTags && isset($doEditStatus->value['revision'])) {
         // If a revision was created, apply any change tags that were requested
         $addTags = $this->changeTags;
         $revId = $doEditStatus->value['revision']->getId();
         // Defer this both for performance and so that addTags() sees the rc_id
         // since the recentchange entry addition is deferred first (bug T100248)
         DeferredUpdates::addCallableUpdate(function () use($addTags, $revId) {
             ChangeTags::addTags($addTags, null, $revId);
         });
     }
     // If the content model changed, add a log entry
     if ($changingContentModel) {
         $this->addContentModelChangeLogEntry($wgUser, $oldContentModel, $this->contentModel, $this->summary);
     }
     return $status;
 }
 protected function saveTags()
 {
     $revId = $this->getTitle()->getLatestRevID();
     $reason = $this->reason;
     $user = $this->getUser();
     $tags = array();
     // Is this a major change, or just a secondary change? Mark both for major
     if ($this->hasArabicLangLink()) {
         $tags[] = MarkMajorChanges::getSecondaryTagName();
     }
     if (!$this->isSecondaryChange) {
         $tags[] = MarkMajorChanges::getMainTagName();
     }
     // Should we use DeferredUpdates::addCallableUpdate?
     $status = ChangeTags::addTags($tags, null, $revId);
     if ($status === true) {
         $this->logTagAdded($tags, $revId, $user, $reason);
         //$this->getTitle()->isMajorChange == true;
         return true;
     }
     return false;
 }
Example #10
0
 /**
  * Extracts the title 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()
 {
     $this->useTransactionalTimeLimit();
     $params = $this->extractRequestParams();
     $pageObj = $this->getTitleOrPageId($params, 'fromdbmaster');
     if (!$pageObj->exists()) {
         $this->dieUsageMsg('notanarticle');
     }
     $titleObj = $pageObj->getTitle();
     $reason = $params['reason'];
     $user = $this->getUser();
     // Check that the user is allowed to carry out the deletion
     $errors = $titleObj->getUserPermissionsErrors('delete', $user);
     if (count($errors)) {
         $this->dieUsageMsg($errors[0]);
     }
     // If change tagging was requested, check that the user is allowed to tag,
     // and the tags are valid
     if (count($params['tags'])) {
         $tagStatus = ChangeTags::canAddTagsAccompanyingChange($params['tags'], $user);
         if (!$tagStatus->isOK()) {
             $this->dieStatus($tagStatus);
         }
     }
     if ($titleObj->getNamespace() == NS_FILE) {
         $status = self::deleteFile($pageObj, $user, $params['oldimage'], $reason, false);
     } else {
         $status = self::delete($pageObj, $user, $reason);
     }
     if (is_array($status)) {
         $this->dieUsageMsg($status[0]);
     }
     if (!$status->isGood()) {
         $this->dieStatus($status);
     }
     // Deprecated parameters
     if ($params['watch']) {
         $watch = 'watch';
     } elseif ($params['unwatch']) {
         $watch = 'unwatch';
     } else {
         $watch = $params['watchlist'];
     }
     $this->setWatch($watch, $titleObj, 'watchdeletion');
     // Apply change tags to the log entry, if requested
     if (count($params['tags'])) {
         ChangeTags::addTags($params['tags'], null, null, $status->value, null);
     }
     $r = array('title' => $titleObj->getPrefixedText(), 'reason' => $reason, 'logid' => $status->value);
     $this->getResult()->addValue(null, $this->getModuleName(), $r);
 }
 /**
  * Called when an edit is saved
  * Adds 'visualeditor-switched' tag to the edit if requested
  *
  * @param $article WikiPage
  * @param $user User
  * @param $content Content
  * @param $summary string
  * @param $isMinor boolean
  * @param $isWatch boolean
  * @param $section int
  * @param $flags int
  * @param $revision Revision|null
  * @param $status Status
  * @param $baseRevId int|boolean
  * @return boolean true
  */
 public static function onPageContentSaveComplete($article, $user, $content, $summary, $isMinor, $isWatch, $section, $flags, $revision, $status, $baseRevId)
 {
     $request = RequestContext::getMain()->getRequest();
     if ($request->getBool('veswitched') && $revision) {
         ChangeTags::addTags('visualeditor-switched', null, $revision->getId());
     }
     return true;
 }
 * Thiswas sourced from TranslateWiki (https://github.com/wikimedia/translatewiki/blob/0b7ba4665ab3e599516d2c2774e2541495a9d7a4/TranslatewikiSettings.php#L478)
 */
$wgHooks['GetBetaFeaturePreferences'][] = function ($user, &$prefs) {
    $prefs['hhvm-beta'] = array('label-message' => 'hhvm-beta-label', 'desc-message' => 'hhvm-beta-desc', 'info-link' => 'http://www.hhvm.com/', 'discussion-link' => 'https://meta.orain.org/wiki/Forum:HHVM');
};
$wgHooks['BeforePageDisplay'][] = function (OutputPage $out) {
    $req = $out->getRequest();
    $user = $out->getUser();
    $hasCookie = $req->getCookie('hhvm', '');
    $wantsCookie = BetaFeatures::isFeatureEnabled($user, 'hhvm-beta');
    if (!$hasCookie && $wantsCookie) {
        $req->response()->setcookie('hhvm', '1', 0, array('prefix' => ''));
    }
    if ($hasCookie && !$wantsCookie) {
        $req->response()->setcookie('hhvm', '0', -1, array('prefix' => ''));
    }
};
$wgHooks['RecentChange_save'][] = function (RecentChange $rc) {
    if (wfIsHHVM()) {
        ChangeTags::addTags('HHVM', $rc->getAttribute('rc_id'));
    }
    return true;
};
$wgHooks['LocalisationCacheRecache'][] = function ($cache, $code, &$cachedData) {
    if ($code === 'en') {
        $cachedData['messages']['hhvm-beta-label'] = 'HHVM';
        $cachedData['messages']['hhvm-beta-desc'] = 'HHVM is a new and faster PHP runtime.';
        $cachedData['messages']['tag-HHVM'] = '[[m:Forum:HHVM|HHVM]]';
        $cachedData['messages']['tag-HHVM-description'] = 'Changes made using HHVM. These are tagged for analysis purposes';
    }
};
Example #13
0
 /**
  * Writes the data in this object to the database
  * @param bool $noudp
  */
 public function save($noudp = false)
 {
     global $wgPutIPinRC, $wgUseEnotif, $wgShowUpdatedMarker, $wgContLang;
     $dbw = wfGetDB(DB_MASTER);
     if (!is_array($this->mExtra)) {
         $this->mExtra = [];
     }
     if (!$wgPutIPinRC) {
         $this->mAttribs['rc_ip'] = '';
     }
     # Strict mode fixups (not-NULL fields)
     foreach (['minor', 'bot', 'new', 'patrolled', 'deleted'] as $field) {
         $this->mAttribs["rc_{$field}"] = (int) $this->mAttribs["rc_{$field}"];
     }
     # ...more fixups (NULL fields)
     foreach (['old_len', 'new_len'] as $field) {
         $this->mAttribs["rc_{$field}"] = isset($this->mAttribs["rc_{$field}"]) ? (int) $this->mAttribs["rc_{$field}"] : null;
     }
     # If our database is strict about IP addresses, use NULL instead of an empty string
     $strictIPs = in_array($dbw->getType(), ['oracle', 'postgres']);
     // legacy
     if ($strictIPs && $this->mAttribs['rc_ip'] == '') {
         unset($this->mAttribs['rc_ip']);
     }
     # Trim spaces on user supplied text
     $this->mAttribs['rc_comment'] = trim($this->mAttribs['rc_comment']);
     # Make sure summary is truncated (whole multibyte characters)
     $this->mAttribs['rc_comment'] = $wgContLang->truncate($this->mAttribs['rc_comment'], 255);
     # Fixup database timestamps
     $this->mAttribs['rc_timestamp'] = $dbw->timestamp($this->mAttribs['rc_timestamp']);
     $this->mAttribs['rc_id'] = $dbw->nextSequenceValue('recentchanges_rc_id_seq');
     # # If we are using foreign keys, an entry of 0 for the page_id will fail, so use NULL
     if ($this->mAttribs['rc_cur_id'] == 0) {
         unset($this->mAttribs['rc_cur_id']);
     }
     # Insert new row
     $dbw->insert('recentchanges', $this->mAttribs, __METHOD__);
     # Set the ID
     $this->mAttribs['rc_id'] = $dbw->insertId();
     # Notify extensions
     Hooks::run('RecentChange_save', [&$this]);
     if (count($this->tags)) {
         ChangeTags::addTags($this->tags, $this->mAttribs['rc_id'], $this->mAttribs['rc_this_oldid'], $this->mAttribs['rc_logid'], null, $this);
     }
     # Notify external application via UDP
     if (!$noudp) {
         $this->notifyRCFeeds();
     }
     # E-mail notifications
     if ($wgUseEnotif || $wgShowUpdatedMarker) {
         $editor = $this->getPerformer();
         $title = $this->getTitle();
         // Never send an RC notification email about categorization changes
         if ($this->mAttribs['rc_type'] != RC_CATEGORIZE && Hooks::run('AbortEmailNotification', [$editor, $title, $this])) {
             // @FIXME: This would be better as an extension hook
             // Send emails or email jobs once this row is safely committed
             $dbw->onTransactionIdle(function () use($editor, $title) {
                 $enotif = new EmailNotification();
                 $enotif->notifyOnPageChange($editor, $title, $this->mAttribs['rc_timestamp'], $this->mAttribs['rc_comment'], $this->mAttribs['rc_minor'], $this->mAttribs['rc_last_oldid'], $this->mExtra['pageStatus']);
             }, __METHOD__);
         }
     }
     // Update the cached list of active users
     if ($this->mAttribs['rc_user'] > 0) {
         JobQueueGroup::singleton()->lazyPush(RecentChangesUpdateJob::newCacheUpdateJob());
     }
 }
 /**
  * Adds tag to specified revision ID
  *
  * @param $revisionId integer
  * @param $tag string
  */
 protected static function AddRevisionTag($revisionId, $tag)
 {
     if (!ChangeTags::addTags($tag, null, $revisionId)) {
         \Wikia\Logger\WikiaLogger::instance()->error('Failed to add tag to revision', ['revisionId' => $revisionId, 'tag' => $tag]);
     }
 }
 /**
  * Called when an edit is saved
  * Adds 'visualeditor-switched' tag to the edit if requested
  *
  * @param RecentChange $rc
  * @return boolean true
  */
 public static function onRecentChange_save(RecentChange $rc)
 {
     $request = RequestContext::getMain()->getRequest();
     if ($request->getBool('veswitched') && $rc->mAttribs['rc_this_oldid']) {
         ChangeTags::addTags('visualeditor-switched', $rc->mAttribs['rc_id'], $rc->mAttribs['rc_this_oldid']);
     }
     return true;
 }
    private function setTags($titlesAndTagInfo, $tag, $userId, $rlId, $comment, $setPatrolled = false)
    {
        // XXX Attach a hook to delete tags from the collabwatchlistrevisiontag table as soon as the actual tags are deleted from the change_tags table
        $allowedTagsAndInfo = $this->getCollabWatchlistTags($rlId);
        if (!array_key_exists($tag, $allowedTagsAndInfo)) {
            return false;
        }
        $dbw = wfGetDB(DB_MASTER);
        foreach ($titlesAndTagInfo as $title => $infos) {
            $rcIds = array();
            // Add entries for the tag to the change_tags table
            // optionally mark edit as patrolled
            foreach ($infos as $infoKey => $info) {
                ChangeTags::addTags($tag, $info['rc_id'], $info['rev_id']);
                $rcIds[] = $info['rc_id'];
                if ($setPatrolled) {
                    RecentChange::markPatrolled($info['rc_id']);
                }
            }
            // Add the tagged revisions to the collaborative watchlist
            $sql = 'INSERT IGNORE INTO collabwatchlistrevisiontag (ct_rc_id, ct_tag, cw_id, user_id, rrt_comment)
					SELECT ct_rc_id, ct_tag, ' . $dbw->strencode($rlId) . ',' . $dbw->strencode($userId) . ',' . $dbw->addQuotes($comment) . ' FROM change_tag WHERE ct_tag = ? AND ct_rc_id ';
            if (count($rcIds) > 1) {
                $sql .= 'IN (' . $dbw->makeList($rcIds) . ')';
                $params = array($tag);
            } else {
                $sql .= '= ?';
                $params = array($tag, $rcIds[0]);
            }
            $prepSql = $dbw->prepare($sql);
            $res = $dbw->execute($prepSql, $params);
            $dbw->freePrepared($prepSql);
            return true;
        }
    }
Example #17
0
 /**
  * Record a file upload in the upload log and the image table
  * @param string $oldver
  * @param string $comment
  * @param string $pageText
  * @param bool|array $props
  * @param string|bool $timestamp
  * @param null|User $user
  * @param string[] $tags
  * @return bool
  */
 function recordUpload2($oldver, $comment, $pageText, $props = false, $timestamp = false, $user = null, $tags = array())
 {
     if (is_null($user)) {
         global $wgUser;
         $user = $wgUser;
     }
     $dbw = $this->repo->getMasterDB();
     # Imports or such might force a certain timestamp; otherwise we generate
     # it and can fudge it slightly to keep (name,timestamp) unique on re-upload.
     if ($timestamp === false) {
         $timestamp = $dbw->timestamp();
         $allowTimeKludge = true;
     } else {
         $allowTimeKludge = false;
     }
     $props = $props ?: $this->repo->getFileProps($this->getVirtualUrl());
     $props['description'] = $comment;
     $props['user'] = $user->getId();
     $props['user_text'] = $user->getName();
     $props['timestamp'] = wfTimestamp(TS_MW, $timestamp);
     // DB -> TS_MW
     $this->setProps($props);
     # Fail now if the file isn't there
     if (!$this->fileExists) {
         wfDebug(__METHOD__ . ": File " . $this->getRel() . " went missing!\n");
         return false;
     }
     $dbw->startAtomic(__METHOD__);
     # Test to see if the row exists using INSERT IGNORE
     # This avoids race conditions by locking the row until the commit, and also
     # doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition.
     $dbw->insert('image', array('img_name' => $this->getName(), 'img_size' => $this->size, 'img_width' => intval($this->width), 'img_height' => intval($this->height), 'img_bits' => $this->bits, 'img_media_type' => $this->media_type, 'img_major_mime' => $this->major_mime, 'img_minor_mime' => $this->minor_mime, 'img_timestamp' => $timestamp, 'img_description' => $comment, 'img_user' => $user->getId(), 'img_user_text' => $user->getName(), 'img_metadata' => $dbw->encodeBlob($this->metadata), 'img_sha1' => $this->sha1), __METHOD__, 'IGNORE');
     $reupload = $dbw->affectedRows() == 0;
     if ($reupload) {
         if ($allowTimeKludge) {
             # Use LOCK IN SHARE MODE to ignore any transaction snapshotting
             $ltimestamp = $dbw->selectField('image', 'img_timestamp', array('img_name' => $this->getName()), __METHOD__, array('LOCK IN SHARE MODE'));
             $lUnixtime = $ltimestamp ? wfTimestamp(TS_UNIX, $ltimestamp) : false;
             # Avoid a timestamp that is not newer than the last version
             # TODO: the image/oldimage tables should be like page/revision with an ID field
             if ($lUnixtime && wfTimestamp(TS_UNIX, $timestamp) <= $lUnixtime) {
                 sleep(1);
                 // fast enough re-uploads would go far in the future otherwise
                 $timestamp = $dbw->timestamp($lUnixtime + 1);
                 $this->timestamp = wfTimestamp(TS_MW, $timestamp);
                 // DB -> TS_MW
             }
         }
         # (bug 34993) Note: $oldver can be empty here, if the previous
         # version of the file was broken. Allow registration of the new
         # version to continue anyway, because that's better than having
         # an image that's not fixable by user operations.
         # Collision, this is an update of a file
         # Insert previous contents into oldimage
         $dbw->insertSelect('oldimage', 'image', array('oi_name' => 'img_name', 'oi_archive_name' => $dbw->addQuotes($oldver), 'oi_size' => 'img_size', 'oi_width' => 'img_width', 'oi_height' => 'img_height', 'oi_bits' => 'img_bits', 'oi_timestamp' => 'img_timestamp', 'oi_description' => 'img_description', 'oi_user' => 'img_user', 'oi_user_text' => 'img_user_text', 'oi_metadata' => 'img_metadata', 'oi_media_type' => 'img_media_type', 'oi_major_mime' => 'img_major_mime', 'oi_minor_mime' => 'img_minor_mime', 'oi_sha1' => 'img_sha1'), array('img_name' => $this->getName()), __METHOD__);
         # Update the current image row
         $dbw->update('image', array('img_size' => $this->size, 'img_width' => intval($this->width), 'img_height' => intval($this->height), 'img_bits' => $this->bits, 'img_media_type' => $this->media_type, 'img_major_mime' => $this->major_mime, 'img_minor_mime' => $this->minor_mime, 'img_timestamp' => $timestamp, 'img_description' => $comment, 'img_user' => $user->getId(), 'img_user_text' => $user->getName(), 'img_metadata' => $dbw->encodeBlob($this->metadata), 'img_sha1' => $this->sha1), array('img_name' => $this->getName()), __METHOD__);
     }
     $descTitle = $this->getTitle();
     $descId = $descTitle->getArticleID();
     $wikiPage = new WikiFilePage($descTitle);
     $wikiPage->setFile($this);
     // Add the log entry...
     $logEntry = new ManualLogEntry('upload', $reupload ? 'overwrite' : 'upload');
     $logEntry->setTimestamp($this->timestamp);
     $logEntry->setPerformer($user);
     $logEntry->setComment($comment);
     $logEntry->setTarget($descTitle);
     // Allow people using the api to associate log entries with the upload.
     // Log has a timestamp, but sometimes different from upload timestamp.
     $logEntry->setParameters(array('img_sha1' => $this->sha1, 'img_timestamp' => $timestamp));
     // Note we keep $logId around since during new image
     // creation, page doesn't exist yet, so log_page = 0
     // but we want it to point to the page we're making,
     // so we later modify the log entry.
     // For a similar reason, we avoid making an RC entry
     // now and wait until the page exists.
     $logId = $logEntry->insert();
     if ($descTitle->exists()) {
         // Use own context to get the action text in content language
         $formatter = LogFormatter::newFromEntry($logEntry);
         $formatter->setContext(RequestContext::newExtraneousContext($descTitle));
         $editSummary = $formatter->getPlainActionText();
         $nullRevision = Revision::newNullRevision($dbw, $descId, $editSummary, false, $user);
         if ($nullRevision) {
             $nullRevision->insertOn($dbw);
             Hooks::run('NewRevisionFromEditComplete', array($wikiPage, $nullRevision, $nullRevision->getParentId(), $user));
             $wikiPage->updateRevisionOn($dbw, $nullRevision);
             // Associate null revision id
             $logEntry->setAssociatedRevId($nullRevision->getId());
         }
         $newPageContent = null;
     } else {
         // Make the description page and RC log entry post-commit
         $newPageContent = ContentHandler::makeContent($pageText, $descTitle);
     }
     # Defer purges, page creation, and link updates in case they error out.
     # The most important thing is that files and the DB registry stay synced.
     $dbw->endAtomic(__METHOD__);
     # Do some cache purges after final commit so that:
     # a) Changes are more likely to be seen post-purge
     # b) They won't cause rollback of the log publish/update above
     $that = $this;
     $dbw->onTransactionIdle(function () use($that, $reupload, $wikiPage, $newPageContent, $comment, $user, $logEntry, $logId, $descId, $tags) {
         # Update memcache after the commit
         $that->invalidateCache();
         $updateLogPage = false;
         if ($newPageContent) {
             # New file page; create the description page.
             # There's already a log entry, so don't make a second RC entry
             # CDN and file cache for the description page are purged by doEditContent.
             $status = $wikiPage->doEditContent($newPageContent, $comment, EDIT_NEW | EDIT_SUPPRESS_RC, false, $user);
             if (isset($status->value['revision'])) {
                 // Associate new page revision id
                 $logEntry->setAssociatedRevId($status->value['revision']->getId());
             }
             // This relies on the resetArticleID() call in WikiPage::insertOn(),
             // which is triggered on $descTitle by doEditContent() above.
             if (isset($status->value['revision'])) {
                 /** @var $rev Revision */
                 $rev = $status->value['revision'];
                 $updateLogPage = $rev->getPage();
             }
         } else {
             # Existing file page: invalidate description page cache
             $wikiPage->getTitle()->invalidateCache();
             $wikiPage->getTitle()->purgeSquid();
             # Allow the new file version to be patrolled from the page footer
             Article::purgePatrolFooterCache($descId);
         }
         # Update associated rev id. This should be done by $logEntry->insert() earlier,
         # but setAssociatedRevId() wasn't called at that point yet...
         $logParams = $logEntry->getParameters();
         $logParams['associated_rev_id'] = $logEntry->getAssociatedRevId();
         $update = array('log_params' => LogEntryBase::makeParamBlob($logParams));
         if ($updateLogPage) {
             # Also log page, in case where we just created it above
             $update['log_page'] = $updateLogPage;
         }
         $that->getRepo()->getMasterDB()->update('logging', $update, array('log_id' => $logId), __METHOD__);
         $that->getRepo()->getMasterDB()->insert('log_search', array('ls_field' => 'associated_rev_id', 'ls_value' => $logEntry->getAssociatedRevId(), 'ls_log_id' => $logId), __METHOD__);
         # Now that the log entry is up-to-date, make an RC entry.
         $recentChange = $logEntry->publish($logId);
         if ($tags) {
             ChangeTags::addTags($tags, $recentChange ? $recentChange->getAttribute('rc_id') : null, $logEntry->getAssociatedRevId(), $logId);
         }
         # Run hook for other updates (typically more cache purging)
         Hooks::run('FileUpload', array($that, $reupload, !$newPageContent));
         if ($reupload) {
             # Delete old thumbnails
             $that->purgeThumbnails();
             # Remove the old file from the CDN cache
             DeferredUpdates::addUpdate(new CdnCacheUpdate(array($that->getUrl())), DeferredUpdates::PRESEND);
         } else {
             # Update backlink pages pointing to this title if created
             LinksUpdate::queueRecursiveJobsForTable($that->getTitle(), 'imagelinks');
         }
     });
     if (!$reupload) {
         # This is a new file, so update the image count
         DeferredUpdates::addUpdate(SiteStatsUpdate::factory(array('images' => 1)));
     }
     # Invalidate cache for all pages using this file
     DeferredUpdates::addUpdate(new HTMLCacheUpdate($this->getTitle(), 'imagelinks'));
     return true;
 }
Example #18
0
 /**
  * Publish the log entry.
  *
  * @param int $newId Id of the log entry.
  * @param string $to One of: rcandudp (default), rc, udp
  * @return RecentChange|null
  */
 public function publish($newId, $to = 'rcandudp')
 {
     $log = new LogPage($this->getType());
     if ($log->isRestricted()) {
         return null;
     }
     $rc = $this->getRecentChange($newId);
     if ($to === 'rc' || $to === 'rcandudp') {
         $rc->save('pleasedontudp');
     }
     if ($to === 'udp' || $to === 'rcandudp') {
         $rc->notifyRCFeeds();
     }
     // Log the autopatrol if the log entry is patrollable
     if ($this->getIsPatrollable() && $rc->getAttribute('rc_patrolled') === 1) {
         PatrolLog::record($rc, true, $this->getPerformer());
     }
     // Add change tags to the log entry and (if applicable) the associated revision
     $tags = $this->getTags();
     if (!is_null($tags)) {
         $rcId = $rc->getAttribute('rc_id');
         $revId = $this->getAssociatedRevId();
         // Use null if $revId is 0
         ChangeTags::addTags($tags, $rcId, $revId > 0 ? $revId : null, $newId);
     }
     return $rc;
 }
	public static function onRecentChangeSave( $recentChange ) {
		global $wgTorTagChanges;

		if ( class_exists('ChangeTags') && $wgTorTagChanges && self::isExitNode() ) {
			ChangeTags::addTags( 'tor', $recentChange->mAttribs['rc_id'], $recentChange->mAttribs['rc_this_oldid'], $recentChange->mAttribs['rc_logid'] );
		}
		return true;
	}
 /**
  * @param $recentChange RecentChange
  * @return bool
  */
 public static function onRecentChangeSave($recentChange)
 {
     $title = Title::makeTitle($recentChange->getAttribute('rc_namespace'), $recentChange->getAttribute('rc_title'));
     $action = $recentChange->mAttribs['rc_log_type'] ? $recentChange->mAttribs['rc_log_type'] : 'edit';
     $actionID = implode('-', array($title->getPrefixedText(), $recentChange->mAttribs['rc_user_text'], $action));
     if (!empty(AbuseFilter::$tagsToSet[$actionID]) && count($tags = AbuseFilter::$tagsToSet[$actionID])) {
         ChangeTags::addTags($tags, $recentChange->mAttribs['rc_id'], $recentChange->mAttribs['rc_this_oldid'], $recentChange->mAttribs['rc_logid']);
     }
     return true;
 }
 /**
  * RecentChange_save hook handler that tags mobile changes
  * @see https://www.mediawiki.org/wiki/Manual:Hooks/RecentChange_save
  *
  * @param RecentChange $rc
  * @return bool
  */
 public static function onRecentChange_save(RecentChange $rc)
 {
     $context = MobileContext::singleton();
     $userAgent = $context->getRequest()->getHeader("User-agent");
     $logType = $rc->getAttribute('rc_log_type');
     // Only log edits and uploads
     if ($context->shouldDisplayMobileView() && ($logType === 'upload' || is_null($logType))) {
         $rcId = $rc->getAttribute('rc_id');
         $revId = $rc->getAttribute('rc_this_oldid');
         $logId = $rc->getAttribute('rc_logid');
         ChangeTags::addTags('mobile edit', $rcId, $revId, $logId);
         // Tag as mobile web edit specifically, if it isn't coming from the apps
         if (strpos($userAgent, 'WikipediaApp/') !== 0) {
             ChangeTags::addTags('mobile web edit', $rcId, $revId, $logId);
         }
     }
     return true;
 }
 public function publish()
 {
     $params = $this->extractRequestParams();
     $user = $this->getUser();
     $targetTitle = ContentTranslation\SiteMapper::getTargetTitle($params['title'], $user->getName());
     $title = Title::newFromText($targetTitle);
     if (!$title) {
         $this->dieUsageMsg('invalidtitle', $params['title']);
     }
     try {
         $wikitext = $this->convertHtmlToWikitext($title, $params['html']);
     } catch (MWException $e) {
         $this->dieUsage($e->getMessage(), 'parsoidserver');
     }
     $saveresult = $this->saveWikitext($title, $wikitext, $params);
     $editStatus = $saveresult['edit']['result'];
     if ($editStatus === 'Success') {
         if (isset($saveresult['edit']['newrevid'])) {
             // Add the tags post-send, after RC row insertion
             $revId = intval($saveresult['edit']['newrevid']);
             DeferredUpdates::addCallableUpdate(function () use($revId, $params) {
                 ChangeTags::addTags('contenttranslation', null, $revId, null, FormatJson::encode(array('from' => $params['from'], 'to' => $params['to'])));
             });
         }
         $result = array('result' => 'success');
         if (isset($saveresult['edit']['newrevid'])) {
             $result['newrevid'] = intval($saveresult['edit']['newrevid']);
         }
         $this->saveTranslationHistory($params);
         // Notify user about milestones
         $this->notifyTranslator();
     } else {
         $result = array('result' => 'error', 'edit' => $saveresult['edit']);
     }
     $this->getResult()->addValue(null, $this->getModuleName(), $result);
 }