Esempio n. 1
0
 /**
  * @param Content $content Pre-save transform content
  * @param integer $flags
  * @param User $user
  * @param string $summary
  * @param array $meta
  * @return Status
  * @throws DBUnexpectedError
  * @throws Exception
  * @throws FatalError
  * @throws MWException
  */
 private function doCreate(Content $content, $flags, User $user, $summary, array $meta)
 {
     global $wgUseRCPatrol, $wgUseNPPatrol;
     $status = Status::newGood(['new' => true, 'revision' => null]);
     $now = wfTimestampNow();
     $newsize = $content->getSize();
     $prepStatus = $content->prepareSave($this, $flags, $meta['oldId'], $user);
     $status->merge($prepStatus);
     if (!$status->isOK()) {
         return $status;
     }
     $dbw = wfGetDB(DB_MASTER);
     $dbw->startAtomic(__METHOD__);
     // Add the page record unless one already exists for the title
     $newid = $this->insertOn($dbw);
     if ($newid === false) {
         $dbw->endAtomic(__METHOD__);
         // nothing inserted
         $status->fatal('edit-already-exists');
         return $status;
         // nothing done
     }
     // At this point we are now comitted to returning an OK
     // status unless some DB query error or other exception comes up.
     // This way callers don't have to call rollback() if $status is bad
     // unless they actually try to catch exceptions (which is rare).
     // @TODO: pass content object?!
     $revision = new Revision(['page' => $newid, 'title' => $this->mTitle, 'comment' => $summary, 'minor_edit' => $meta['minor'], 'text' => $meta['serialized'], 'len' => $newsize, 'user' => $user->getId(), 'user_text' => $user->getName(), 'timestamp' => $now, 'content_model' => $content->getModel(), 'content_format' => $meta['serialFormat']]);
     // Save the revision text...
     $revisionId = $revision->insertOn($dbw);
     // Update the page record with revision data
     if (!$this->updateRevisionOn($dbw, $revision, 0)) {
         throw new MWException("Failed to update page row to use new revision.");
     }
     Hooks::run('NewRevisionFromEditComplete', [$this, $revision, false, $user]);
     // Update recentchanges
     if (!($flags & EDIT_SUPPRESS_RC)) {
         // Mark as patrolled if the user can do so
         $patrolled = ($wgUseRCPatrol || $wgUseNPPatrol) && !count($this->mTitle->getUserPermissionsErrors('autopatrol', $user));
         // Add RC row to the DB
         RecentChange::notifyNew($now, $this->mTitle, $revision->isMinor(), $user, $summary, $meta['bot'], '', $newsize, $revisionId, $patrolled, $meta['tags']);
     }
     $user->incEditCount();
     $dbw->endAtomic(__METHOD__);
     $this->mTimestamp = $now;
     // Return the new revision to the caller
     $status->value['revision'] = $revision;
     // Do secondary updates once the main changes have been committed...
     DeferredUpdates::addUpdate(new AtomicSectionUpdate($dbw, __METHOD__, function () use($revision, &$user, $content, $summary, &$flags, $meta, &$status) {
         // Update links, etc.
         $this->doEditUpdates($revision, $user, ['created' => true]);
         // Trigger post-create hook
         $params = [&$this, &$user, $content, $summary, $flags & EDIT_MINOR, null, null, &$flags, $revision];
         ContentHandler::runLegacyHooks('ArticleInsertComplete', $params, '1.21');
         Hooks::run('PageContentInsertComplete', $params);
         // Trigger post-save hook
         $params = array_merge($params, [&$status, $meta['baseRevId']]);
         ContentHandler::runLegacyHooks('ArticleSaveComplete', $params, '1.21');
         Hooks::run('PageContentSaveComplete', $params);
     }), DeferredUpdates::PRESEND);
     return $status;
 }
Esempio n. 2
0
	/**
	 * Change an existing article or create a new article. Updates RC and all necessary caches,
	 * optionally via the deferred update array.
	 *
	 * @param $content Content: new content
	 * @param string $summary edit summary
	 * @param $flags Integer bitfield:
	 *      EDIT_NEW
	 *          Article is known or assumed to be non-existent, create a new one
	 *      EDIT_UPDATE
	 *          Article is known or assumed to be pre-existing, update it
	 *      EDIT_MINOR
	 *          Mark this edit minor, if the user is allowed to do so
	 *      EDIT_SUPPRESS_RC
	 *          Do not log the change in recentchanges
	 *      EDIT_FORCE_BOT
	 *          Mark the edit a "bot" edit regardless of user rights
	 *      EDIT_DEFER_UPDATES
	 *          Defer some of the updates until the end of index.php
	 *      EDIT_AUTOSUMMARY
	 *          Fill in blank summaries with generated text where possible
	 *
	 * If neither EDIT_NEW nor EDIT_UPDATE is specified, the status of the article will be detected.
	 * If EDIT_UPDATE is specified and the article doesn't exist, the function will return an
	 * edit-gone-missing error. If EDIT_NEW is specified and the article does exist, an
	 * edit-already-exists error will be returned. These two conditions are also possible with
	 * auto-detection due to MediaWiki's performance-optimised locking strategy.
	 *
	 * @param bool|int $baseRevId the revision ID this edit was based off, if any
	 * @param $user User the user doing the edit
	 * @param $serialisation_format String: format for storing the content in the database
	 *
	 * @throws MWException
	 * @return Status object. Possible errors:
	 *     edit-hook-aborted:       The ArticleSave hook aborted the edit but didn't set the fatal flag of $status
	 *     edit-gone-missing:       In update mode, but the article didn't exist
	 *     edit-conflict:           In update mode, the article changed unexpectedly
	 *     edit-no-change:          Warning that the text was the same as before
	 *     edit-already-exists:     In creation mode, but the article already exists
	 *
	 *  Extensions may define additional errors.
	 *
	 *  $return->value will contain an associative array with members as follows:
	 *     new:                     Boolean indicating if the function attempted to create a new article
	 *     revision:                The revision object for the inserted revision, or null
	 *
	 * @since 1.21
	 */
	public function doEditContent( Content $content, $summary, $flags = 0, $baseRevId = false,
								   User $user = null, $serialisation_format = null ) {
		global $wgUser, $wgUseAutomaticEditSummaries, $wgUseRCPatrol, $wgUseNPPatrol;

		// Low-level sanity check
		if ( $this->mTitle->getText() === '' ) {
			throw new MWException( 'Something is trying to edit an article with an empty title' );
		}

		wfProfileIn( __METHOD__ );

		if ( !$content->getContentHandler()->canBeUsedOn( $this->getTitle() ) ) {
			wfProfileOut( __METHOD__ );
			return Status::newFatal( 'content-not-allowed-here',
				ContentHandler::getLocalizedName( $content->getModel() ),
				$this->getTitle()->getPrefixedText() );
		}

		$user = is_null( $user ) ? $wgUser : $user;
		$status = Status::newGood( array() );

		// Load the data from the master database if needed.
		// The caller may already loaded it from the master or even loaded it using
		// SELECT FOR UPDATE, so do not override that using clear().
		$this->loadPageData( 'fromdbmaster' );

		$flags = $this->checkFlags( $flags );

		// handle hook
		$hook_args = array( &$this, &$user, &$content, &$summary,
							$flags & EDIT_MINOR, null, null, &$flags, &$status );

		if ( !wfRunHooks( 'PageContentSave', $hook_args )
			|| !ContentHandler::runLegacyHooks( 'ArticleSave', $hook_args ) ) {

			wfDebug( __METHOD__ . ": ArticleSave or ArticleSaveContent hook aborted save!\n" );

			if ( $status->isOK() ) {
				$status->fatal( 'edit-hook-aborted' );
			}

			wfProfileOut( __METHOD__ );
			return $status;
		}

		// Silently ignore EDIT_MINOR if not allowed
		$isminor = ( $flags & EDIT_MINOR ) && $user->isAllowed( 'minoredit' );
		$bot = $flags & EDIT_FORCE_BOT;

		$old_content = $this->getContent( Revision::RAW ); // current revision's content

		$oldsize = $old_content ? $old_content->getSize() : 0;
		$oldid = $this->getLatest();
		$oldIsRedirect = $this->isRedirect();
		$oldcountable = $this->isCountable();

		$handler = $content->getContentHandler();

		// Provide autosummaries if one is not provided and autosummaries are enabled.
		if ( $wgUseAutomaticEditSummaries && $flags & EDIT_AUTOSUMMARY && $summary == '' ) {
			if ( !$old_content ) {
				$old_content = null;
			}
			$summary = $handler->getAutosummary( $old_content, $content, $flags );
		}

		$editInfo = $this->prepareContentForEdit( $content, null, $user, $serialisation_format );
		$serialized = $editInfo->pst;

		/**
		 * @var Content $content
		 */
		$content = $editInfo->pstContent;
		$newsize = $content->getSize();

		$dbw = wfGetDB( DB_MASTER );
		$now = wfTimestampNow();
		$this->mTimestamp = $now;

		if ( $flags & EDIT_UPDATE ) {
			// Update article, but only if changed.
			$status->value['new'] = false;

			if ( !$oldid ) {
				// Article gone missing
				wfDebug( __METHOD__ . ": EDIT_UPDATE specified but article doesn't exist\n" );
				$status->fatal( 'edit-gone-missing' );

				wfProfileOut( __METHOD__ );
				return $status;
			} elseif ( !$old_content ) {
				// Sanity check for bug 37225
				wfProfileOut( __METHOD__ );
				throw new MWException( "Could not find text for current revision {$oldid}." );
			}

			$revision = new Revision( array(
				'page'       => $this->getId(),
				'title'      => $this->getTitle(), // for determining the default content model
				'comment'    => $summary,
				'minor_edit' => $isminor,
				'text'       => $serialized,
				'len'        => $newsize,
				'parent_id'  => $oldid,
				'user'       => $user->getId(),
				'user_text'  => $user->getName(),
				'timestamp'  => $now,
				'content_model' => $content->getModel(),
				'content_format' => $serialisation_format,
			) ); // XXX: pass content object?!

			$changed = !$content->equals( $old_content );

			if ( $changed ) {
				if ( !$content->isValid() ) {
					wfProfileOut( __METHOD__ );
					throw new MWException( "New content failed validity check!" );
				}

				$dbw->begin( __METHOD__ );

				$prepStatus = $content->prepareSave( $this, $flags, $baseRevId, $user );
				$status->merge( $prepStatus );

				if ( !$status->isOK() ) {
					$dbw->rollback( __METHOD__ );

					wfProfileOut( __METHOD__ );
					return $status;
				}

				$revisionId = $revision->insertOn( $dbw );

				// Update page
				//
				// Note that we use $this->mLatest instead of fetching a value from the master DB
				// during the course of this function. This makes sure that EditPage can detect
				// edit conflicts reliably, either by $ok here, or by $article->getTimestamp()
				// before this function is called. A previous function used a separate query, this
				// creates a window where concurrent edits can cause an ignored edit conflict.
				$ok = $this->updateRevisionOn( $dbw, $revision, $oldid, $oldIsRedirect );

				if ( !$ok ) {
					// Belated edit conflict! Run away!!
					$status->fatal( 'edit-conflict' );

					$dbw->rollback( __METHOD__ );

					wfProfileOut( __METHOD__ );
					return $status;
				}

				wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $revision, $baseRevId, $user ) );
				// Update recentchanges
				if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
					// Mark as patrolled if the user can do so
					$patrolled = $wgUseRCPatrol && !count(
						$this->mTitle->getUserPermissionsErrors( 'autopatrol', $user ) );
					// Add RC row to the DB
					$rc = RecentChange::notifyEdit( $now, $this->mTitle, $isminor, $user, $summary,
						$oldid, $this->getTimestamp(), $bot, '', $oldsize, $newsize,
						$revisionId, $patrolled
					);

					// Log auto-patrolled edits
					if ( $patrolled ) {
						PatrolLog::record( $rc, true, $user );
					}
				}
				$user->incEditCount();
				$dbw->commit( __METHOD__ );
			} else {
				// Bug 32948: revision ID must be set to page {{REVISIONID}} and
				// related variables correctly
				$revision->setId( $this->getLatest() );
			}

			// Update links tables, site stats, etc.
			$this->doEditUpdates(
				$revision,
				$user,
				array(
					'changed' => $changed,
					'oldcountable' => $oldcountable
				)
			);

			if ( !$changed ) {
				$status->warning( 'edit-no-change' );
				$revision = null;
				// Update page_touched, this is usually implicit in the page update
				// Other cache updates are done in onArticleEdit()
				$this->mTitle->invalidateCache();
			}
		} else {
			// Create new article
			$status->value['new'] = true;

			$dbw->begin( __METHOD__ );

			$prepStatus = $content->prepareSave( $this, $flags, $baseRevId, $user );
			$status->merge( $prepStatus );

			if ( !$status->isOK() ) {
				$dbw->rollback( __METHOD__ );

				wfProfileOut( __METHOD__ );
				return $status;
			}

			$status->merge( $prepStatus );

			// Add the page record; stake our claim on this title!
			// This will return false if the article already exists
			$newid = $this->insertOn( $dbw );

			if ( $newid === false ) {
				$dbw->rollback( __METHOD__ );
				$status->fatal( 'edit-already-exists' );

				wfProfileOut( __METHOD__ );
				return $status;
			}

			// Save the revision text...
			$revision = new Revision( array(
				'page'       => $newid,
				'title'      => $this->getTitle(), // for determining the default content model
				'comment'    => $summary,
				'minor_edit' => $isminor,
				'text'       => $serialized,
				'len'        => $newsize,
				'user'       => $user->getId(),
				'user_text'  => $user->getName(),
				'timestamp'  => $now,
				'content_model' => $content->getModel(),
				'content_format' => $serialisation_format,
			) );
			$revisionId = $revision->insertOn( $dbw );

			// Bug 37225: use accessor to get the text as Revision may trim it
			$content = $revision->getContent(); // sanity; get normalized version

			if ( $content ) {
				$newsize = $content->getSize();
			}

			// Update the page record with revision data
			$this->updateRevisionOn( $dbw, $revision, 0 );

			wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $revision, false, $user ) );

			// Update recentchanges
			if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
				// Mark as patrolled if the user can do so
				$patrolled = ( $wgUseRCPatrol || $wgUseNPPatrol ) && !count(
					$this->mTitle->getUserPermissionsErrors( 'autopatrol', $user ) );
				// Add RC row to the DB
				$rc = RecentChange::notifyNew( $now, $this->mTitle, $isminor, $user, $summary, $bot,
					'', $newsize, $revisionId, $patrolled );

				// Log auto-patrolled edits
				if ( $patrolled ) {
					PatrolLog::record( $rc, true, $user );
				}
			}
			$user->incEditCount();
			$dbw->commit( __METHOD__ );

			// Update links, etc.
			$this->doEditUpdates( $revision, $user, array( 'created' => true ) );

			$hook_args = array( &$this, &$user, $content, $summary,
								$flags & EDIT_MINOR, null, null, &$flags, $revision );

			ContentHandler::runLegacyHooks( 'ArticleInsertComplete', $hook_args );
			wfRunHooks( 'PageContentInsertComplete', $hook_args );
		}

		// Do updates right now unless deferral was requested
		if ( !( $flags & EDIT_DEFER_UPDATES ) ) {
			DeferredUpdates::doUpdates();
		}

		// Return the new revision (or null) to the caller
		$status->value['revision'] = $revision;

		$hook_args = array( &$this, &$user, $content, $summary,
							$flags & EDIT_MINOR, null, null, &$flags, $revision, &$status, $baseRevId );

		ContentHandler::runLegacyHooks( 'ArticleSaveComplete', $hook_args );
		wfRunHooks( 'PageContentSaveComplete', $hook_args );

		// Promote user to any groups they meet the criteria for
		$user->addAutopromoteOnceGroups( 'onEdit' );

		wfProfileOut( __METHOD__ );
		return $status;
	}
Esempio n. 3
0
 /**
  * Article::doEdit()
  *
  * Change an existing article or create a new article. Updates RC and all necessary caches,
  * optionally via the deferred update array.
  *
  * $wgUser must be set before calling this function.
  *
  * @param $text String: new text
  * @param $summary String: edit summary
  * @param $flags Integer bitfield:
  *      EDIT_NEW
  *          Article is known or assumed to be non-existent, create a new one
  *      EDIT_UPDATE
  *          Article is known or assumed to be pre-existing, update it
  *      EDIT_MINOR
  *          Mark this edit minor, if the user is allowed to do so
  *      EDIT_SUPPRESS_RC
  *          Do not log the change in recentchanges
  *      EDIT_FORCE_BOT
  *          Mark the edit a "bot" edit regardless of user rights
  *      EDIT_DEFER_UPDATES
  *          Defer some of the updates until the end of index.php
  *      EDIT_AUTOSUMMARY
  *          Fill in blank summaries with generated text where possible
  *
  * If neither EDIT_NEW nor EDIT_UPDATE is specified, the status of the article will be detected.
  * If EDIT_UPDATE is specified and the article doesn't exist, the function will an
  * edit-gone-missing error. If EDIT_NEW is specified and the article does exist, an
  * edit-already-exists error will be returned. These two conditions are also possible with
  * auto-detection due to MediaWiki's performance-optimised locking strategy.
  *
  * @param $baseRevId the revision ID this edit was based off, if any
  * @param $user Optional user object, $wgUser will be used if not passed
  *
  * @return Status object. Possible errors:
  *     edit-hook-aborted:       The ArticleSave hook aborted the edit but didn't set the fatal flag of $status
  *     edit-gone-missing:       In update mode, but the article didn't exist
  *     edit-conflict:           In update mode, the article changed unexpectedly
  *     edit-no-change:          Warning that the text was the same as before
  *     edit-already-exists:     In creation mode, but the article already exists
  *
  *  Extensions may define additional errors.
  *
  *  $return->value will contain an associative array with members as follows:
  *     new:                     Boolean indicating if the function attempted to create a new article
  *     revision:                The revision object for the inserted revision, or null
  *
  *  Compatibility note: this function previously returned a boolean value indicating success/failure
  */
 public function doEdit($text, $summary, $flags = 0, $baseRevId = false, $user = null)
 {
     global $wgUser, $wgDBtransactions, $wgUseAutomaticEditSummaries;
     # Low-level sanity check
     if ($this->mTitle->getText() === '') {
         throw new MWException('Something is trying to edit an article with an empty title');
     }
     wfProfileIn(__METHOD__);
     $user = is_null($user) ? $wgUser : $user;
     $status = Status::newGood(array());
     # Load $this->mTitle->getArticleID() and $this->mLatest if it's not already
     $this->loadPageData();
     $flags = $this->checkFlags($flags);
     if (!wfRunHooks('ArticleSave', array(&$this, &$user, &$text, &$summary, $flags & EDIT_MINOR, null, null, &$flags, &$status))) {
         wfDebug(__METHOD__ . ": ArticleSave hook aborted save!\n");
         if ($status->isOK()) {
             $status->fatal('edit-hook-aborted');
         }
         wfProfileOut(__METHOD__);
         return $status;
     }
     # Silently ignore EDIT_MINOR if not allowed
     $isminor = $flags & EDIT_MINOR && $user->isAllowed('minoredit');
     $bot = $flags & EDIT_FORCE_BOT;
     $oldtext = $this->getRawText();
     // current revision
     $oldsize = strlen($oldtext);
     # Provide autosummaries if one is not provided and autosummaries are enabled.
     if ($wgUseAutomaticEditSummaries && $flags & EDIT_AUTOSUMMARY && $summary == '') {
         $summary = $this->getAutosummary($oldtext, $text, $flags);
     }
     $editInfo = $this->prepareTextForEdit($text);
     $text = $editInfo->pst;
     $newsize = strlen($text);
     $dbw = wfGetDB(DB_MASTER);
     $now = wfTimestampNow();
     $this->mTimestamp = $now;
     if ($flags & EDIT_UPDATE) {
         # Update article, but only if changed.
         $status->value['new'] = false;
         # Make sure the revision is either completely inserted or not inserted at all
         if (!$wgDBtransactions) {
             $userAbort = ignore_user_abort(true);
         }
         $changed = strcmp($text, $oldtext) != 0;
         if ($changed) {
             $this->mGoodAdjustment = (int) $this->isCountable($text) - (int) $this->isCountable($oldtext);
             $this->mTotalAdjustment = 0;
             if (!$this->mLatest) {
                 # Article gone missing
                 wfDebug(__METHOD__ . ": EDIT_UPDATE specified but article doesn't exist\n");
                 $status->fatal('edit-gone-missing');
                 wfProfileOut(__METHOD__);
                 return $status;
             }
             $revision = new Revision(array('page' => $this->getId(), 'comment' => $summary, 'minor_edit' => $isminor, 'text' => $text, 'parent_id' => $this->mLatest, 'user' => $user->getId(), 'user_text' => $user->getName()));
             $dbw->begin();
             $revisionId = $revision->insertOn($dbw);
             # Update page
             #
             # Note that we use $this->mLatest instead of fetching a value from the master DB
             # during the course of this function. This makes sure that EditPage can detect
             # edit conflicts reliably, either by $ok here, or by $article->getTimestamp()
             # before this function is called. A previous function used a separate query, this
             # creates a window where concurrent edits can cause an ignored edit conflict.
             $ok = $this->updateRevisionOn($dbw, $revision, $this->mLatest);
             if (!$ok) {
                 /* Belated edit conflict! Run away!! */
                 $status->fatal('edit-conflict');
                 # Delete the invalid revision if the DB is not transactional
                 if (!$wgDBtransactions) {
                     $dbw->delete('revision', array('rev_id' => $revisionId), __METHOD__);
                 }
                 $revisionId = 0;
                 $dbw->rollback();
             } else {
                 global $wgUseRCPatrol;
                 wfRunHooks('NewRevisionFromEditComplete', array($this, $revision, $baseRevId, $user));
                 # Update recentchanges
                 if (!($flags & EDIT_SUPPRESS_RC)) {
                     # Mark as patrolled if the user can do so
                     $patrolled = $wgUseRCPatrol && $this->mTitle->userCan('autopatrol');
                     # Add RC row to the DB
                     $rc = RecentChange::notifyEdit($now, $this->mTitle, $isminor, $user, $summary, $this->mLatest, $this->getTimestamp(), $bot, '', $oldsize, $newsize, $revisionId, $patrolled);
                     # Log auto-patrolled edits
                     if ($patrolled) {
                         PatrolLog::record($rc, true);
                     }
                 }
                 $user->incEditCount();
                 $dbw->commit();
             }
         } else {
             $status->warning('edit-no-change');
             $revision = null;
             // Keep the same revision ID, but do some updates on it
             $revisionId = $this->getRevIdFetched();
             // Update page_touched, this is usually implicit in the page update
             // Other cache updates are done in onArticleEdit()
             $this->mTitle->invalidateCache();
         }
         if (!$wgDBtransactions) {
             ignore_user_abort($userAbort);
         }
         // Now that ignore_user_abort is restored, we can respond to fatal errors
         if (!$status->isOK()) {
             wfProfileOut(__METHOD__);
             return $status;
         }
         # Invalidate cache of this article and all pages using this article
         # as a template. Partly deferred.
         Article::onArticleEdit($this->mTitle);
         # Update links tables, site stats, etc.
         $this->editUpdates($text, $summary, $isminor, $now, $revisionId, $changed);
     } else {
         # Create new article
         $status->value['new'] = true;
         # Set statistics members
         # We work out if it's countable after PST to avoid counter drift
         # when articles are created with {{subst:}}
         $this->mGoodAdjustment = (int) $this->isCountable($text);
         $this->mTotalAdjustment = 1;
         $dbw->begin();
         # Add the page record; stake our claim on this title!
         # This will return false if the article already exists
         $newid = $this->insertOn($dbw);
         if ($newid === false) {
             $dbw->rollback();
             $status->fatal('edit-already-exists');
             wfProfileOut(__METHOD__);
             return $status;
         }
         # Save the revision text...
         $revision = new Revision(array('page' => $newid, 'comment' => $summary, 'minor_edit' => $isminor, 'text' => $text, 'user' => $user->getId(), 'user_text' => $user->getName()));
         $revisionId = $revision->insertOn($dbw);
         $this->mTitle->resetArticleID($newid);
         # Update the page record with revision data
         $this->updateRevisionOn($dbw, $revision, 0);
         wfRunHooks('NewRevisionFromEditComplete', array($this, $revision, false, $user));
         # Update recentchanges
         if (!($flags & EDIT_SUPPRESS_RC)) {
             global $wgUseRCPatrol, $wgUseNPPatrol;
             # Mark as patrolled if the user can do so
             $patrolled = ($wgUseRCPatrol || $wgUseNPPatrol) && $this->mTitle->userCan('autopatrol');
             # Add RC row to the DB
             $rc = RecentChange::notifyNew($now, $this->mTitle, $isminor, $user, $summary, $bot, '', strlen($text), $revisionId, $patrolled);
             # Log auto-patrolled edits
             if ($patrolled) {
                 PatrolLog::record($rc, true);
             }
         }
         $user->incEditCount();
         $dbw->commit();
         # Update links, etc.
         $this->editUpdates($text, $summary, $isminor, $now, $revisionId, true);
         # Clear caches
         Article::onArticleCreate($this->mTitle);
         wfRunHooks('ArticleInsertComplete', array(&$this, &$user, $text, $summary, $flags & EDIT_MINOR, null, null, &$flags, $revision));
     }
     # Do updates right now unless deferral was requested
     if (!($flags & EDIT_DEFER_UPDATES)) {
         wfDoUpdates();
     }
     // Return the new revision (or null) to the caller
     $status->value['revision'] = $revision;
     wfRunHooks('ArticleSaveComplete', array(&$this, &$user, $text, $summary, $flags & EDIT_MINOR, null, null, &$flags, $revision, &$status, $baseRevId));
     wfProfileOut(__METHOD__);
     return $status;
 }
Esempio n. 4
0
 function insertNewArticle($article, $text, $summary, $isminor, $watchthis, $suppressRC = false, $comment = false)
 {
     global $wgOut, $wgUser;
     global $wgUseSquid, $wgDeferredUpdateList, $wgInternalServer;
     $fname = 'Article::insertNewArticle';
     wfProfileIn($fname);
     $article->mGoodAdjustment = $article->isCountable($text);
     $article->mTotalAdjustment = 1;
     $ns = $article->mTitle->getNamespace();
     $ttl = $article->mTitle->getDBkey();
     # If this is a comment, add the summary as headline
     if ($comment && $summary != "") {
         $text = "== {$summary} ==\n\n" . $text;
     }
     $text = $article->preSaveTransform($text);
     $isminor = $isminor && $wgUser->isLoggedIn() ? 1 : 0;
     $now = wfTimestampNow();
     $dbw =& wfGetDB(DB_MASTER);
     # Add the page record; stake our claim on this title!
     $newid = $article->insertOn($dbw);
     # Save the revision text...
     $revision = new Revision(array('page' => $newid, 'comment' => $summary, 'minor_edit' => $isminor, 'text' => $text));
     $revisionId = $revision->insertOn($dbw);
     $article->mTitle->resetArticleID($newid);
     # Update the page record with revision data
     $article->updateRevisionOn($dbw, $revision, 0);
     Article::onArticleCreate($article->mTitle);
     if (!$suppressRC) {
         RecentChange::notifyNew($now, $article->mTitle, $isminor, $wgUser, $summary, 'default', '', strlen($text), $revisionId);
     }
     if ($watchthis) {
         #if(!$article->mTitle->userIsWatching()) $this->watch($article);
         if (wfRunHooks('WatchArticle', array(&$wgUser, &$article))) {
             $wgUser->addWatch($article->mTitle);
             $wgUser->saveSettings();
             wfRunHooks('WatchArticleComplete', array(&$wgUser, &$article));
         }
     }
     # The talk page isn't in the regular link tables, so we need to update manually:
     $talkns = $ns ^ 1;
     # talk -> normal; normal -> talk
     $dbw->update('page', array('page_touched' => $dbw->timestamp($now)), array('page_namespace' => $talkns, 'page_title' => $ttl), $fname);
     # standard deferred updates
     $article->editUpdates($text, $summary, $isminor, $now, $revisionId);
     if ($this->mprotect == "yes") {
         # $this->mprotect
         # $this->mprotect_reason
         $id = $article->mTitle->getArticleID();
         $limit = 'sysop';
         $dbw->update('page', array('page_touched' => $dbw->timestamp(), 'page_restrictions' => (string) $limit), array('page_id' => $id), 'Article::protect');
         $restrictions = "move=" . $limit;
         $restrictions .= ":edit=" . $limit;
         if (!$moveonly) {
             #$restrictions .= ":edit=" . $limit;
         }
         if (wfRunHooks('ArticleProtect', array(&$article, &$wgUser, $limit == 'sysop', $this->mprotect_reason, $moveonly))) {
             $dbw =& wfGetDB(DB_MASTER);
             $dbw->update('page', array('page_touched' => $dbw->timestamp(), 'page_restrictions' => $restrictions), array('page_id' => $id), 'Article::protect');
             wfRunHooks('ArticleProtectComplete', array(&$article, &$wgUser, $limit == 'sysop', $this->mprotect_reason, $moveonly));
             $log = new LogPage('protect');
             $log->addEntry('protect', $article->mTitle, $this->mprotect_reason);
         }
     }
     # AWC - Edit
     # Dont want ot redirect...
     #$oldid = 0; # new article
     #$article->showArticle( $text, wfMsg( 'newarticle' ), false, $isminor, $now, $summary, $oldid );
     wfProfileOut($fname);
 }
Esempio n. 5
0
 /**
  * Article::doEdit()
  *
  * Change an existing article or create a new article. Updates RC and all necessary caches, 
  * optionally via the deferred update array.
  *
  * $wgUser must be set before calling this function.
  *
  * @param string $text New text
  * @param string $summary Edit summary
  * @param integer $flags bitfield:
  *      EDIT_NEW
  *          Article is known or assumed to be non-existent, create a new one
  *      EDIT_UPDATE
  *          Article is known or assumed to be pre-existing, update it
  *      EDIT_MINOR
  *          Mark this edit minor, if the user is allowed to do so
  *      EDIT_SUPPRESS_RC
  *          Do not log the change in recentchanges
  *      EDIT_FORCE_BOT
  *          Mark the edit a "bot" edit regardless of user rights
  *      EDIT_DEFER_UPDATES
  *          Defer some of the updates until the end of index.php
  *      EDIT_AUTOSUMMARY
  *          Fill in blank summaries with generated text where possible
  * 
  * If neither EDIT_NEW nor EDIT_UPDATE is specified, the status of the article will be detected. 
  * If EDIT_UPDATE is specified and the article doesn't exist, the function will return false. If 
  * EDIT_NEW is specified and the article does exist, a duplicate key error will cause an exception
  * to be thrown from the Database. These two conditions are also possible with auto-detection due
  * to MediaWiki's performance-optimised locking strategy.
  *
  * @return bool success
  */
 function doEdit($text, $summary, $flags = 0)
 {
     global $wgUser, $wgDBtransactions;
     wfProfileIn(__METHOD__);
     $good = true;
     if (!($flags & EDIT_NEW) && !($flags & EDIT_UPDATE)) {
         $aid = $this->mTitle->getArticleID(GAID_FOR_UPDATE);
         if ($aid) {
             $flags |= EDIT_UPDATE;
         } else {
             $flags |= EDIT_NEW;
         }
     }
     if (!wfRunHooks('ArticleSave', array(&$this, &$wgUser, &$text, &$summary, $flags & EDIT_MINOR, null, null, &$flags))) {
         wfDebug(__METHOD__ . ": ArticleSave hook aborted save!\n");
         wfProfileOut(__METHOD__);
         return false;
     }
     # Silently ignore EDIT_MINOR if not allowed
     $isminor = $flags & EDIT_MINOR && $wgUser->isAllowed('minoredit');
     $bot = $wgUser->isAllowed('bot') || $flags & EDIT_FORCE_BOT;
     $oldtext = $this->getContent();
     $oldsize = strlen($oldtext);
     # Provide autosummaries if one is not provided.
     if ($flags & EDIT_AUTOSUMMARY && $summary == '') {
         $summary = $this->getAutosummary($oldtext, $text, $flags);
     }
     $text = $this->preSaveTransform($text);
     $newsize = strlen($text);
     $dbw =& wfGetDB(DB_MASTER);
     $now = wfTimestampNow();
     if ($flags & EDIT_UPDATE) {
         # Update article, but only if changed.
         # Make sure the revision is either completely inserted or not inserted at all
         if (!$wgDBtransactions) {
             $userAbort = ignore_user_abort(true);
         }
         $lastRevision = 0;
         $revisionId = 0;
         if (0 != strcmp($text, $oldtext)) {
             $this->mGoodAdjustment = (int) $this->isCountable($text) - (int) $this->isCountable($oldtext);
             $this->mTotalAdjustment = 0;
             $lastRevision = $dbw->selectField('page', 'page_latest', array('page_id' => $this->getId()));
             if (!$lastRevision) {
                 # Article gone missing
                 wfDebug(__METHOD__ . ": EDIT_UPDATE specified but article doesn't exist\n");
                 wfProfileOut(__METHOD__);
                 return false;
             }
             $revision = new Revision(array('page' => $this->getId(), 'comment' => $summary, 'minor_edit' => $isminor, 'text' => $text));
             $dbw->begin();
             $revisionId = $revision->insertOn($dbw);
             # Update page
             $ok = $this->updateRevisionOn($dbw, $revision, $lastRevision);
             if (!$ok) {
                 /* Belated edit conflict! Run away!! */
                 $good = false;
                 $dbw->rollback();
             } else {
                 # Update recentchanges
                 if (!($flags & EDIT_SUPPRESS_RC)) {
                     $rcid = RecentChange::notifyEdit($now, $this->mTitle, $isminor, $wgUser, $summary, $lastRevision, $this->getTimestamp(), $bot, '', $oldsize, $newsize, $revisionId);
                     # Mark as patrolled if the user can do so
                     if ($wgUser->isAllowed('autopatrol')) {
                         RecentChange::markPatrolled($rcid);
                     }
                 }
                 $wgUser->incEditCount();
                 $dbw->commit();
             }
         } else {
             // Keep the same revision ID, but do some updates on it
             $revisionId = $this->getRevIdFetched();
             // Update page_touched, this is usually implicit in the page update
             // Other cache updates are done in onArticleEdit()
             $this->mTitle->invalidateCache();
         }
         if (!$wgDBtransactions) {
             ignore_user_abort($userAbort);
         }
         if ($good) {
             # Invalidate cache of this article and all pages using this article
             # as a template. Partly deferred.
             Article::onArticleEdit($this->mTitle);
             # Update links tables, site stats, etc.
             $changed = strcmp($oldtext, $text) != 0;
             $this->editUpdates($text, $summary, $isminor, $now, $revisionId, $changed);
         }
     } else {
         # Create new article
         # Set statistics members
         # We work out if it's countable after PST to avoid counter drift
         # when articles are created with {{subst:}}
         $this->mGoodAdjustment = (int) $this->isCountable($text);
         $this->mTotalAdjustment = 1;
         $dbw->begin();
         # Add the page record; stake our claim on this title!
         # This will fail with a database query exception if the article already exists
         $newid = $this->insertOn($dbw);
         # Save the revision text...
         $revision = new Revision(array('page' => $newid, 'comment' => $summary, 'minor_edit' => $isminor, 'text' => $text));
         $revisionId = $revision->insertOn($dbw);
         $this->mTitle->resetArticleID($newid);
         # Update the page record with revision data
         $this->updateRevisionOn($dbw, $revision, 0);
         if (!($flags & EDIT_SUPPRESS_RC)) {
             $rcid = RecentChange::notifyNew($now, $this->mTitle, $isminor, $wgUser, $summary, $bot, '', strlen($text), $revisionId);
             # Mark as patrolled if the user can
             if ($wgUser->isAllowed('autopatrol')) {
                 RecentChange::markPatrolled($rcid);
             }
         }
         $wgUser->incEditCount();
         $dbw->commit();
         # Update links, etc.
         $this->editUpdates($text, $summary, $isminor, $now, $revisionId, true);
         # Clear caches
         Article::onArticleCreate($this->mTitle);
         wfRunHooks('ArticleInsertComplete', array(&$this, &$wgUser, $text, $summary, $flags & EDIT_MINOR, null, null, &$flags));
     }
     if ($good && !($flags & EDIT_DEFER_UPDATES)) {
         wfDoUpdates();
     }
     wfRunHooks('ArticleSaveComplete', array(&$this, &$wgUser, $text, $summary, $flags & EDIT_MINOR, null, null, &$flags));
     wfProfileOut(__METHOD__);
     return $good;
 }
Esempio n. 6
0
 public function execute()
 {
     $userName = $this->getOption('user', false);
     $summary = $this->getOption('summary', 'Imported from text file');
     $useTimestamp = $this->hasOption('use-timestamp');
     $rc = $this->hasOption('rc');
     $bot = $this->hasOption('bot');
     $overwrite = $this->hasOption('overwrite');
     $prefix = $this->getOption('prefix', '');
     // Get all the arguments. A loop is required since Maintenance doesn't
     // support an arbitrary number of arguments.
     $files = [];
     $i = 0;
     while ($arg = $this->getArg($i++)) {
         if (file_exists($arg)) {
             $files[$arg] = file_get_contents($arg);
         } else {
             // use glob to support the Windows shell, which doesn't automatically
             // expand wildcards
             $found = false;
             foreach (glob($arg) as $filename) {
                 $found = true;
                 $files[$filename] = file_get_contents($filename);
             }
             if (!$found) {
                 $this->error("Fatal error: The file '{$arg}' does not exist!", 1);
             }
         }
     }
     $count = count($files);
     $this->output("Importing {$count} pages...\n");
     if ($userName === false) {
         $user = User::newSystemUser('Maintenance script', ['steal' => true]);
     } else {
         $user = User::newFromName($userName);
     }
     if (!$user) {
         $this->error("Invalid username\n", true);
     }
     if ($user->isAnon()) {
         $user->addToDatabase();
     }
     $exit = 0;
     $successCount = 0;
     $failCount = 0;
     $skipCount = 0;
     foreach ($files as $file => $text) {
         $pageName = $prefix . pathinfo($file, PATHINFO_FILENAME);
         $timestamp = $useTimestamp ? wfTimestamp(TS_UNIX, filemtime($file)) : wfTimestampNow();
         $title = Title::newFromText($pageName);
         // Have to check for # manually, since it gets interpreted as a fragment
         if (!$title || $title->hasFragment()) {
             $this->error("Invalid title {$pageName}. Skipping.\n");
             $skipCount++;
             continue;
         }
         $exists = $title->exists();
         $oldRevID = $title->getLatestRevID();
         $oldRev = $oldRevID ? Revision::newFromId($oldRevID) : null;
         $actualTitle = $title->getPrefixedText();
         if ($exists) {
             $touched = wfTimestamp(TS_UNIX, $title->getTouched());
             if (!$overwrite) {
                 $this->output("Title {$actualTitle} already exists. Skipping.\n");
                 $skipCount++;
                 continue;
             } elseif ($useTimestamp && intval($touched) >= intval($timestamp)) {
                 $this->output("File for title {$actualTitle} has not been modified since the " . "destination page was touched. Skipping.\n");
                 $skipCount++;
                 continue;
             }
         }
         $rev = new WikiRevision(ConfigFactory::getDefaultInstance()->makeConfig('main'));
         $rev->setText(rtrim($text));
         $rev->setTitle($title);
         $rev->setUserObj($user);
         $rev->setComment($summary);
         $rev->setTimestamp($timestamp);
         if ($exists && $overwrite && $rev->getContent()->equals($oldRev->getContent())) {
             $this->output("File for title {$actualTitle} contains no changes from the current " . "revision. Skipping.\n");
             $skipCount++;
             continue;
         }
         $status = $rev->importOldRevision();
         $newId = $title->getLatestRevID();
         if ($status) {
             $action = $exists ? 'updated' : 'created';
             $this->output("Successfully {$action} {$actualTitle}\n");
             $successCount++;
         } else {
             $action = $exists ? 'update' : 'create';
             $this->output("Failed to {$action} {$actualTitle}\n");
             $failCount++;
             $exit = 1;
         }
         // Create the RecentChanges entry if necessary
         if ($rc && $status) {
             if ($exists) {
                 if (is_object($oldRev)) {
                     $oldContent = $oldRev->getContent();
                     RecentChange::notifyEdit($timestamp, $title, $rev->getMinor(), $user, $summary, $oldRevID, $oldRev->getTimestamp(), $bot, '', $oldContent ? $oldContent->getSize() : 0, $rev->getContent()->getSize(), $newId, 1);
                 }
             } else {
                 RecentChange::notifyNew($timestamp, $title, $rev->getMinor(), $user, $summary, $bot, '', $rev->getContent()->getSize(), $newId, 1);
             }
         }
     }
     $this->output("Done! {$successCount} succeeded, {$skipCount} skipped.\n");
     if ($exit) {
         $this->error("Import failed with {$failCount} failed pages.\n", $exit);
     }
 }
Esempio n. 7
0
 /**
  * Change an existing article or create a new article. Updates RC and all necessary caches,
  * optionally via the deferred update array.
  *
  * @param Content $content New content
  * @param string $summary Edit summary
  * @param int $flags Bitfield:
  *      EDIT_NEW
  *          Article is known or assumed to be non-existent, create a new one
  *      EDIT_UPDATE
  *          Article is known or assumed to be pre-existing, update it
  *      EDIT_MINOR
  *          Mark this edit minor, if the user is allowed to do so
  *      EDIT_SUPPRESS_RC
  *          Do not log the change in recentchanges
  *      EDIT_FORCE_BOT
  *          Mark the edit a "bot" edit regardless of user rights
  *      EDIT_AUTOSUMMARY
  *          Fill in blank summaries with generated text where possible
  *
  * If neither EDIT_NEW nor EDIT_UPDATE is specified, the status of the
  * article will be detected. If EDIT_UPDATE is specified and the article
  * doesn't exist, the function will return an edit-gone-missing error. If
  * EDIT_NEW is specified and the article does exist, an edit-already-exists
  * error will be returned. These two conditions are also possible with
  * auto-detection due to MediaWiki's performance-optimised locking strategy.
  *
  * @param bool|int $baseRevId The revision ID this edit was based off, if any.
  *   This is not the parent revision ID, rather the revision ID for older
  *   content used as the source for a rollback, for example.
  * @param User $user The user doing the edit
  * @param string $serialFormat Format for storing the content in the
  *   database.
  *
  * @throws MWException
  * @return Status Possible errors:
  *     edit-hook-aborted: The ArticleSave hook aborted the edit but didn't
  *       set the fatal flag of $status.
  *     edit-gone-missing: In update mode, but the article didn't exist.
  *     edit-conflict: In update mode, the article changed unexpectedly.
  *     edit-no-change: Warning that the text was the same as before.
  *     edit-already-exists: In creation mode, but the article already exists.
  *
  *  Extensions may define additional errors.
  *
  *  $return->value will contain an associative array with members as follows:
  *     new: Boolean indicating if the function attempted to create a new article.
  *     revision: The revision object for the inserted revision, or null.
  *
  * @since 1.21
  * @throws MWException
  */
 public function doEditContent(Content $content, $summary, $flags = 0, $baseRevId = false, User $user = null, $serialFormat = null)
 {
     global $wgUser, $wgUseAutomaticEditSummaries, $wgUseRCPatrol, $wgUseNPPatrol;
     // Low-level sanity check
     if ($this->mTitle->getText() === '') {
         throw new MWException('Something is trying to edit an article with an empty title');
     }
     if (!$content->getContentHandler()->canBeUsedOn($this->getTitle())) {
         return Status::newFatal('content-not-allowed-here', ContentHandler::getLocalizedName($content->getModel()), $this->getTitle()->getPrefixedText());
     }
     $user = is_null($user) ? $wgUser : $user;
     $status = Status::newGood(array());
     // Load the data from the master database if needed.
     // The caller may already loaded it from the master or even loaded it using
     // SELECT FOR UPDATE, so do not override that using clear().
     $this->loadPageData('fromdbmaster');
     $flags = $this->checkFlags($flags);
     // handle hook
     $hook_args = array(&$this, &$user, &$content, &$summary, $flags & EDIT_MINOR, null, null, &$flags, &$status);
     if (!Hooks::run('PageContentSave', $hook_args) || !ContentHandler::runLegacyHooks('ArticleSave', $hook_args)) {
         wfDebug(__METHOD__ . ": ArticleSave or ArticleSaveContent hook aborted save!\n");
         if ($status->isOK()) {
             $status->fatal('edit-hook-aborted');
         }
         return $status;
     }
     // Silently ignore EDIT_MINOR if not allowed
     $isminor = $flags & EDIT_MINOR && $user->isAllowed('minoredit');
     $bot = $flags & EDIT_FORCE_BOT;
     $old_revision = $this->getRevision();
     // current revision
     $old_content = $this->getContent(Revision::RAW);
     // current revision's content
     $oldsize = $old_content ? $old_content->getSize() : 0;
     $oldid = $this->getLatest();
     $oldIsRedirect = $this->isRedirect();
     $oldcountable = $this->isCountable();
     $handler = $content->getContentHandler();
     // Provide autosummaries if one is not provided and autosummaries are enabled.
     if ($wgUseAutomaticEditSummaries && $flags & EDIT_AUTOSUMMARY && $summary == '') {
         if (!$old_content) {
             $old_content = null;
         }
         $summary = $handler->getAutosummary($old_content, $content, $flags);
     }
     $editInfo = $this->prepareContentForEdit($content, null, $user, $serialFormat);
     $serialized = $editInfo->pst;
     /**
      * @var Content $content
      */
     $content = $editInfo->pstContent;
     $newsize = $content->getSize();
     $dbw = wfGetDB(DB_MASTER);
     $now = wfTimestampNow();
     if ($flags & EDIT_UPDATE) {
         // Update article, but only if changed.
         $status->value['new'] = false;
         if (!$oldid) {
             // Article gone missing
             wfDebug(__METHOD__ . ": EDIT_UPDATE specified but article doesn't exist\n");
             $status->fatal('edit-gone-missing');
             return $status;
         } elseif (!$old_content) {
             // Sanity check for bug 37225
             throw new MWException("Could not find text for current revision {$oldid}.");
         }
         $revision = new Revision(array('page' => $this->getId(), 'title' => $this->getTitle(), 'comment' => $summary, 'minor_edit' => $isminor, 'text' => $serialized, 'len' => $newsize, 'parent_id' => $oldid, 'user' => $user->getId(), 'user_text' => $user->getName(), 'timestamp' => $now, 'content_model' => $content->getModel(), 'content_format' => $serialFormat));
         // XXX: pass content object?!
         $changed = !$content->equals($old_content);
         if ($changed) {
             $prepStatus = $content->prepareSave($this, $flags, $oldid, $user);
             $status->merge($prepStatus);
             if (!$status->isOK()) {
                 return $status;
             }
             $dbw->begin(__METHOD__);
             // Get the latest page_latest value while locking it.
             // Do a CAS style check to see if it's the same as when this method
             // started. If it changed then bail out before touching the DB.
             $latestNow = $this->lockAndGetLatest();
             if ($latestNow != $oldid) {
                 $dbw->commit(__METHOD__);
                 // Page updated or deleted in the mean time
                 $status->fatal('edit-conflict');
                 return $status;
             }
             // At this point we are now comitted to returning an OK
             // status unless some DB query error or other exception comes up.
             // This way callers don't have to call rollback() if $status is bad
             // unless they actually try to catch exceptions (which is rare).
             $revisionId = $revision->insertOn($dbw);
             // Update page_latest and friends to reflect the new revision
             if (!$this->updateRevisionOn($dbw, $revision, null, $oldIsRedirect)) {
                 $dbw->rollback(__METHOD__);
                 throw new MWException("Failed to update page row to use new revision.");
             }
             Hooks::run('NewRevisionFromEditComplete', array($this, $revision, $baseRevId, $user));
             // Update recentchanges
             if (!($flags & EDIT_SUPPRESS_RC)) {
                 // Mark as patrolled if the user can do so
                 $patrolled = $wgUseRCPatrol && !count($this->mTitle->getUserPermissionsErrors('autopatrol', $user));
                 // Add RC row to the DB
                 RecentChange::notifyEdit($now, $this->mTitle, $isminor, $user, $summary, $oldid, $this->getTimestamp(), $bot, '', $oldsize, $newsize, $revisionId, $patrolled);
             }
             $user->incEditCount();
             $dbw->commit(__METHOD__);
             $this->mTimestamp = $now;
         } else {
             // Bug 32948: revision ID must be set to page {{REVISIONID}} and
             // related variables correctly
             $revision->setId($this->getLatest());
         }
         // Update links tables, site stats, etc.
         $this->doEditUpdates($revision, $user, array('changed' => $changed, 'oldcountable' => $oldcountable, 'oldrevision' => $old_revision));
         if (!$changed) {
             $status->warning('edit-no-change');
             $revision = null;
             // Update page_touched, this is usually implicit in the page update
             // Other cache updates are done in onArticleEdit()
             $this->mTitle->invalidateCache($now);
         }
     } else {
         // Create new article
         $status->value['new'] = true;
         $prepStatus = $content->prepareSave($this, $flags, $oldid, $user);
         $status->merge($prepStatus);
         if (!$status->isOK()) {
             return $status;
         }
         $dbw->begin(__METHOD__);
         // Add the page record unless one already exists for the title
         $newid = $this->insertOn($dbw);
         if ($newid === false) {
             $dbw->commit(__METHOD__);
             // nothing inserted
             $status->fatal('edit-already-exists');
             return $status;
             // nothing done
         }
         // At this point we are now comitted to returning an OK
         // status unless some DB query error or other exception comes up.
         // This way callers don't have to call rollback() if $status is bad
         // unless they actually try to catch exceptions (which is rare).
         // Save the revision text...
         $revision = new Revision(array('page' => $newid, 'title' => $this->getTitle(), 'comment' => $summary, 'minor_edit' => $isminor, 'text' => $serialized, 'len' => $newsize, 'user' => $user->getId(), 'user_text' => $user->getName(), 'timestamp' => $now, 'content_model' => $content->getModel(), 'content_format' => $serialFormat));
         $revisionId = $revision->insertOn($dbw);
         // Bug 37225: use accessor to get the text as Revision may trim it
         $content = $revision->getContent();
         // sanity; get normalized version
         if ($content) {
             $newsize = $content->getSize();
         }
         // Update the page record with revision data
         if (!$this->updateRevisionOn($dbw, $revision, 0)) {
             $dbw->rollback(__METHOD__);
             throw new MWException("Failed to update page row to use new revision.");
         }
         Hooks::run('NewRevisionFromEditComplete', array($this, $revision, false, $user));
         // Update recentchanges
         if (!($flags & EDIT_SUPPRESS_RC)) {
             // Mark as patrolled if the user can do so
             $patrolled = ($wgUseRCPatrol || $wgUseNPPatrol) && !count($this->mTitle->getUserPermissionsErrors('autopatrol', $user));
             // Add RC row to the DB
             RecentChange::notifyNew($now, $this->mTitle, $isminor, $user, $summary, $bot, '', $newsize, $revisionId, $patrolled);
         }
         $user->incEditCount();
         $dbw->commit(__METHOD__);
         $this->mTimestamp = $now;
         // Update links, etc.
         $this->doEditUpdates($revision, $user, array('created' => true, 'oldrevision' => $old_revision));
         $hook_args = array(&$this, &$user, $content, $summary, $flags & EDIT_MINOR, null, null, &$flags, $revision);
         ContentHandler::runLegacyHooks('ArticleInsertComplete', $hook_args);
         Hooks::run('PageContentInsertComplete', $hook_args);
     }
     // Return the new revision (or null) to the caller
     $status->value['revision'] = $revision;
     $hook_args = array(&$this, &$user, $content, $summary, $flags & EDIT_MINOR, null, null, &$flags, $revision, &$status, $baseRevId);
     ContentHandler::runLegacyHooks('ArticleSaveComplete', $hook_args);
     Hooks::run('PageContentSaveComplete', $hook_args);
     // Promote user to any groups they meet the criteria for
     DeferredUpdates::addCallableUpdate(function () use($user) {
         $user->addAutopromoteOnceGroups('onEdit');
         $user->addAutopromoteOnceGroups('onView');
         // b/c
     });
     return $status;
 }
Esempio n. 8
0
 /**
  * Theoretically we could defer these whole insert and update
  * functions for after display, but that's taking a big leap
  * of faith, and we want to be able to report database
  * errors at some point.
  * @private
  */
 function insertNewArticle($text, $summary, $isminor, $watchthis, $suppressRC = false, $comment = false)
 {
     global $wgOut, $wgUser;
     global $wgUseSquid, $wgDeferredUpdateList, $wgInternalServer;
     $fname = 'Article::insertNewArticle';
     wfProfileIn($fname);
     $this->mGoodAdjustment = $this->isCountable($text);
     $this->mTotalAdjustment = 1;
     $ns = $this->mTitle->getNamespace();
     $ttl = $this->mTitle->getDBkey();
     # If this is a comment, add the summary as headline
     if ($comment && $summary != "") {
         $text = "== {$summary} ==\n\n" . $text;
     }
     $text = $this->preSaveTransform($text);
     $isminor = $isminor && $wgUser->isLoggedIn() ? 1 : 0;
     $now = wfTimestampNow();
     $dbw =& wfGetDB(DB_MASTER);
     # Add the page record; stake our claim on this title!
     $newid = $this->insertOn($dbw);
     # Save the revision text...
     $revision = new Revision(array('page' => $newid, 'comment' => $summary, 'minor_edit' => $isminor, 'text' => $text));
     $revisionId = $revision->insertOn($dbw);
     $this->mTitle->resetArticleID($newid);
     # Update the page record with revision data
     $this->updateRevisionOn($dbw, $revision, 0);
     Article::onArticleCreate($this->mTitle);
     if ($watchthis) {
         if (!$this->mTitle->userIsWatching()) {
             $this->watch();
         }
     } else {
         if ($this->mTitle->userIsWatching()) {
             $this->unwatch();
         }
     }
     # The talk page isn't in the regular link tables, so we need to update manually:
     $talkns = $ns ^ 1;
     # talk -> normal; normal -> talk
     $dbw->update('page', array('page_touched' => $dbw->timestamp($now)), array('page_namespace' => $talkns, 'page_title' => $ttl), $fname);
     # standard deferred updates
     $this->editUpdates($text);
     # TG PATCH. Moved from some lines above to here
     # Is important to call RecentChange::notifyNew _after_ editUpdates
     # because a user_newtalk flag and addwatch might be committed in editUpdates
     # which triggers the sending of an Enotif in RecentChange::notifyNew just right now
     if (!$suppressRC) {
         RecentChange::notifyNew($now, $this->mTitle, $isminor, $wgUser, $summary, 'default', '', strlen($text), $revisionId);
     }
     $oldid = 0;
     # new article
     $this->showArticle($text, wfMsg('newarticle'), false);
     wfProfileOut($fname);
 }
 /**
  * Duplicate one page to another, including full histories
  * Does some basic error-catching, but not as much as the code above [should]
  *
  * @param $source Title to duplicate
  * @param $dest Title to save to
  * @return bool
  */
 private function duplicate(&$source, &$dest)
 {
     global $wgUser, $wgBot;
     if (!$source->exists() || $dest->exists()) {
         return false;
     }
     # Source doesn't exist, or destination does
     $dbw = wfGetDB(DB_MASTER);
     $dbw->begin();
     $sid = $source->getArticleId();
     # Create an article representing the destination page and save it
     $destArticle = new Article($dest);
     $aid = $destArticle->insertOn($dbw);
     # Perform the revision duplication
     # An INSERT...SELECT here seems to f**k things up
     $res = $dbw->select('revision', '*', array('rev_page' => $sid), __METHOD__);
     if ($res && $dbw->numRows($res) > 0) {
         while ($row = $dbw->fetchObject($res)) {
             $values['rev_page'] = $aid;
             $values['rev_text_id'] = $row->rev_text_id;
             $values['rev_comment'] = $row->rev_comment;
             $values['rev_user'] = $row->rev_user;
             $values['rev_user_text'] = $row->rev_user_text;
             $values['rev_timestamp'] = $row->rev_timestamp;
             $values['rev_minor_edit'] = $row->rev_minor_edit;
             $values['rev_deleted'] = $row->rev_deleted;
             $dbw->insert('revision', $values, __METHOD__);
         }
         $dbw->freeResult($res);
     }
     # Update page record
     $latest = $dbw->selectField('revision', 'MAX(rev_id)', array('rev_page' => $aid), __METHOD__);
     $rev = Revision::newFromId($latest);
     $destArticle->updateRevisionOn($dbw, $rev);
     # Commit transaction
     $dbw->commit();
     # Create a null revision with an explanation; do cache clearances, etc.
     $dbw->begin();
     $comment = wfMsgForContent('duplicator-summary', $source->getPrefixedText());
     $nr = Revision::newNullRevision($dbw, $aid, $comment, true);
     $nid = $nr->insertOn($dbw);
     $destArticle->updateRevisionOn($dbw, $nr);
     $destArticle->createUpdates($nr);
     Article::onArticleCreate($dest);
     $bot = $wgUser->isAllowed('bot');
     RecentChange::notifyNew($nr->getTimestamp(), $dest, true, $wgUser, $comment, $bot);
     $dest->invalidateCache();
     $dbw->commit();
     return true;
 }