MarkAHershberger has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/80690


Change subject: Abstract out some code for use in BlockandNuke
......................................................................

Abstract out some code for use in BlockandNuke

Change-Id: Iaa4abe7fa3ed22d98bb97aeb53923bf5409e1ecb
---
A UserMerger.php
1 file changed, 469 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/UserMerge 
refs/changes/90/80690/1

diff --git a/UserMerger.php b/UserMerger.php
new file mode 100644
index 0000000..474267c
--- /dev/null
+++ b/UserMerger.php
@@ -0,0 +1,469 @@
+<?php
+
+class UserMerger {
+       protected $page;
+
+       public function __construct( $page = null ) {
+               $this->page = $page;
+       }
+
+       public function merge( $oldUser, $newUser, $deleteUserPage = true ) {
+               $this->mergeEditcount( $newUser, $oldUser );
+               $this->mergeUser( $newUser, $oldUser );
+               if ( $deleteUserPage ) {
+                       $this->movePages( $newUser, $oldUser );
+                       $this->deleteUser( $oldUser );
+               }
+       }
+
+       /**
+        * Function to delete users following a successful mergeUser call
+        *
+        * Removes user entries from the user table and the user_groups table
+        *
+        * @param $user User
+        *
+        * @return bool Always returns true - throws exceptions on failure.
+        */
+       public function deleteUser( $user ) {
+               $olduserID = $user->getId();
+               $olduser_text = $user->getName();
+
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->delete(
+                       'user_groups',
+                       array( 'ug_user' => $olduserID )
+               );
+               $dbw->delete(
+                       'user',
+                       array( 'user_id' => $olduserID )
+               );
+
+               $log = new LogPage( 'usermerge' );
+               if( $this->page ) {
+                       $this->page->getOutput()->addHTML(
+                               wfMessage( 'usermerge-userdeleted', 
$olduser_text, $olduserID )->escaped() .
+                               Html::element( 'br' ) . "\n"
+                       );
+
+                       $log->addEntry( 'deleteuser', 
$this->page->getUser()->getUserPage(), '', array( $olduser_text, $olduserID ) );
+               } else {
+                       $log->addEntry( 'deleteuser', Title::newFromText( 
$olduser_text, NS_USER ), '', array( $olduser_text, $olduserID ) );
+               }
+
+               wfRunHooks( 'DeleteAccount', array( &$user ) );
+
+               $users = $dbw->selectField(
+                       'user',
+                       'COUNT(*)',
+                       array()
+               );
+               $dbw->update( 'site_stats',
+                       array( 'ss_users' => $users ),
+                       array( 'ss_row_id' => 1 )
+               );
+               return true;
+       }
+
+       /**
+        * Deduplicate watchlist entries
+        * which old (merge-from) and new (merge-to) users are watching
+        *
+        * @param $oldUser User
+        * @param $newUser User
+        *
+        * @return bool
+        */
+       public function deduplicateWatchlistEntries( $oldUser, $newUser ) {
+
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->begin( __METHOD__ );
+
+               $res = $dbw->select(
+                       array(
+                               'w1' => 'watchlist',
+                               'w2' => 'watchlist'
+                       ),
+                       array(
+                               'w2.wl_namespace',
+                               'w2.wl_title'
+                       ),
+                       array(
+                               'w1.wl_user' => $newUser->getID(),
+                               'w2.wl_user' => $oldUser->getID()
+                       ),
+                       __METHOD__,
+                       array( 'FOR UPDATE' ),
+                       array(
+                               'w2' => array(
+                                       'INNER JOIN',
+                                       array(
+                                               'w1.wl_namespace = 
w2.wl_namespace',
+                                               'w1.wl_title = w2.wl_title'
+                                       ),
+                               )
+                       )
+               );
+
+               # Construct an array to delete all watched pages of the old user
+               # which the new user already watches
+               $conds = array();
+
+               foreach ( $res as $result ) {
+                       $conds[] = $dbw->makeList(
+                               array(
+                                       'wl_user' => $oldUser->getID(),
+                                       'wl_namespace' => $result->wl_namespace,
+                                       'wl_title' => $result->wl_title
+                               ),
+                               LIST_AND
+                       );
+               }
+
+               if ( empty( $conds ) ) {
+                       $dbw->commit( __METHOD__ );
+                       return true;
+               }
+
+               # Perform a multi-row delete
+
+               # requires
+               # MediaWiki database function with fixed 
https://bugzilla.wikimedia.org/50078
+               # i.e. MediaWiki core after 
505dbb331e16a03d87cb4511ee86df12ea295c40 (20130625)
+               $dbw->delete(
+                       'watchlist',
+                       $dbw->makeList( $conds, LIST_OR ),
+                       __METHOD__
+               );
+
+               $dbw->commit( __METHOD__ );
+
+               return true;
+       }
+
+
+       /**
+        * Function to merge database references from one user to another user
+        *
+        * Merges database references from one user ID or username to another 
user ID or username
+        * to preserve referential integrity.
+        *
+        * @param $newUser User to merge from and delete
+        * @param $oldUser User to merge into
+        *
+        * @return bool Always returns true - throws exceptions on failure.
+        */
+       public function mergeUser( $newUser, $oldUser, $block = false, 
$banningUser = null ) {
+               $newuser_text = $newUser->getName();
+               $newuserID = $newUser->idForName();
+               $olduser_text = $oldUser->getName();
+               $olduserID = $oldUser->idForName();
+
+               if( $block == "block" ) {
+                       if( $banningUser === null ) {
+                               $banningUser = $oldUser;
+                       }
+                       // Make sure we block the IP first.
+                       $blk = new Block($newUser->getName(), $newUser->getId(),
+                               $banningUser->getID(), wfMsg('block-message'),
+                               wfTimestamp(), 0, Block::infinity(), 0, 1, 0, 
0, 1);
+                       $blk->isAutoBlocking( true );
+                       if($blk->insert()) {
+                               $log = new LogPage('block');
+                               $log->addEntry('block', Title::makeTitle( 
NS_USER, $oldUser->getName() ),
+                                       'Blocked through UserMerger', 
array('infinite', $oldUser->getName(),  'nocreate'));
+                       }
+               }
+
+               // Fields to update with the format:
+               // array( tableName, idField, textField )
+               $updateFields = array(
+                       array( 'archive', 'ar_user', 'ar_user_text' ),
+                       array( 'revision', 'rev_user', 'rev_user_text' ),
+                       array( 'filearchive', 'fa_user', 'fa_user_text' ),
+                       array( 'image', 'img_user', 'img_user_text' ),
+                       array( 'oldimage', 'oi_user', 'oi_user_text' ),
+                       array( 'recentchanges', 'rc_user', 'rc_user_text' ),
+                       array( 'logging', 'log_user' ),
+                       array( 'ipblocks', 'ipb_user', 'ipb_address' ),
+                       array( 'ipblocks', 'ipb_by', 'ipb_by_text' ),
+                       array( 'watchlist', 'wl_user' ),
+               );
+
+               $dbw = wfGetDB( DB_MASTER );
+               $out = null;
+               if( $this->page ) {
+                       $out = $this->page->getOutput();
+               }
+
+               $this->deduplicateWatchlistEntries( $oldUser, $newUser );
+
+               foreach ( $updateFields as $fieldInfo ) {
+                       $tableName = array_shift( $fieldInfo );
+                       $idField = array_shift( $fieldInfo );
+
+                       $dbw->update(
+                               $tableName,
+                               array( $idField => $newuserID ) + 
array_fill_keys( $fieldInfo, $newuser_text ),
+                               array( $idField => $olduserID ),
+                               __METHOD__,
+                               array( 'IGNORE' )
+                       );
+
+                       if( $out ) {
+                               $out->addHTML(
+                                       wfMessage(
+                                               'usermerge-updating',
+                                               $tableName,
+                                               $olduserID,
+                                               $newuserID
+                                       )->escaped() .
+                                       Html::element( 'br' ) . "\n"
+                               );
+
+                               foreach ( $fieldInfo as $textField ) {
+                                       $out->addHTML(
+                                               wfMessage(
+                                                       'usermerge-updating',
+                                                       $tableName,
+                                                       $olduser_text,
+                                                       $newuser_text
+                                               )->escaped() .
+                                               Html::element( 'br' ) . "\n"
+                                       );
+                               }
+                       }
+               }
+
+               $dbw->delete( 'user_newtalk', array( 'user_id' => $olduserID ) 
);
+
+               if( $out ) {
+                       $out->addHTML(
+                               Html::element( 'hr' ) . "\n" .
+                               wfMessage( 'usermerge-success', $olduser_text, 
$olduserID, $newuser_text, $newuserID )->escaped() .
+                               Html::element( 'br' ) . "\n"
+                       );
+
+                       $log = new LogPage( 'usermerge' );
+                       $log->addEntry(
+                               'mergeuser',
+                               $this->page->getUser()->getUserPage(),
+                               '',
+                               array( $olduser_text, $olduserID, 
$newuser_text, $newuserID )
+                       );
+               }
+               wfRunHooks( 'MergeAccountFromTo', array( &$oldUser, &$newUser ) 
);
+
+               return true;
+       }
+
+
+       /**
+        * Function to add edit count
+        *
+        * Adds edit count of both users
+        *
+        * @param $newUser user to merge references TO
+        * @param $oldUser user to remove references FROM
+        *
+        * @return bool Always returns true - throws exceptions on failure.
+        *
+        * @author Matthew April <[email protected]>
+        */
+       public function mergeEditcount( $newUser, $oldUser ) {
+               $dbw = wfGetDB( DB_MASTER );
+
+               $newuserID = $newUser->getId();
+               $olduserID = $oldUser->getId();
+
+               $olduserEdits = $dbw->selectField(
+                       'user',
+                       'user_editcount',
+                       array( 'user_id' => $olduserID ),
+                       __METHOD__
+               );
+               if ( $olduserEdits === false ) {
+                       $olduserEdits = 0;
+               }
+
+               $newuserEdits = $dbw->selectField(
+                       'user',
+                       'user_editcount',
+                       array( 'user_id' => $newuserID ),
+                       __METHOD__
+               );
+               if ( $newuserEdits === false ) {
+                       $newuserEdits = 0;
+               }
+
+               $totalEdits = $olduserEdits + $newuserEdits;
+
+               # don't run querys if neither user has any edits
+               if ( $totalEdits > 0 ) {
+                       # update new user with total edits
+                       $dbw->update( 'user',
+                               array( 'user_editcount' => $totalEdits ),
+                               array( 'user_id' => $newuserID ),
+                               __METHOD__
+                       );
+
+                       # clear old users edits
+                       $dbw->update( 'user',
+                               array( 'user_editcount' => 0 ),
+                               array( 'user_id' => $olduserID ),
+                               __METHOD__
+                       );
+               }
+
+               if( $this->page ) {
+                       $this->page->getOutput()->addHTML(
+                               wfMessage(
+                                       'usermerge-editcount-merge-success',
+                                       $olduserEdits, $olduserID, 
$newuserEdits, $newuserID, $totalEdits
+                               )->escaped() .
+                               Html::element( 'br' ) . "\n"
+                       );
+               }
+
+               return true;
+       }
+
+       /**
+        * Function to merge user pages
+        *
+        * Deletes all pages when merging to Anon
+        * Moves user page when the target user page does not exist or is empty
+        * Deletes redirect if nothing links to old page
+        * Deletes the old user page when the target user page exists
+        *
+        * @param $newuser_text string Username to merge pages TO
+        * @param $olduser_text string Username of user to remove pages FROM
+        *
+        * @return bool True on completion
+        *
+        * @author Matthew April <[email protected]>
+        */
+       public function movePages( $newUser, $oldUser ) {
+               $newuser_text = $newUser->getName();
+               $olduser_text = $oldUser->getName();
+               global $wgContLang;
+
+               $oldusername = trim( str_replace( '_', ' ', $olduser_text ) );
+               $oldusername = Title::makeTitle( NS_USER, $oldusername );
+               $newusername = Title::makeTitleSafe( NS_USER, 
$wgContLang->ucfirst( $newuser_text ) );
+
+               # select all user pages and sub-pages
+               $dbr = wfGetDB( DB_SLAVE );
+               $pages = $dbr->select( 'page',
+                       array( 'page_namespace', 'page_title' ),
+                       array(
+                               'page_namespace' => array( NS_USER, 
NS_USER_TALK ),
+                               $dbr->makeList( array(
+                                       'page_title' => $dbr->buildLike( 
$oldusername->getDBkey() . '/', $dbr->anyString() ),
+                                       'page_title' => $oldusername->getDBkey()
+                                       ),
+                                       LIST_OR
+                               )
+                       )
+                );
+
+               $output = '';
+
+               foreach ( $pages as $row ) {
+
+                       $oldPage = Title::makeTitleSafe( $row->page_namespace, 
$row->page_title );
+                       $newPage = Title::makeTitleSafe( $row->page_namespace,
+                               preg_replace( '!^[^/]+!', 
$newusername->getDBkey(), $row->page_title ) );
+
+                       if ( $newuser_text === "Anonymous" ) { # delete ALL old 
pages
+                               if ( $oldPage->exists() ) {
+                                       $oldPageArticle = new Article( 
$oldPage, 0 );
+                                       $oldPageArticle->doDeleteArticle( 
wfMessage( 'usermerge-autopagedelete' )->inContentLanguage()->text() );
+
+                                       $oldLink = Linker::linkKnown( $oldPage 
);
+                                       $output .= Html::rawElement( 'li',
+                                               array( 'class' => 
'mw-renameuser-pe' ),
+                                               wfMessage( 
'usermerge-page-deleted' )->rawParams( $oldLink )->escaped()
+                                       );
+
+                               }
+                       } elseif ( $newPage->exists()
+                               && !$oldPage->isValidMoveTarget( $newPage )
+                               && $newPage->getLength() > 0 ) { # delete old 
pages that can't be moved
+
+                               $oldPageArticle = new Article( $oldPage, 0 );
+                               $oldPageArticle->doDeleteArticle( wfMessage( 
'usermerge-autopagedelete' )->text() );
+
+                               $link = Linker::linkKnown( $oldPage );
+                               $output .= Html::rawElement( 'li',
+                                       array( 'class' => 'mw-renameuser-pe' ),
+                                       wfMessage( 'usermerge-page-deleted' 
)->rawParams( $link )->escaped()
+                               );
+
+                       } else { # move content to new page
+                               # delete target page if it exists and is blank
+                               if ( $newPage->exists() ) {
+                                       $newPageArticle = new Article( 
$newPage, 0 );
+                                       $newPageArticle->doDeleteArticle( 
wfMessage( 'usermerge-autopagedelete' )->inContentLanguage()->text() );
+                               }
+
+                               # move to target location
+                               $success = $oldPage->moveTo(
+                                       $newPage,
+                                       false,
+                                       wfMessage(
+                                               'usermerge-move-log',
+                                               $oldusername->getText(),
+                                               $newusername->getText() 
)->inContentLanguage()->text()
+                               );
+
+                               if ( $success === true ) {
+                                       $oldLink = Linker::linkKnown(
+                                               $oldPage,
+                                               null,
+                                               array(),
+                                               array( 'redirect' => 'no' )
+                                       );
+                                       $newLink = Linker::linkKnown( $newPage 
);
+                                       $output .= Html::rawElement( 'li',
+                                               array( 'class' => 
'mw-renameuser-pm' ),
+                                               wfMessage( 
'usermerge-page-moved' )->rawParams( $oldLink, $newLink )->escaped()
+                                       );
+                               } else {
+                                       $oldLink = Linker::linkKnown( $oldPage 
);
+                                       $newLink = Linker::linkKnown( $newPage 
);
+                                       $output .= Html::rawElement( 'li',
+                                               array( 'class' => 
'mw-renameuser-pu' ),
+                                               wfMessage( 
'usermerge-page-unmoved' )->rawParams( $oldLink, $newLink )->escaped()
+                                       );
+                               }
+
+                               # check if any pages link here
+                               $res = $dbr->selectField( 'pagelinks',
+                                       'pl_title',
+                                       array( 'pl_title' => $olduser_text ),
+                                       __METHOD__
+                               );
+                               if ( !$dbr->numRows( $res ) ) {
+                                       # nothing links here, so delete unmoved 
page/redirect
+                                       $oldPageArticle = new Article( 
$oldPage, 0 );
+                                       $oldPageArticle->doDeleteArticle( 
wfMessage( 'usermerge-autopagedelete' )->inContentLanguage()->text() );
+                               }
+                       }
+
+               }
+
+               if ( $output && $this->page ) {
+                       $this->page->getOutput()->addHTML(
+                               Html::rawElement( 'ul',
+                                       array(),
+                                       $output
+                               )
+                       );
+               } elseif( $output ) {
+                       var_dump($output );
+               }
+
+               return true;
+       }
+}
\ No newline at end of file

-- 
To view, visit https://gerrit.wikimedia.org/r/80690
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Iaa4abe7fa3ed22d98bb97aeb53923bf5409e1ecb
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/UserMerge
Gerrit-Branch: master
Gerrit-Owner: MarkAHershberger <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to