Extension:UserSnoop

Description
The UserSnoop MediaWiki extension/special page

This extension creates a new special page through which a user with the appropriate permissions ('usersnoop' and 'sysop') can view and manipulate users.

The main section is display of user information: If the calling user is a member of the 'bureaucrat' group then they also can:
 * internal user id
 * username
 * real name
 * email address
 * whether the user has new talk or not
 * date of registration
 * number of edits
 * whether the user is blocked or not
 * block reason (if blocked)
 * list of *effective* groups
 * last update of user profile
 * user's signature
 * user's last login
 * force the user logout (boot user)
 * block the user
 * spread the block on the user to all of his/her ip addresses
 * unblock the user

The actions on information that can be called on the target user:
 * page views
 * page name
 * number of visits
 * last visit
 * watchlist
 * page name
 * last visit
 * last edit by user
 * last edit by any user
 * new pages
 * page name
 * create date
 * last edit by user
 * last edit by any user

Installation

 * 1) Run UserPageViews.sql on your wiki db
 * 2) Run UserPageHits.sql on your wiki db
 * 3) Copy and paste the source code to UserSnoop.php
 * 4) Edit your LocalSettings.php to append:

UserSnoop.php
\n \n";		}		return $out;		}	function sandboxParse($wikiText) {			global $wgTitle, $wgUser;			$myParser = new Parser;			$myParserOptions = new ParserOptions;			$myParserOptions->initialiseFromUser($wgUser);			$result = $myParser->parse($wikiText, $wgTitle, $myParserOptions);			return $result->getText;	}	function blockUser($user_id = 0) {		global $wgUser;		if($user_id == 0) {			$user_id = $this->uid;		}		$blk = new Block($this->targetUser, $user_id, $wgUser->getID, wfMsg('usersnoopblockmessage'),				wfTimestamp, 0, Block::infinity, 0, 1, 0, 0, 1);		if($blk->insert) {			$log = new LogPage('block');			$log->addEntry('block', Title::makeTitle( NS_USER, $this->targetUser ),				 'Blocked through Special:UserSnoop', array('infinite', 'nocreate'));		}	}	function unblockUser($user_id = 0) {		global $wgUser;		if($user_id == 0) {			$user_id = $this->uid;		}  	$dbr = wfGetDB(DB_SLAVE); $ipb_id = $dbr->selectField('ipblocks', 'ipb_id', array('ipb_user'=>$user_id), __METHOD__); $blk = Block::newFromId($ipb_id);

if($blk->delete) { $log = new LogPage('block'); $log->addEntry('unblock', Title::makeTitle(NS_USER, $this->targetUser), wfMsg('usersnoopunblockmessage')); }		}	function loadAllMessages { static $messagesLoaded = false; if(!$messagesLoaded) { global $wgMessageCache; #todo: add more languages $wgMessageCache->addMessages(				array('usersnoop' => 'User snoop', 'usersnoopusername' => 'Username', 'usersnoopaction' => 'Action', 'usersnoopnone' => '(none)', 'usersnooppageviews' => 'Page views', 'usersnoopwatchlist' => 'Watchlist', 'usersnoopnewpages' => 'New pages', 'usersnoopsubmit' => 'Submit', 'usersnoopid' => 'ID', 'usersnooprealname' => 'Real name', 'usersnoopnewtalk' => 'New talk', 'usersnoopregistered' => 'Registered', 'usersnoopedits' => 'Edits', 'usersnoopyes' => 'Yes', 'usersnoopno' => 'No', 'usersnoopblk' => 'Blk', 'usersnoopblockreason' => 'Block reason', 'usersnoopgroups' => 'Groups', 'usersnooplastupdated' => 'Last updated', 'usersnoopsignature' => 'Signature', 'usersnooplastlogin' => 'Last login', 'usersnoopforcelogout' => 'Force logout', 'usersnoopblock' => 'Block', 'usersnoopspreadblock' => 'Spread block', 'usersnoopunblock' => 'Unblock', 'usersnoopblockmessage' => 'Blocked through Special:UserSnoop', 'usersnoopunblockmessage' => 'Unblocked through Special:UserSnoop', 'usersnooppage' => 'Page', 'usersnoophits' => 'Hits', 'usersnooplast' => 'Last', 'usersnooplastvisit' => 'Last visit', 'usersnooplasteditedbythisuser' => 'Last edited by this user', 'usersnooplasteditedbyanyuser' => 'Last edited by any user', 'usersnoopcreated' => 'Created')				,'en'); $messagesLoaded = true; }		return true; }	function loadLocalizedName(&$specialPageArray, $code) { self::loadAllMessages; $text = wfMsg('usersnoop'); $title = Title::newFromText($text); $specialPageArray['UserSnoop'][] = $title->getDBKey; return true; } }

require_once("$IP/includes/Pager.php");
 * 1) include the pager class

class UserSnoopPager extends AlphabeticPager {	protected $targetUser = ""; //our victim protected $uid = 0;       //our victim's uid #constructor - also inilizes "stuff" function __construct($uid=0) { if($uid > 0) { $this->uid = $uid; $dbr = wfGetDB(DB_SLAVE); $this->targetUser = $dbr->selectField('user','user_name',array('user_id'=>$this->uid),__METHOD__); } else { global $wgRequest; $this->targetUser = $wgRequest->getVal( 'username' ); if($this->targetUser != "") { $dbr = wfGetDB(DB_SLAVE); $this->uid = $dbr->selectField('user','user_id',array('user_name'=>$this->targetUser),__METHOD__); }		}		parent::__construct; }
 * 1) create a custom pager for our extension
 * 2) all other pagers will inherit this one

function getBodyHeader { }

function getBodyFooter { }

function getBody { if (!$this->mQueryDone) { $this->doQuery; }		$batch = new LinkBatch; $db = $this->mDb;

$this->mResult->rewind;

$batch->execute; $this->mResult->rewind; return parent::getBody; }

function formatRow($row) { }

function getQueryInfo { }

function getIndexField { }

function getPageHeader { }

function getDefaultQuery { global $wgRequest; $query = parent::getDefaultQuery; if($this->targetUser != '') { $query['username'] = $this->targetUser; }		$query['action'] = $wgRequest->getVal('action'); return $query; }	function sandboxParse($wikiText) { global $wgTitle, $wgUser; $myParser = new Parser; $myParserOptions = new ParserOptions; $myParserOptions->initialiseFromUser($wgUser); $result = $myParser->parse($wikiText, $wgTitle, $myParserOptions); return $result->getText; }

}

class UserSnoopPagerPageviews extends UserSnoopPager{ function UserSnoopPagerPageviews($uid=0) { parent::__construct($uid); }
 * 1) pager class used for user page views

function getIndexField { return "rownum"; }

function getBodyHeader { $s = ' ";		return $s;	}

function getQueryInfo { list ($userpagehits) = wfGetDB->tableNamesN('user_page_hits'); $conds = array; $table = "(select @rownum:=@rownum+1 as rownum,";		$table .= "user_name, user_real_name, page_namespace, page_title,hits, last ";		$table .= "from (select @rownum:=0) r, ";		$table .= "(select user_name, user_real_name, page_namespace, page_title,hits,"; $table .= "last from user_page_hits) p";		if($this->targetUser) {			$table .= " where user_name = ";			$table .= wfGetDB->addQuotes($this->targetUser);		}		$table .= ") results"; return array(			'tables' => " $table ",			'fields' => array( 'rownum', 'user_name', 'user_real_name', 'page_namespace', 'page_title', 'hits', "concat(substr(last, 1, 4),'-',substr(last,5,2),'-',substr(last,7,2),' ',substr(last,9,2),':',substr(last,11,2),':',substr(last,13,2)) AS last"),			'conds' => $conds		);

}

function formatRow( $row ) { $userPage = Title::makeTitle( NS_USER, $row->user_name ); $name = $this->getSkin->makeLinkObj( $userPage, htmlspecialchars( $userPage->getText ) ); $pageTitle = Title::makeTitle( $row->page_namespace, $row->page_title ); if($row->page_namespace > 0) { $pageFullName = $pageTitle->getNsText.":".htmlspecialchars($pageTitle->getText ); } else { $pageFullName = htmlspecialchars( $pageTitle->getText); }		$page = $this->getSkin->makeLinkObj( $pageTitle, $pageFullName );

$res = ' '; $res .= "$row->rownum "; $res .= " $page "; $res .= "$row->hits "; $res .= "$row->last "; $res .= " \n"; return $res; } }

class UserSnoopPagerWatchlist extends UserSnoopPager {
 * 1) used for the watchlist data

function getIndexField { return "rownum"; }

function getBodyHeader { $s = ' ";		return $s;	}

function getQueryInfo { $conds = array;

$table = "(select @rownum:=@rownum+1 as rownum, wl_user userid, wl_namespace namespace, wl_title title, `last` lastview, lastedit, lastuseredit";		$table .= " from page, watchlist, user_page_views,";		$table .= " (select @rownum:=0) r,";		$table .= " (select rev_page, max(rev_timestamp) lastedit from revision group by rev_page) rev1,";		$table .= " (select rev_user, rev_page, max(rev_timestamp) lastuseredit from revision group by rev_user, rev_page) rev2";		$table .= " where page.page_namespace = wl_namespace and page.page_title = wl_title";		$table .= " and rev1.rev_page = page.page_id";		$table .= " and rev2.rev_user = wl_user";		$table .= " and rev2.rev_page = page.page_id";		$table .= " and user_page_views.user_id = wl_user";		$table .= " and user_page_views.page_id = page.page_id";		if($this->targetUser) {			$table .= " and wl_user = ".$this->uid;		}		$table .= ") result"; return array(   			'tables' => " $table ",    			'fields' => array( 'rownum', 'namespace', 'title', "concat(substr(lastview, 1, 4),'-',substr(lastview,5,2),'-',substr(lastview,7,2),' ',substr(lastview,9,2),':',substr(lastview,11,2),':',substr(lastview,13,2)) AS lastview", "concat(substr(lastedit, 1, 4),'-',substr(lastedit,5,2),'-',substr(lastedit,7,2),' ',substr(lastedit,9,2),':',substr(lastedit,11,2),':',substr(lastedit,13,2)) AS lastedit", "concat(substr(lastuseredit, 1, 4),'-',substr(lastuseredit,5,2),'-',substr(lastuseredit,7,2),' ',substr(lastuseredit,9,2),':',substr(lastuseredit,11,2),':',substr(lastuseredit,13,2)) AS lastuseredit" ),   			'conds' => $conds    		);

}

function formatRow( $row ) { $pageTitle = Title::makeTitle( $row->namespace, $row->title ); if($row->namespace > 0) { $pageFullName = $pageTitle->getNsText.":".htmlspecialchars($pageTitle->getText ); } else { $pageFullName = htmlspecialchars( $pageTitle->getText); }		$page = $this->getSkin->makeLinkObj( $pageTitle, $pageFullName );

$res = ' '; $res .= "$row->rownum "; $res .= " $page "; $res .= "$row->lastview "; $res .= "$row->lastuseredit "; $res .= "$row->lastedit "; $res .= " \n"; return $res; }

}

class UserSnoopPagerNewPages extends UserSnoopPager {
 * 1) used for the newpage listing

function getIndexField { return "rownum"; }

function getBodyHeader { $s = ' ";		return $s;	}

function getQueryInfo { list ($userpagehits) = wfGetDB->tableNamesN('user_page_hits'); $conds = array; $table = "(select @rownum:=@rownum+1 as rownum, revision.rev_user user_id, namespace, title, created, lastuseredit, lastedit";		$table .= " from revision, (select @rownum:=0) r,";		$table .= " (SELECT page_namespace namespace, page_title title, page_id pageid, min(rev_timestamp) created"; $table .= " FROM revision, page"; $table .= " where page.page_id = revision.rev_page"; $table .= " group by namespace, title, pageid) revs,";		$table .= " (select rev_page, max(rev_timestamp) lastedit from revision group by rev_page) lastedit,";		$table .= " (select rev_page, rev_user, max(rev_timestamp) lastuseredit from revision group by rev_page,"; $table .= " rev_user) lastuseredit";		$table .= " where revision.rev_page = revs.pageid";		$table .= " and revision.rev_timestamp = revs.created";		$table .= " and lastedit.rev_page = revs.pageid";		$table .= " and lastuseredit.rev_page = revs.pageid";		$table .= " and lastuseredit.rev_user = revision.rev_user";		if($this->targetUser) {			$table .= " and revision.rev_user = ".$this->uid;		}		$table .= ") res";

return array(			'tables' => " $table ",			'fields' => array( 'rownum', 'namespace', 'title', "concat(substr(created, 1, 4),'-',substr(created,5,2),'-',substr(created,7,2),' ',substr(created,9,2),':',substr(created,11,2),':',substr(created,13,2)) AS created", "concat(substr(lastuseredit, 1, 4),'-',substr(lastuseredit,5,2),'-',substr(lastuseredit,7,2),' ',substr(lastuseredit,9,2),':',substr(lastuseredit,11,2),':',substr(lastuseredit,13,2)) AS lastuseredit", "concat(substr(lastedit, 1, 4),'-',substr(lastedit,5,2),'-',substr(lastedit,7,2),' ',substr(lastedit,9,2),':',substr(lastedit,11,2),':',substr(lastedit,13,2)) AS lastedit", ),			'conds' => $conds		);

}

function formatRow( $row ) { $pageTitle = Title::makeTitle( $row->namespace, $row->title ); if($row->namespace > 0) { $pageFullName = $pageTitle->getNsText.":".htmlspecialchars($pageTitle->getText ); } else { $pageFullName = htmlspecialchars( $pageTitle->getText); }		$page = $this->getSkin->makeLinkObj( $pageTitle, $pageFullName );

$res = ' '; $res .= "$row->rownum "; $res .= " $page "; $res .= "$row->created "; $res .= "$row->lastuseredit "; $res .= "$row->lastedit "; $res .= " \n"; return $res; }

}

} //if !defined('USER_SNOOP')

Note
This extension duplicates some of the functionality of Extension:UserPageViewTracker