use Wikimedia\Assert\Assert;
use Wikimedia\Rdbms\FakeResultWrapper;
use Wikimedia\Rdbms\IDatabase;
-use Wikimedia\Rdbms\DBError;
use Wikimedia\Rdbms\DBUnexpectedError;
/**
$dbr = wfGetDB( DB_REPLICA );
- $tables = [ 'revision', 'user' ];
+ $actorMigration = ActorMigration::newMigration();
+ $actorQuery = $actorMigration->getJoin( 'rev_user' );
+
+ $tables = array_merge( [ 'revision' ], $actorQuery['tables'], [ 'user' ] );
$fields = [
- 'user_id' => 'rev_user',
- 'user_name' => 'rev_user_text',
+ 'user_id' => $actorQuery['fields']['rev_user'],
+ 'user_name' => $actorQuery['fields']['rev_user_text'],
+ 'actor_id' => $actorQuery['fields']['rev_actor'],
'user_real_name' => 'MIN(user_real_name)',
'timestamp' => 'MAX(rev_timestamp)',
];
// The user who made the top revision gets credited as "this page was last edited by
// John, based on contributions by Tom, Dick and Harry", so don't include them twice.
- $user = $this->getUser();
- if ( $user ) {
- $conds[] = "rev_user != $user";
- } else {
- $conds[] = "rev_user_text != {$dbr->addQuotes( $this->getUserText() )}";
- }
+ $user = $this->getUser()
+ ? User::newFromId( $this->getUser() )
+ : User::newFromName( $this->getUserText(), false );
+ $conds[] = 'NOT(' . $actorMigration->getWhere( $dbr, 'rev_user', $user )['conds'] . ')';
// Username hidden?
$conds[] = "{$dbr->bitAnd( 'rev_deleted', Revision::DELETED_USER )} = 0";
$jconds = [
- 'user' => [ 'LEFT JOIN', 'rev_user = user_id' ],
- ];
+ 'user' => [ 'LEFT JOIN', $actorQuery['fields']['rev_user'] . ' = user_id' ],
+ ] + $actorQuery['joins'];
$options = [
- 'GROUP BY' => [ 'rev_user', 'rev_user_text' ],
+ 'GROUP BY' => [ $fields['user_id'], $fields['user_name'] ],
'ORDER BY' => 'timestamp DESC',
];
return;
}
- Hooks::run( 'PageViewUpdates', [ $this, $user ] );
- // Update newtalk / watchlist notification status
- try {
- $user->clearNotification( $this->mTitle, $oldid );
- } catch ( DBError $e ) {
- // Avoid outage if the master is not reachable
- MWExceptionHandler::logException( $e );
- }
+ // Update newtalk / watchlist notification status;
+ // Avoid outage if the master is not reachable by using a deferred updated
+ DeferredUpdates::addCallableUpdate(
+ function () use ( $user, $oldid ) {
+ Hooks::run( 'PageViewUpdates', [ $this, $user ] );
+
+ $user->clearNotification( $this->mTitle, $oldid );
+ },
+ DeferredUpdates::PRESEND
+ );
}
/**
throw new MWException( "Failed to update page row to use new revision." );
}
+ $tags = $meta['tags'];
Hooks::run( 'NewRevisionFromEditComplete',
- [ $this, $revision, $meta['baseRevId'], $user ] );
+ [ $this, $revision, $meta['baseRevId'], $user, &$tags ] );
// Update recentchanges
if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
// Mark as patrolled if the user can do so
- $patrolled = $wgUseRCPatrol && !count(
+ $autopatrolled = $wgUseRCPatrol && !count(
$this->mTitle->getUserPermissionsErrors( 'autopatrol', $user ) );
// Add RC row to the DB
RecentChange::notifyEdit(
$oldContent ? $oldContent->getSize() : 0,
$newsize,
$revisionId,
- $patrolled,
- $meta['tags']
+ $autopatrolled ? RecentChange::PRC_AUTOPATROLLED :
+ RecentChange::PRC_UNPATROLLED,
+ $tags
);
}
* @param int $u1 Unused
* @param bool $u2 Unused
* @param array|string &$error Array of errors to append to
- * @param User $user The deleting user
+ * @param User $deleter The deleting user
* @param array $tags Tags to apply to the deletion action
* @param string $logsubtype
* @return Status Status object; if successful, $status->value is the log_id of the
* found, $status is a non-fatal 'cannotdelete' error
*/
public function doDeleteArticleReal(
- $reason, $suppress = false, $u1 = null, $u2 = null, &$error = '', User $user = null,
+ $reason, $suppress = false, $u1 = null, $u2 = null, &$error = '', User $deleter = null,
$tags = [], $logsubtype = 'delete'
) {
- global $wgUser, $wgContentHandlerUseDB, $wgCommentTableSchemaMigrationStage;
+ global $wgUser, $wgContentHandlerUseDB, $wgCommentTableSchemaMigrationStage,
+ $wgActorTableSchemaMigrationStage;
wfDebug( __METHOD__ . "\n" );
// Avoid PHP 7.1 warning of passing $this by reference
$wikiPage = $this;
- $user = is_null( $user ) ? $wgUser : $user;
+ $deleter = is_null( $deleter ) ? $wgUser : $deleter;
if ( !Hooks::run( 'ArticleDelete',
- [ &$wikiPage, &$user, &$reason, &$error, &$status, $suppress ]
+ [ &$wikiPage, &$deleter, &$reason, &$error, &$status, $suppress ]
) ) {
if ( $status->isOK() ) {
// Hook aborted but didn't set a fatal status
}
$commentStore = CommentStore::getStore();
+ $actorMigration = ActorMigration::newMigration();
$revQuery = Revision::getQueryInfo();
$bitfield = false;
foreach ( $res as $row ) {
$comment = $commentStore->getComment( 'rev_comment', $row );
+ $user = User::newFromAnyId( $row->rev_user, $row->rev_user_text, $row->rev_actor );
$rowInsert = [
'ar_namespace' => $namespace,
'ar_title' => $dbKey,
- 'ar_user' => $row->rev_user,
- 'ar_user_text' => $row->rev_user_text,
'ar_timestamp' => $row->rev_timestamp,
'ar_minor_edit' => $row->rev_minor_edit,
'ar_rev_id' => $row->rev_id,
'ar_page_id' => $id,
'ar_deleted' => $suppress ? $bitfield : $row->rev_deleted,
'ar_sha1' => $row->rev_sha1,
- ] + $commentStore->insert( $dbw, 'ar_comment', $comment );
+ ] + $commentStore->insert( $dbw, 'ar_comment', $comment )
+ + $actorMigration->getInsertValues( $dbw, 'ar_user', $user );
if ( $wgContentHandlerUseDB ) {
$rowInsert['ar_content_model'] = $row->rev_content_model;
$rowInsert['ar_content_format'] = $row->rev_content_format;
if ( $wgCommentTableSchemaMigrationStage > MIGRATION_OLD ) {
$dbw->delete( 'revision_comment_temp', [ 'revcomment_rev' => $revids ], __METHOD__ );
}
+ if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+ $dbw->delete( 'revision_actor_temp', [ 'revactor_rev' => $revids ], __METHOD__ );
+ }
// Also delete records from ip_changes as applicable.
if ( count( $ipRevIds ) > 0 ) {
$logtype = $suppress ? 'suppress' : 'delete';
$logEntry = new ManualLogEntry( $logtype, $logsubtype );
- $logEntry->setPerformer( $user );
+ $logEntry->setPerformer( $deleter );
$logEntry->setTarget( $logTitle );
$logEntry->setComment( $reason );
$logEntry->setTags( $tags );
$dbw->endAtomic( __METHOD__ );
- $this->doDeleteUpdates( $id, $content, $revision, $user );
+ $this->doDeleteUpdates( $id, $content, $revision, $deleter );
Hooks::run( 'ArticleDeleteComplete', [
&$wikiPageBeforeDelete,
- &$user,
+ &$deleter,
$reason,
$id,
$content,
// Get the last edit not by this person...
// Note: these may not be public values
- $user = intval( $current->getUser( Revision::RAW ) );
- $user_text = $dbw->addQuotes( $current->getUserText( Revision::RAW ) );
- $s = $dbw->selectRow( 'revision',
+ $userId = intval( $current->getUser( Revision::RAW ) );
+ $userName = $current->getUserText( Revision::RAW );
+ if ( $userId ) {
+ $user = User::newFromId( $userId );
+ $user->setName( $userName );
+ } else {
+ $user = User::newFromName( $current->getUserText( Revision::RAW ), false );
+ }
+
+ $actorWhere = ActorMigration::newMigration()->getWhere( $dbw, 'rev_user', $user );
+
+ $s = $dbw->selectRow(
+ [ 'revision' ] + $actorWhere['tables'],
[ 'rev_id', 'rev_timestamp', 'rev_deleted' ],
- [ 'rev_page' => $current->getPage(),
- "rev_user != {$user} OR rev_user_text != {$user_text}"
- ], __METHOD__,
- [ 'USE INDEX' => 'page_timestamp',
- 'ORDER BY' => 'rev_timestamp DESC' ]
- );
+ [
+ 'rev_page' => $current->getPage(),
+ 'NOT(' . $actorWhere['conds'] . ')',
+ ],
+ __METHOD__,
+ [
+ 'USE INDEX' => [ 'revision' => 'page_timestamp' ],
+ 'ORDER BY' => 'rev_timestamp DESC'
+ ],
+ $actorWhere['joins']
+ );
if ( $s === false ) {
// No one else ever edited this page
return [ [ 'cantrollback' ] ];
}
if ( count( $set ) ) {
+ $actorWhere = ActorMigration::newMigration()->getWhere( $dbw, 'rc_user', $user, false );
$dbw->update( 'recentchanges', $set,
[ /* WHERE */
'rc_cur_id' => $current->getPage(),
- 'rc_user_text' => $current->getUserText(),
'rc_timestamp > ' . $dbw->addQuotes( $s->rev_timestamp ),
+ $actorWhere['conds'], // No tables/joins are needed for rc_user
],
__METHOD__
);