Example #1
0
 /**
  * @param Title $Title
  * @param User $User
  * @param int $articleId
  * @param string $text
  */
 public function __construct($Title, $User, $articleId = 0, $text = '')
 {
     global $wgEnableBlogArticles;
     /**
      * initialization
      */
     $this->mPageNs = $Title->getNamespace();
     if (empty($articleId)) {
         $this->mPageId = $Title->getArticleID();
         if (empty($this->mPageId)) {
             $Title->getArticleID(Title::GAID_FOR_UPDATE);
         }
     } else {
         $this->setPageId($articleId);
     }
     if (is_object($User)) {
         $this->mUserId = intval($User->getID());
     } else {
         $this->mUserId = intval($User);
     }
     $this->mIsContent = $Title->isContentPage() && ($wgEnableBlogArticles && !in_array($this->mPageNs, array(NS_BLOG_ARTICLE, NS_BLOG_ARTICLE_TALK, NS_BLOG_LISTING, NS_BLOG_LISTING_TALK)));
     $this->mDate = date('Y-m-d');
     if ($text) {
         $this->mText = preg_replace('/\\[\\[[^\\:\\]]+\\:[^\\]]*\\]\\]/', '', $text);
     }
 }
Example #2
0
 /**
  * @return int log_id of the inserted log entry
  */
 protected function saveContent()
 {
     global $wgLogRestrictions;
     $dbw = wfGetDB(DB_MASTER);
     $log_id = $dbw->nextSequenceValue('logging_log_id_seq');
     $this->timestamp = $now = wfTimestampNow();
     $data = array('log_id' => $log_id, 'log_type' => $this->type, 'log_action' => $this->action, 'log_timestamp' => $dbw->timestamp($now), 'log_user' => $this->doer->getId(), 'log_user_text' => $this->doer->getName(), 'log_namespace' => $this->target->getNamespace(), 'log_title' => $this->target->getDBkey(), 'log_page' => $this->target->getArticleID(), 'log_comment' => $this->comment, 'log_params' => $this->params);
     $dbw->insert('logging', $data, __METHOD__);
     $newId = !is_null($log_id) ? $log_id : $dbw->insertId();
     # And update recentchanges
     if ($this->updateRecentChanges) {
         $titleObj = SpecialPage::getTitleFor('Log', $this->type);
         RecentChange::notifyLog($now, $titleObj, $this->doer, $this->getRcComment(), '', $this->type, $this->action, $this->target, $this->comment, $this->params, $newId, $this->getRcCommentIRC());
     } elseif ($this->sendToUDP) {
         # Don't send private logs to UDP
         if (isset($wgLogRestrictions[$this->type]) && $wgLogRestrictions[$this->type] != '*') {
             return $newId;
         }
         # Notify external application via UDP.
         # We send this to IRC but do not want to add it the RC table.
         $titleObj = SpecialPage::getTitleFor('Log', $this->type);
         $rc = RecentChange::newLogEntry($now, $titleObj, $this->doer, $this->getRcComment(), '', $this->type, $this->action, $this->target, $this->comment, $this->params, $newId, $this->getRcCommentIRC());
         $rc->notifyRC2UDP();
     }
     return $newId;
 }
 /**
  * Returns a list of query conditions that should be run against the revision table
  *
  * @return array List of conditions
  */
 protected function getQueryConditions()
 {
     $conds = array();
     if ($this->title) {
         $conds['rev_page'] = $this->title->getArticleID();
     }
     if ($this->offset) {
         $dbr = wfGetDB(DB_SLAVE, self::DB_REVISIONS_TABLE);
         $conds[] = 'rev_timestamp <= ' . $dbr->addQuotes($this->offset);
     }
     return $conds;
 }
 /**
  * @throws \Email\Check
  */
 protected function assertValidPageAddedToCategory()
 {
     if (!$this->pageAddedToCategory instanceof \Title) {
         throw new Check("Invalid value passed for pageAddedToCategory (param: pageTitle)");
     }
     if (!$this->pageAddedToCategory->exists()) {
         // Check master DB just in case the page was just created and it
         // hasn't been replicated to the slave yet
         if ($this->pageAddedToCategory->getArticleID(\Title::GAID_FOR_UPDATE) == 0) {
             throw new Check("pageAddedToCategory doesn't exist.");
         }
     }
 }
 /**
  * Checks if a given article has been fixed by a user
  * inside a productivity loop.
  * @param Title $title
  * @return bool
  */
 public function isItemFixed(Title $title)
 {
     if ($title->getArticleID() !== 0) {
         return $this->removeFixedItem(ucfirst(self::INSIGHT_TYPE), $title);
     }
     return false;
 }
Example #6
0
 /**
  * Get MediaWiki's ID for this value or 0 if not available.
  *
  * @return integer
  */
 public function getArticleID()
 {
     if ($this->m_id === false) {
         $this->m_id = !is_null($this->getTitle()) ? $this->m_title->getArticleID() : 0;
     }
     return $this->m_id;
 }
 /**
  * Performs all actions required to log all information required to have a given template
  * classified and have them stored in an accessible way.
  * @param string $type A type that you want to classify the template as.
  * @param bool $value Value of the classification. If false, the type will be set to unclassified.
  * @param int $actor Specifies if the recognition was made by a machine or a human
  * @return bool
  * @throws MWException
  */
 public function classifyTemplate($type, $value, $actor = self::CLASSIFICATION_ACTOR_HUMAN)
 {
     /**
      * Check if the fetched $type is valid
      * and if the user is permitted to perform templatedraft related actions.
      */
     $prop = self::getClassificationProp($type);
     if (!$prop || !$this->title->userCan('templatedraft')) {
         return false;
     }
     /**
      * SET THE PRIMARY PAGE PROPERTY
      *
      * If the $value equals false it means somebody has just made a negative recognition
      * (e.g. the template is NOT an infobox). In this case, we set the primary property to
      * unclassified to mark that the template has been reviewed, but we do not have a definite
      * information on its type.
      */
     if (!$value) {
         $type = self::TEMPLATE_UNCLASSIFIED;
     }
     Wikia::setProps($this->title->getArticleID(), [self::TEMPLATE_CLASSIFICATION_MAIN_PROP => $type]);
     /**
      * SET THE SECONDARY PAGE PROPERTY
      *
      * This property is used to log more detailed information on the performed action.
      */
     $data = ['value' => (bool) $value, 'actor' => $actor, 'actor-id' => $this->wg->User->getId(), 'timestamp' => wfTimestamp()];
     Wikia::setProps($this->title->getArticleID(), [$prop => json_encode($data)]);
     /**
      * Since Wikia::setProps fails silently we can return true at this point.
      */
     return true;
 }
 /**
  * getProps -- get props for comment article
  *
  */
 public function getProps()
 {
     if ((!$this->mProps || !is_array($this->mProps)) && class_exists('BlogArticle')) {
         $this->mProps = BlogArticle::getProps($this->mTitle->getArticleID());
     }
     return $this->mProps;
 }
Example #9
0
 /**
  * Updates cascading protections
  *
  * @param $parserOutput ParserOutput object for the current version
  */
 public function doCascadeProtectionUpdates(ParserOutput $parserOutput)
 {
     if (wfReadOnly() || !$this->mTitle->areRestrictionsCascading()) {
         return;
     }
     // templatelinks table may have become out of sync,
     // especially if using variable-based transclusions.
     // For paranoia, check if things have changed and if
     // so apply updates to the database. This will ensure
     // that cascaded protections apply as soon as the changes
     // are visible.
     # Get templates from templatelinks
     $id = $this->mTitle->getArticleID();
     $tlTemplates = array();
     $dbr = wfGetDB(DB_SLAVE);
     $res = $dbr->select(array('templatelinks'), array('tl_namespace', 'tl_title'), array('tl_from' => $id), __METHOD__);
     foreach ($res as $row) {
         $tlTemplates["{$row->tl_namespace}:{$row->tl_title}"] = true;
     }
     # Get templates from parser output.
     $poTemplates = array();
     foreach ($parserOutput->getTemplates() as $ns => $templates) {
         foreach ($templates as $dbk => $id) {
             $poTemplates["{$ns}:{$dbk}"] = true;
         }
     }
     # Get the diff
     $templates_diff = array_diff_key($poTemplates, $tlTemplates);
     if (count($templates_diff) > 0) {
         # Whee, link updates time.
         # Note: we are only interested in links here. We don't need to get other DataUpdate items from the parser output.
         $u = new LinksUpdate($this->mTitle, $parserOutput, false);
         $u->doUpdate();
     }
 }
 /**
  * Returns primary coordinates of the given page, if any
  * @param Title $title
  * @return Coord|false: Coordinates or false
  */
 public static function getPageCoordinates(Title $title)
 {
     $coords = self::getAllCoordinates($title->getArticleID(), array('gt_primary' => 1));
     if ($coords) {
         return $coords[0];
     }
     return false;
 }
 /**
  * Checks if a given article has been fixed by a user
  * inside a productivity loop.
  * @param Title $title
  * @return bool
  */
 public function isItemFixed(Title $title)
 {
     $dbr = wfGetDB(DB_MASTER);
     $row = $dbr->selectRow('pagelinks', '*', ['pl_from' => $title->getArticleID()]);
     if ($row) {
         return $this->removeFixedItem(ucfirst(self::INSIGHT_TYPE), $title);
     }
     return false;
 }
Example #12
0
 function __construct(SpecialMergeHistory $form, $conds, Title $source, Title $dest)
 {
     $this->mForm = $form;
     $this->mConds = $conds;
     $this->title = $source;
     $this->articleID = $source->getArticleID();
     $dbr = wfGetDB(DB_REPLICA);
     $maxtimestamp = $dbr->selectField('revision', 'MIN(rev_timestamp)', ['rev_page' => $dest->getArticleID()], __METHOD__);
     $this->maxTimestamp = $maxtimestamp;
     parent::__construct($form->getContext());
 }
Example #13
0
 /**
  * Test that getting all properties clears the single properties
  * that have been cached by getting a property, saving a new value for
  * the property, getting all properties (which clears the cached single
  * properties), then getting the property again. The new value for the
  * property rather than the cached value of the property should be
  * returned.
  */
 public function testClearCache()
 {
     $pageProps = PageProps::getInstance();
     $page1ID = $this->title1->getArticleID();
     $pageProps->getProperty($this->title1, "property1");
     $new_value = "another value";
     $this->setProperty($page1ID, "property1", $new_value);
     $pageProps->getProperties($this->title1);
     $result = $pageProps->getProperty($this->title1, "property1");
     $this->assertArrayHasKey($page1ID, $result, "Found property");
     $this->assertEquals($result[$page1ID], "another value", "Clear cache");
 }
 /**
  * Driver function that handles updating assessment data in database
  * @param Title $titleObj Title object of the subject page
  * @param array $assessmentData Data for all assessments compiled
  */
 public static function doUpdates($titleObj, $assessmentData)
 {
     global $wgUpdateRowsPerQuery;
     $factory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
     $ticket = $factory->getEmptyTransactionTicket(__METHOD__);
     $pageId = $titleObj->getArticleID();
     $revisionId = $titleObj->getLatestRevID();
     // Compile a list of projects to find out which ones to be deleted afterwards
     $projects = array();
     foreach ($assessmentData as $parserData) {
         // For each project, get the corresponding ID from page_assessments_projects table
         $projectId = self::getProjectId($parserData[0]);
         if ($projectId === false) {
             $projectId = self::insertProject($parserData[0]);
         }
         $projects[$parserData[0]] = $projectId;
     }
     $projectsInDb = self::getAllProjects($pageId, self::READ_LATEST);
     $toInsert = array_diff($projects, $projectsInDb);
     $toDelete = array_diff($projectsInDb, $projects);
     $toUpdate = array_intersect($projects, $projectsInDb);
     $i = 0;
     // Add and update records to the database
     foreach ($assessmentData as $parserData) {
         $projectId = $projects[$parserData[0]];
         if ($projectId) {
             $class = $parserData[1];
             $importance = $parserData[2];
             $values = array('pa_page_id' => $pageId, 'pa_project_id' => $projectId, 'pa_class' => $class, 'pa_importance' => $importance, 'pa_page_revision' => $revisionId);
             if (in_array($projectId, $toInsert)) {
                 self::insertRecord($values);
             } elseif (in_array($projectId, $toUpdate)) {
                 self::updateRecord($values);
             }
             // Check for database lag if there's a huge number of assessments
             if ($i > 0 && $i % $wgUpdateRowsPerQuery == 0) {
                 $factory->commitAndWaitForReplication(__METHOD__, $ticket);
             }
             $i++;
         }
     }
     // Delete records from the database
     foreach ($toDelete as $project) {
         $values = array('pa_page_id' => $pageId, 'pa_project_id' => $project);
         self::deleteRecord($values);
         // Check for database lag if there's a huge number of deleted assessments
         if ($i > 0 && $i % $wgUpdateRowsPerQuery == 0) {
             $factory->commitAndWaitForReplication(__METHOD__, $ticket);
         }
         $i++;
     }
     return;
 }
 public static function newFromTarget(Title $target)
 {
     $pageid = $target->getArticleID();
     $dbr = wfGetDB(DB_SLAVE);
     $res = $dbr->select('indexes', array('in_namespace', 'in_title'), array('in_from' => $pageid), __METHOD__);
     if (!$res->numRows()) {
         return null;
     }
     $ind = new IndexFunction();
     $row = $res->fetchRow();
     $ind->mFrom = Title::makeTitle($row->in_namespace, $row->in_title);
     return $ind;
 }
Example #16
0
 /**
  * Extract information from a Title object for return to Lua
  *
  * This also records a link to this title in the current ParserOutput
  * and caches the title for repeated lookups. The caller should call
  * incrementExpensiveFunctionCount() if necessary.
  *
  * @param $title Title Title to return
  * @return array Lua data
  */
 private function returnTitleToLua(Title $title)
 {
     // Cache it
     $this->titleCache[$title->getPrefixedDBkey()] = $title;
     if ($title->getArticleID() > 0) {
         $this->idCache[$title->getArticleID()] = $title;
     }
     // Record a link
     if ($this->getParser() && !$title->equals($this->getTitle())) {
         $this->getParser()->getOutput()->addLink($title);
     }
     $ns = $title->getNamespace();
     $ret = array('isLocal' => (bool) $title->isLocal(), 'isRedirect' => (bool) $title->isRedirect(), 'interwiki' => $title->getInterwiki(), 'namespace' => $ns, 'nsText' => $title->getNsText(), 'text' => $title->getText(), 'id' => $title->getArticleID(), 'fragment' => $title->getFragment(), 'thePartialUrl' => $title->getPartialURL());
     if ($ns === NS_SPECIAL) {
         $ret['exists'] = (bool) SpecialPageFactory::exists($title->getDBkey());
     } else {
         $ret['exists'] = $ret['id'] > 0;
     }
     if ($ns !== NS_FILE && $ns !== NS_MEDIA) {
         $ret['fileExists'] = false;
     }
     return $ret;
 }
Example #17
0
    private function showHistory()
    {
        $this->showMergeForm();
        # List all stored revisions
        $revisions = new MergeHistoryPager($this, [], $this->mTargetObj, $this->mDestObj);
        $haveRevisions = $revisions && $revisions->getNumRows() > 0;
        $out = $this->getOutput();
        $titleObj = $this->getPageTitle();
        $action = $titleObj->getLocalURL(['action' => 'submit']);
        # Start the form here
        $top = Xml::openElement('form', ['method' => 'post', 'action' => $action, 'id' => 'merge']);
        $out->addHTML($top);
        if ($haveRevisions) {
            # Format the user-visible controls (comment field, submission button)
            # in a nice little table
            $table = Xml::openElement('fieldset') . $this->msg('mergehistory-merge', $this->mTargetObj->getPrefixedText(), $this->mDestObj->getPrefixedText())->parse() . Xml::openElement('table', ['id' => 'mw-mergehistory-table']) . '<tr>
						<td class="mw-label">' . Xml::label($this->msg('mergehistory-reason')->text(), 'wpComment') . '</td>
					<td class="mw-input">' . Xml::input('wpComment', 50, $this->mComment, ['id' => 'wpComment']) . '</td>
					</tr>
					<tr>
						<td>&#160;</td>
						<td class="mw-submit">' . Xml::submitButton($this->msg('mergehistory-submit')->text(), ['name' => 'merge', 'id' => 'mw-merge-submit']) . '</td>
					</tr>' . Xml::closeElement('table') . Xml::closeElement('fieldset');
            $out->addHTML($table);
        }
        $out->addHTML('<h2 id="mw-mergehistory">' . $this->msg('mergehistory-list')->escaped() . "</h2>\n");
        if ($haveRevisions) {
            $out->addHTML($revisions->getNavigationBar());
            $out->addHTML('<ul>');
            $out->addHTML($revisions->getBody());
            $out->addHTML('</ul>');
            $out->addHTML($revisions->getNavigationBar());
        } else {
            $out->addWikiMsg('mergehistory-empty');
        }
        # Show relevant lines from the merge log:
        $mergeLogPage = new LogPage('merge');
        $out->addHTML('<h2>' . $mergeLogPage->getName()->escaped() . "</h2>\n");
        LogEventsList::showLogExtract($out, 'merge', $this->mTargetObj);
        # When we submit, go by page ID to avoid some nasty but unlikely collisions.
        # Such would happen if a page was renamed after the form loaded, but before submit
        $misc = Html::hidden('targetID', $this->mTargetObj->getArticleID());
        $misc .= Html::hidden('destID', $this->mDestObj->getArticleID());
        $misc .= Html::hidden('target', $this->mTarget);
        $misc .= Html::hidden('dest', $this->mDest);
        $misc .= Html::hidden('wpEditToken', $this->getUser()->getEditToken());
        $misc .= Xml::closeElement('form');
        $out->addHTML($misc);
        return true;
    }
 /**
  * Dispatched from execute();
  */
 private function processParameter($sParameter)
 {
     try {
         $this->oRequestedTitle = Title::newFromText($sParameter);
         /*if( !$this->oRequestedTitle->exists() && $this->oRequestedTitle->getNamespace() != NS_SPECIAL ) { //!$this->mRequestedTitle->isSpecialPage() does not work in MW 1.13
         			throw new Exception( 'error-requested-title-does-not-exist' );
         		}*/
         //Get relevant page props
         $dbr = wfGetDB(DB_SLAVE);
         $res = $dbr->selectField('page_props', 'pp_value', array('pp_propname' => 'bs-universalexport-params', 'pp_page' => $this->oRequestedTitle->getArticleID()));
         if ($res != false) {
             $res = FormatJson::decode($res, true);
             if (is_array($res)) {
                 $this->aParams = array_merge($this->aParams, $res);
             }
         }
         BsUniversalExportHelper::getParamsFromQueryString($this->aParams);
         //Title::userCan always returns false on special pages (exept for createaccount action)
         if ($this->oRequestedTitle->getNamespace() === NS_SPECIAL) {
             if ($this->getUser()->isAllowed('universalexport-export') !== true) {
                 throw new Exception('bs-universalexport-error-permission');
             }
         } elseif ($this->oRequestedTitle->userCan('universalexport-export') === false) {
             throw new Exception('bs-universalexport-error-permission');
         }
         // TODO RBV (24.01.11 17:37): array_intersect(), may be better?
         $aCategoryNames = BsUniversalExportHelper::getCategoriesForTitle($this->oRequestedTitle);
         foreach ($aCategoryNames as $sCategoryName) {
             if (in_array($sCategoryName, $this->aCategoryBlacklist)) {
                 throw new Exception('bs-universalexport-error-requested-title-in-category-blacklist');
             }
         }
         BsUniversalExportHelper::checkPermissionForTitle($this->oRequestedTitle, $this->aParams);
         //Throws Exception
         $sModuleKey = $this->aParams['module'];
         if (!isset($this->aModules[$sModuleKey]) || !$this->aModules[$sModuleKey] instanceof BsUniversalExportModule) {
             throw new Exception('bs-universalexport-error-requested-export-module-not-found');
         }
         $oExportModule = $this->aModules[$sModuleKey];
         $aFile = $oExportModule->createExportFile($this);
         $this->returnFile($aFile);
     } catch (Exception $oException) {
         //Display Exception-Message and Stacktrace
         $this->oOutputPage->setPageTitle(wfMessage('bs-universalexport-page-title-on-error')->text());
         $oExceptionView = new ViewException($oException);
         $this->oOutputPage->addHtml($oExceptionView->execute());
     }
 }
Example #19
0
 /**
  * Constructor
  *
  * @param Title $title Title of the page we're updating
  * @param ParserOutput $parserOutput Output from a full parse of this page
  * @param bool $recursive Queue jobs for recursive updates?
  * @throws MWException
  */
 function __construct($title, $parserOutput, $recursive = true)
 {
     parent::__construct(false);
     // no implicit transaction
     if (!$title instanceof Title) {
         throw new MWException("The calling convention to LinksUpdate::LinksUpdate() has changed. " . "Please see Article::editUpdates() for an invocation example.\n");
     }
     if (!$parserOutput instanceof ParserOutput) {
         throw new MWException("The calling convention to LinksUpdate::__construct() has changed. " . "Please see WikiPage::doEditUpdates() for an invocation example.\n");
     }
     $this->mTitle = $title;
     $this->mId = $title->getArticleID();
     if (!$this->mId) {
         throw new MWException("The Title object did not provide an article " . "ID. Perhaps the page doesn't exist?");
     }
     $this->mParserOutput = $parserOutput;
     $this->mLinks = $parserOutput->getLinks();
     $this->mImages = $parserOutput->getImages();
     $this->mTemplates = $parserOutput->getTemplates();
     $this->mExternals = $parserOutput->getExternalLinks();
     $this->mCategories = $parserOutput->getCategories();
     $this->mProperties = $parserOutput->getProperties();
     $this->mInterwikis = $parserOutput->getInterwikiLinks();
     # Convert the format of the interlanguage links
     # I didn't want to change it in the ParserOutput, because that array is passed all
     # the way back to the skin, so either a skin API break would be required, or an
     # inefficient back-conversion.
     $ill = $parserOutput->getLanguageLinks();
     $this->mInterlangs = array();
     foreach ($ill as $link) {
         list($key, $title) = explode(':', $link, 2);
         $this->mInterlangs[$key] = $title;
     }
     foreach ($this->mCategories as &$sortkey) {
         # If the sortkey is longer then 255 bytes,
         # it truncated by DB, and then doesn't get
         # matched when comparing existing vs current
         # categories, causing bug 25254.
         # Also. substr behaves weird when given "".
         if ($sortkey !== '') {
             $sortkey = substr($sortkey, 0, 255);
         }
     }
     $this->mRecursive = $recursive;
     Hooks::run('LinksUpdateConstructed', array(&$this));
 }
 /**
  * Get number of active users watching a page
  * @param Title $title
  * @return int
  */
 public static function numUsersWatchingPage(Title $title)
 {
     global $wgMemc, $wgCookieExpiration;
     # Check the cache...
     $key = wfMemcKey('flaggedrevs', 'usersWatching', $title->getArticleID());
     $val = $wgMemc->get($key);
     if (is_int($val)) {
         return $val;
         // cache hit
     }
     # Get number of active editors watching this page...
     $dbr = wfGetDB(DB_SLAVE);
     $cutoff = $dbr->timestamp(wfTimestamp(TS_UNIX) - 2 * $wgCookieExpiration);
     $count = (int) $dbr->selectField(array('watchlist', 'user'), 'COUNT(*)', array('wl_namespace' => $title->getNamespace(), 'wl_title' => $title->getDBkey(), 'wl_user = user_id', 'user_touched > ' . $dbr->addQuotes($cutoff)), __METHOD__);
     if ($count > 10) {
         # Save new value to cache (more aggresive for larger counts)
         $wgMemc->set($key, $count, $count > 200 ? 30 * 60 : 5 * 60);
     }
     return $count;
 }
Example #21
0
 /**
  * Constructor
  *
  * @param Title $title Title of the page we're updating
  * @param ParserOutput $parserOutput Output from a full parse of this page
  * @param bool $recursive Queue jobs for recursive updates?
  * @throws MWException
  */
 function __construct(Title $title, ParserOutput $parserOutput, $recursive = true)
 {
     parent::__construct(false);
     // no implicit transaction
     $this->mTitle = $title;
     $this->mId = $title->getArticleID(Title::GAID_FOR_UPDATE);
     if (!$this->mId) {
         throw new InvalidArgumentException("The Title object yields no ID. Perhaps the page doesn't exist?");
     }
     $this->mParserOutput = $parserOutput;
     $this->mLinks = $parserOutput->getLinks();
     $this->mImages = $parserOutput->getImages();
     $this->mTemplates = $parserOutput->getTemplates();
     $this->mExternals = $parserOutput->getExternalLinks();
     $this->mCategories = $parserOutput->getCategories();
     $this->mProperties = $parserOutput->getProperties();
     $this->mInterwikis = $parserOutput->getInterwikiLinks();
     # Convert the format of the interlanguage links
     # I didn't want to change it in the ParserOutput, because that array is passed all
     # the way back to the skin, so either a skin API break would be required, or an
     # inefficient back-conversion.
     $ill = $parserOutput->getLanguageLinks();
     $this->mInterlangs = array();
     foreach ($ill as $link) {
         list($key, $title) = explode(':', $link, 2);
         $this->mInterlangs[$key] = $title;
     }
     foreach ($this->mCategories as &$sortkey) {
         # If the sortkey is longer then 255 bytes,
         # it truncated by DB, and then doesn't get
         # matched when comparing existing vs current
         # categories, causing bug 25254.
         # Also. substr behaves weird when given "".
         if ($sortkey !== '') {
             $sortkey = substr($sortkey, 0, 255);
         }
     }
     $this->mRecursive = $recursive;
     Hooks::run('LinksUpdateConstructed', array(&$this));
 }
 /**
  * Set the stability configuration settings for a page
  * @param Title $title
  * @param array $config
  * @return bool Row changed
  */
 public static function setStabilitySettings(Title $title, array $config)
 {
     $dbw = wfGetDB(DB_MASTER);
     # If setting to site default values and there is a row then erase it
     if (self::configIsReset($config)) {
         $dbw->delete('flaggedpage_config', array('fpc_page_id' => $title->getArticleID()), __METHOD__);
         $changed = $dbw->affectedRows() != 0;
         // did this do anything?
         # Otherwise, add/replace row if we are not just setting it to the site default
     } else {
         $dbExpiry = Block::encodeExpiry($config['expiry'], $dbw);
         # Get current config...
         $oldRow = $dbw->selectRow('flaggedpage_config', array('fpc_override', 'fpc_level', 'fpc_expiry'), array('fpc_page_id' => $title->getArticleID()), __METHOD__, 'FOR UPDATE');
         # Check if this is not the same config as the existing (if any) row
         $changed = !$oldRow || $oldRow->fpc_override != $config['override'] || $oldRow->fpc_level != $config['autoreview'] || $oldRow->fpc_expiry != $dbExpiry;
         # If the new config is different, replace the old row...
         if ($changed) {
             $dbw->replace('flaggedpage_config', array('PRIMARY'), array('fpc_page_id' => $title->getArticleID(), 'fpc_select' => -1, 'fpc_override' => (int) $config['override'], 'fpc_level' => $config['autoreview'], 'fpc_expiry' => $dbExpiry), __METHOD__);
         }
     }
     return $changed;
 }
 /**
  * Update flaggedrevs page/tracking tables (revision moving)
  */
 public static function onArticleMergeComplete(Title $sourceTitle, Title $destTitle)
 {
     $oldPageID = $sourceTitle->getArticleID();
     $newPageID = $destTitle->getArticleID();
     # Get flagged revisions from old page id that point to destination page
     $dbw = wfGetDB(DB_MASTER);
     $result = $dbw->select(array('flaggedrevs', 'revision'), array('fr_rev_id'), array('fr_page_id' => $oldPageID, 'fr_rev_id = rev_id', 'rev_page' => $newPageID), __METHOD__);
     # Update these rows
     $revIDs = array();
     foreach ($result as $row) {
         $revIDs[] = $row->fr_rev_id;
     }
     if (!empty($revIDs)) {
         $dbw->update('flaggedrevs', array('fr_page_id' => $newPageID), array('fr_page_id' => $oldPageID, 'fr_rev_id' => $revIDs), __METHOD__);
     }
     # Update pages...stable versions possibly lost to another page
     FlaggedRevs::stableVersionUpdates($sourceTitle);
     FlaggedRevs::HTMLCacheUpdates($sourceTitle);
     FlaggedRevs::stableVersionUpdates($destTitle);
     FlaggedRevs::HTMLCacheUpdates($destTitle);
     return true;
 }
Example #24
0
 /**
  * Move this page's subpages to be subpages of $nt
  *
  * @param Title $nt Move target
  * @param bool $auth Whether $wgUser's permissions should be checked
  * @param string $reason The reason for the move
  * @param bool $createRedirect Whether to create redirects from the old subpages to
  *     the new ones Ignored if the user doesn't have the 'suppressredirect' right
  * @return array Array with old page titles as keys, and strings (new page titles) or
  *     arrays (errors) as values, or an error array with numeric indices if no pages
  *     were moved
  */
 public function moveSubpages($nt, $auth = true, $reason = '', $createRedirect = true)
 {
     global $wgMaximumMovedPages;
     // Check permissions
     if (!$this->userCan('move-subpages')) {
         return array('cant-move-subpages');
     }
     // Do the source and target namespaces support subpages?
     if (!MWNamespace::hasSubpages($this->getNamespace())) {
         return array('namespace-nosubpages', MWNamespace::getCanonicalName($this->getNamespace()));
     }
     if (!MWNamespace::hasSubpages($nt->getNamespace())) {
         return array('namespace-nosubpages', MWNamespace::getCanonicalName($nt->getNamespace()));
     }
     $subpages = $this->getSubpages($wgMaximumMovedPages + 1);
     $retval = array();
     $count = 0;
     foreach ($subpages as $oldSubpage) {
         $count++;
         if ($count > $wgMaximumMovedPages) {
             $retval[$oldSubpage->getPrefixedText()] = array('movepage-max-pages', $wgMaximumMovedPages);
             break;
         }
         // We don't know whether this function was called before
         // or after moving the root page, so check both
         // $this and $nt
         if ($oldSubpage->getArticleID() == $this->getArticleID() || $oldSubpage->getArticleID() == $nt->getArticleID()) {
             // When moving a page to a subpage of itself,
             // don't move it twice
             continue;
         }
         $newPageName = preg_replace('#^' . preg_quote($this->getDBkey(), '#') . '#', StringUtils::escapeRegexReplacement($nt->getDBkey()), $oldSubpage->getDBkey());
         if ($oldSubpage->isTalkPage()) {
             $newNs = $nt->getTalkPage()->getNamespace();
         } else {
             $newNs = $nt->getSubjectPage()->getNamespace();
         }
         # Bug 14385: we need makeTitleSafe because the new page names may
         # be longer than 255 characters.
         $newSubpage = Title::makeTitleSafe($newNs, $newPageName);
         $success = $oldSubpage->moveTo($newSubpage, $auth, $reason, $createRedirect);
         if ($success === true) {
             $retval[$oldSubpage->getPrefixedText()] = $newSubpage->getPrefixedText();
         } else {
             $retval[$oldSubpage->getPrefixedText()] = $success;
         }
     }
     return $retval;
 }
Example #25
0
 /**
  * Returns page counts that would be too "expensive" to retrieve by normal means.
  *
  * @param Title $title Title to get counts for
  * @return array
  */
 protected function pageCounts(Title $title)
 {
     $id = $title->getArticleID();
     $config = $this->context->getConfig();
     $dbrWatchlist = wfGetDB(DB_SLAVE, 'watchlist');
     $result = array();
     // Number of page watchers
     $watchers = (int) $dbrWatchlist->selectField('watchlist', 'COUNT(*)', array('wl_namespace' => $title->getNamespace(), 'wl_title' => $title->getDBkey()), __METHOD__);
     $result['watchers'] = $watchers;
     if ($config->get('ShowUpdatedMarker')) {
         // Threshold: last visited about 26 weeks before latest edit
         $updated = wfTimestamp(TS_UNIX, $this->page->getTimestamp());
         $age = $config->get('WatchersMaxAge');
         $threshold = $dbrWatchlist->timestamp($updated - $age);
         // Number of page watchers who also visited a "recent" edit
         $visitingWatchers = (int) $dbrWatchlist->selectField('watchlist', 'COUNT(*)', array('wl_namespace' => $title->getNamespace(), 'wl_title' => $title->getDBkey(), 'wl_notificationtimestamp >= ' . $dbrWatchlist->addQuotes($threshold) . ' OR wl_notificationtimestamp IS NULL'), __METHOD__);
         $result['visitingWatchers'] = $visitingWatchers;
     }
     $dbr = wfGetDB(DB_SLAVE);
     // Total number of edits
     $edits = (int) $dbr->selectField('revision', 'COUNT(*)', array('rev_page' => $id), __METHOD__);
     $result['edits'] = $edits;
     // Total number of distinct authors
     if ($config->get('MiserMode')) {
         $result['authors'] = 0;
     } else {
         $result['authors'] = (int) $dbr->selectField('revision', 'COUNT(DISTINCT rev_user_text)', array('rev_page' => $id), __METHOD__);
     }
     // "Recent" threshold defined by RCMaxAge setting
     $threshold = $dbr->timestamp(time() - $config->get('RCMaxAge'));
     // Recent number of edits
     $edits = (int) $dbr->selectField('revision', 'COUNT(rev_page)', array('rev_page' => $id, "rev_timestamp >= " . $dbr->addQuotes($threshold)), __METHOD__);
     $result['recent_edits'] = $edits;
     // Recent number of distinct authors
     $result['recent_authors'] = (int) $dbr->selectField('revision', 'COUNT(DISTINCT rev_user_text)', array('rev_page' => $id, "rev_timestamp >= " . $dbr->addQuotes($threshold)), __METHOD__);
     // Subpages (if enabled)
     if (MWNamespace::hasSubpages($title->getNamespace())) {
         $conds = array('page_namespace' => $title->getNamespace());
         $conds[] = 'page_title ' . $dbr->buildLike($title->getDBkey() . '/', $dbr->anyString());
         // Subpages of this page (redirects)
         $conds['page_is_redirect'] = 1;
         $result['subpages']['redirects'] = (int) $dbr->selectField('page', 'COUNT(page_id)', $conds, __METHOD__);
         // Subpages of this page (non-redirects)
         $conds['page_is_redirect'] = 0;
         $result['subpages']['nonredirects'] = (int) $dbr->selectField('page', 'COUNT(page_id)', $conds, __METHOD__);
         // Subpages of this page (total)
         $result['subpages']['total'] = $result['subpages']['redirects'] + $result['subpages']['nonredirects'];
     }
     // Counts for the number of transclusion links (to/from)
     if ($config->get('MiserMode')) {
         $result['transclusion']['to'] = 0;
     } else {
         $result['transclusion']['to'] = (int) $dbr->selectField('templatelinks', 'COUNT(tl_from)', array('tl_namespace' => $title->getNamespace(), 'tl_title' => $title->getDBkey()), __METHOD__);
     }
     $result['transclusion']['from'] = (int) $dbr->selectField('templatelinks', 'COUNT(*)', array('tl_from' => $title->getArticleID()), __METHOD__);
     return $result;
 }
Example #26
0
 /**
  * Attempt submission (no UI)
  *
  * @param $result
  * @param $bot bool
  *
  * @return Status object, possibly with a message, but always with one of the AS_* constants in $status->value,
  *
  * 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 $wgFilterCallback, $wgUser, $wgRequest, $wgParser;
     global $wgMaxArticleSize;
     $status = Status::newGood();
     wfProfileIn(__METHOD__);
     wfProfileIn(__METHOD__ . '-checks');
     if (!wfRunHooks('EditPage::attemptSave', array($this))) {
         wfDebug("Hook 'EditPage::attemptSave' aborted article saving\n");
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     # Check image redirect
     if ($this->mTitle->getNamespace() == NS_FILE && Title::newFromRedirect($this->textbox1) instanceof Title && !$wgUser->isAllowed('upload')) {
         $code = $wgUser->isAnon() ? self::AS_IMAGE_REDIRECT_ANON : self::AS_IMAGE_REDIRECT_LOGGED;
         $status->setResult(false, $code);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     # Check for spam
     $match = self::matchSummarySpamRegex($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;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if ($wgFilterCallback && is_callable($wgFilterCallback) && $wgFilterCallback($this->mTitle, $this->textbox1, $this->section, $this->hookError, $this->summary)) {
         # Error messages or other handling should be performed by the filter function
         $status->setResult(false, self::AS_FILTERING);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if (!wfRunHooks('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;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         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;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         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);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         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);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if (!$wgUser->isAllowed('edit')) {
         if ($wgUser->isAnon()) {
             $status->setResult(false, self::AS_READ_ONLY_PAGE_ANON);
             wfProfileOut(__METHOD__ . '-checks');
             wfProfileOut(__METHOD__);
             return $status;
         } else {
             $status->fatal('readonlytext');
             $status->value = self::AS_READ_ONLY_PAGE_LOGGED;
             wfProfileOut(__METHOD__ . '-checks');
             wfProfileOut(__METHOD__);
             return $status;
         }
     }
     if (wfReadOnly()) {
         $status->fatal('readonlytext');
         $status->value = self::AS_READ_ONLY_PAGE;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if ($wgUser->pingLimiter()) {
         $status->fatal('actionthrottledtext');
         $status->value = self::AS_RATE_LIMITED;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         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);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     wfProfileOut(__METHOD__ . '-checks');
     # If article is new, insert it.
     $aid = $this->mTitle->getArticleID(Title::GAID_FOR_UPDATE);
     $new = $aid == 0;
     if ($new) {
         // Late check for create permission, just in case *PARANOIA*
         if (!$this->mTitle->userCan('create')) {
             $status->fatal('nocreatetext');
             $status->value = self::AS_NO_CREATE_PERMISSION;
             wfDebug(__METHOD__ . ": no create permission\n");
             wfProfileOut(__METHOD__);
             return $status;
         }
         # Don't save a new article if it's blank.
         if ($this->textbox1 == '') {
             $status->setResult(false, self::AS_BLANK_ARTICLE);
             wfProfileOut(__METHOD__);
             return $status;
         }
         // Run post-section-merge edit filter
         if (!wfRunHooks('EditFilterMerged', array($this, $this->textbox1, &$this->hookError, $this->summary))) {
             # Error messages etc. could be handled within the hook...
             $status->fatal('hookaborted');
             $status->value = self::AS_HOOK_ERROR;
             wfProfileOut(__METHOD__);
             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;
             wfProfileOut(__METHOD__);
             return $status;
         }
         # Handle the user preference to force summaries here. Check if it's not a redirect.
         if (!$this->allowBlankSummary && !Title::newFromRedirect($this->textbox1)) {
             if (md5($this->summary) == $this->autoSumm) {
                 $this->missingSummary = true;
                 $status->fatal('missingsummary');
                 // or 'missingcommentheader' if $section == 'new'. Blegh
                 $status->value = self::AS_SUMMARY_NEEDED;
                 wfProfileOut(__METHOD__);
                 return $status;
             }
         }
         $text = $this->textbox1;
         $result['sectionanchor'] = '';
         if ($this->section == 'new') {
             if ($this->sectiontitle !== '') {
                 // Insert the section title above the content.
                 $text = wfMsgForContent('newsectionheaderdefaultlevel', $this->sectiontitle) . "\n\n" . $text;
                 // Jump to the new section
                 $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText($this->sectiontitle);
                 // If no edit summary was specified, create one automatically from the section
                 // title and have it link to the new section. Otherwise, respect the summary as
                 // passed.
                 if ($this->summary === '') {
                     $cleanSectionTitle = $wgParser->stripSectionName($this->sectiontitle);
                     $this->summary = wfMsgForContent('newsectionsummary', $cleanSectionTitle);
                 }
             } elseif ($this->summary !== '') {
                 // Insert the section title above the content.
                 $text = wfMsgForContent('newsectionheaderdefaultlevel', $this->summary) . "\n\n" . $text;
                 // Jump to the new section
                 $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText($this->summary);
                 // Create a link to the new section from the edit summary.
                 $cleanSummary = $wgParser->stripSectionName($this->summary);
                 $this->summary = wfMsgForContent('newsectionsummary', $cleanSummary);
             }
         }
         $status->value = self::AS_SUCCESS_NEW_ARTICLE;
     } else {
         # 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->summary) {
                     // 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 == '' && $this->userWasLastToEdit($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 (for
         // backwards compatibility with old forms/bots).
         if ($this->sectiontitle !== '') {
             $sectionTitle = $this->sectiontitle;
         } else {
             $sectionTitle = $this->summary;
         }
         if ($this->isConflict) {
             wfDebug(__METHOD__ . ": conflict! getting section '{$this->section}' for time '{$this->edittime}' (article time '{$timestamp}')\n");
             $text = $this->mArticle->replaceSection($this->section, $this->textbox1, $sectionTitle, $this->edittime);
         } else {
             wfDebug(__METHOD__ . ": getting section '{$this->section}'\n");
             $text = $this->mArticle->replaceSection($this->section, $this->textbox1, $sectionTitle);
         }
         if (is_null($text)) {
             wfDebug(__METHOD__ . ": activating conflict; section replace failed.\n");
             $this->isConflict = true;
             $text = $this->textbox1;
             // do not try to merge here!
         } elseif ($this->isConflict) {
             # Attempt merge
             if ($this->mergeChangesInto($text)) {
                 // 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 = $text;
                 wfDebug(__METHOD__ . ": Keeping edit conflict, failed merge.\n");
             }
         }
         if ($this->isConflict) {
             $status->setResult(false, self::AS_CONFLICT_DETECTED);
             wfProfileOut(__METHOD__);
             return $status;
         }
         // Run post-section-merge edit filter
         if (!wfRunHooks('EditFilterMerged', array($this, $text, &$this->hookError, $this->summary))) {
             # Error messages etc. could be handled within the hook...
             $status->fatal('hookaborted');
             $status->value = self::AS_HOOK_ERROR;
             wfProfileOut(__METHOD__);
             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;
             wfProfileOut(__METHOD__);
             return $status;
         }
         # Handle the user preference to force summaries here, but not for null edits
         if ($this->section != 'new' && !$this->allowBlankSummary && $this->getOriginalContent() != $text && !Title::newFromRedirect($text)) {
             if (md5($this->summary) == $this->autoSumm) {
                 $this->missingSummary = true;
                 $status->fatal('missingsummary');
                 $status->value = self::AS_SUMMARY_NEEDED;
                 wfProfileOut(__METHOD__);
                 return $status;
             }
         }
         # And a similar thing for new sections
         if ($this->section == 'new' && !$this->allowBlankSummary) {
             if (trim($this->summary) == '') {
                 $this->missingSummary = true;
                 $status->fatal('missingsummary');
                 // or 'missingcommentheader' if $section == 'new'. Blegh
                 $status->value = self::AS_SUMMARY_NEEDED;
                 wfProfileOut(__METHOD__);
                 return $status;
             }
         }
         # All's well
         wfProfileIn(__METHOD__ . '-sectionanchor');
         $sectionanchor = '';
         if ($this->section == 'new') {
             if ($this->textbox1 == '') {
                 $this->missingComment = true;
                 $status->fatal('missingcommenttext');
                 $status->value = self::AS_TEXTBOX_EMPTY;
                 wfProfileOut(__METHOD__ . '-sectionanchor');
                 wfProfileOut(__METHOD__);
                 return $status;
             }
             if ($this->sectiontitle !== '') {
                 $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText($this->sectiontitle);
                 // If no edit summary was specified, create one automatically from the section
                 // title and have it link to the new section. Otherwise, respect the summary as
                 // passed.
                 if ($this->summary === '') {
                     $cleanSectionTitle = $wgParser->stripSectionName($this->sectiontitle);
                     $this->summary = wfMsgForContent('newsectionsummary', $cleanSectionTitle);
                 }
             } elseif ($this->summary !== '') {
                 $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText($this->summary);
                 # This is a new section, so create a link to the new section
                 # in the revision summary.
                 $cleanSummary = $wgParser->stripSectionName($this->summary);
                 $this->summary = wfMsgForContent('newsectionsummary', $cleanSummary);
             }
         } 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;
         wfProfileOut(__METHOD__ . '-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 = $text;
         $this->section = '';
         $status->value = self::AS_SUCCESS_UPDATE;
     }
     // Check for length errors again now that the section is merged in
     $this->kblength = (int) (strlen($text) / 1024);
     if ($this->kblength > $wgMaxArticleSize) {
         $this->tooBig = true;
         $status->setResult(false, self::AS_MAX_ARTICLE_SIZE_EXCEEDED);
         wfProfileOut(__METHOD__);
         return $status;
     }
     $flags = EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY | ($new ? EDIT_NEW : EDIT_UPDATE) | ($this->minoredit && !$this->isNew ? EDIT_MINOR : 0) | ($bot ? EDIT_FORCE_BOT : 0);
     $doEditStatus = $this->mArticle->doEdit($text, $this->summary, $flags);
     if ($doEditStatus->isOK()) {
         $result['redirect'] = Title::newFromRedirect($text) !== null;
         $this->commitWatch();
         wfProfileOut(__METHOD__);
         return $status;
     } else {
         $this->isConflict = true;
         $doEditStatus->value = self::AS_END;
         // Destroys data doEdit() put in $status->value but who cares
         wfProfileOut(__METHOD__);
         return $doEditStatus;
     }
 }
 /**
  * Constructs a RecentChange object for the given categorization
  * This does not call save() on the object and thus does not write to the db
  *
  * @since 1.27
  *
  * @param string $timestamp Timestamp of the recent change to occur
  * @param Title $categoryTitle Title of the category a page is being added to or removed from
  * @param User $user User object of the user that made the change
  * @param string $comment Change summary
  * @param Title $pageTitle Title of the page that is being added or removed
  * @param int $oldRevId Parent revision ID of this change
  * @param int $newRevId Revision ID of this change
  * @param string $lastTimestamp Parent revision timestamp of this change
  * @param bool $bot true, if the change was made by a bot
  * @param string $ip IP address of the user, if the change was made anonymously
  * @param int $deleted Indicates whether the change has been deleted
  *
  * @return RecentChange
  */
 public static function newForCategorization($timestamp, Title $categoryTitle, User $user = null, $comment, Title $pageTitle, $oldRevId, $newRevId, $lastTimestamp, $bot, $ip = '', $deleted = 0)
 {
     $rc = new RecentChange();
     $rc->mTitle = $categoryTitle;
     $rc->mPerformer = $user;
     $rc->mAttribs = array('rc_timestamp' => $timestamp, 'rc_namespace' => $categoryTitle->getNamespace(), 'rc_title' => $categoryTitle->getDBkey(), 'rc_type' => RC_CATEGORIZE, 'rc_source' => self::SRC_CATEGORIZE, 'rc_minor' => 0, 'rc_cur_id' => $pageTitle->getArticleID(), 'rc_user' => $user ? $user->getId() : 0, 'rc_user_text' => $user ? $user->getName() : '', 'rc_comment' => $comment, 'rc_this_oldid' => $newRevId, 'rc_last_oldid' => $oldRevId, 'rc_bot' => $bot ? 1 : 0, 'rc_ip' => self::checkIPAddress($ip), 'rc_patrolled' => 1, 'rc_new' => 0, 'rc_old_len' => 0, 'rc_new_len' => 0, 'rc_deleted' => $deleted, 'rc_logid' => 0, 'rc_log_type' => null, 'rc_log_action' => '', 'rc_params' => '');
     $rc->mExtra = array('prefixedDBkey' => $categoryTitle->getPrefixedDBkey(), 'lastTimestamp' => $lastTimestamp, 'oldSize' => 0, 'newSize' => 0, 'pageStatus' => 'changed');
     return $rc;
 }
Example #28
0
 /**
  * Store layers of a page to database. This will remove all previous layers
  * of that page from the database first.
  *
  * @since 3.0
  *
  * @param MapsLayerGroup $layerGroup contains all layers of the page.
  * @param Title $title the page title the layers are associated with.
  *
  * @return boolean
  */
 public static function storeLayers(MapsLayerGroup $layerGroup, Title $title)
 {
     // clear cache for this one:
     unset(self::$layerGroups[$title->getPrefixedDBkey()]);
     /*
      * create data for multiple row insert:
      */
     $pageId = $title->getArticleID();
     foreach ($layerGroup->getLayers() as $layer) {
         $dbLayers[] = self::databaseRowFromLayer($layer, $pageId);
     }
     /*
      * insert all layer rows of the page into database:
      */
     $db = wfGetDB(DB_MASTER);
     // delete old, stored layers first:
     $db->delete('maps_layers', array('layer_page_id' => $pageId), __METHOD__);
     if (empty($dbLayers)) {
         // empty group, nothing to insert
         return true;
     } else {
         // insert new rows:
         return $db->insert('maps_layers', $dbLayers, __METHOD__);
     }
 }
Example #29
0
 /**
  * Get geo data for articles from categories given title belongs to
  *
  * @param Title $title page title to get places from categories this title belongs to
  * @return array set of PlaceModel objects
  */
 public function getFromCategoriesByTitle(Title $title)
 {
     wfProfileIn(__METHOD__);
     // get article categories
     $dbr = $this->getDB();
     $res = $dbr->select('categorylinks', 'cl_to', array('cl_from' => $title->getArticleID()), __METHOD__);
     $categories = array();
     while ($row = $res->fetchObject()) {
         $categories[] = $row->cl_to;
     }
     $models = $this->getFromCategories($categories);
     wfProfileOut(__METHOD__);
     return $models;
 }
 /**
  * Get all non-hidden categories for a title.
  *
  * Kind of similar to title::getParentCategories.
  *
  * @param Title $title Which title to get the categories for.
  * @return Array of String's that are the (non-prefixed) db-keys of the cats.
  */
 private function getVisibleCategories(Title $title)
 {
     $dbr = wfGetDB(DB_SLAVE);
     $where = array('cl_from' => $title->getArticleID(), 'pp_propname' => null);
     $joins = array('page' => array('LEFT OUTER JOIN', array('page_namespace' => NS_CATEGORY, 'page_title=cl_to')), 'page_props' => array('LEFT OUTER JOIN', array('pp_page=page_id', 'pp_propname' => 'hiddencat')));
     $res = $dbr->select(array('categorylinks', 'page', 'page_props'), 'cl_to', $where, __METHOD__, array(), $joins);
     $finalResult = array();
     if ($res !== false) {
         foreach ($res as $row) {
             $finalResult[] = $row->cl_to;
         }
     }
     return $finalResult;
 }