* 'Recentchanges Patrol' to mark new edits that haven't yet been viewed
* Support for faster C++ diff module (WikiDiff extension)
* More scary link caching modes
+* Old manually maintained log pages replaced with searchable Special:Log
* ... and more!
=== Caveats ===
do_objectcache_update(); flush();
do_categorylinks_update(); flush();
do_image_name_unique_update(); flush();
+ do_logging_update(); flush();
if ( isTemplateInitialised() ) {
print "Template namespace already initialised\n";
# moved to separate EditPage and CacheManager classes.
require_once ( 'CacheManager.php' );
-include_once ( 'SpecialValidate.php' ) ;
$wgArticleCurContentFields = false;
$wgArticleOldContentFields = false;
function validate () {
global $wgOut, $wgUseValidation;
if( $wgUseValidation ) {
+ require_once ( 'SpecialValidate.php' ) ;
$wgOut->setPagetitle( wfMsg( 'validate' ) . ': ' . $this->mTitle->getPrefixedText() );
$wgOut->setRobotpolicy( 'noindex,follow' );
if( $this->mTitle->getNamespace() != 0 ) {
), 'Article::protect'
);
- $log = new LogPage( wfMsg( 'protectlogpage' ), wfMsg( 'protectlogtext' ) );
+ $log = new LogPage( 'protect' );
if ( $limit === '' ) {
- $log->addEntry( wfMsg( 'unprotectedarticle', $this->mTitle->getPrefixedText() ), $reason );
+ $log->addEntry( 'unprotect', $this->mTitle, $reason );
} else {
- $log->addEntry( wfMsg( 'protectedarticle', $this->mTitle->getPrefixedText() ), $reason );
+ $log->addEntry( 'protect', $this->mTitle, $reason );
}
$wgOut->redirect( $this->mTitle->getFullURL() );
return;
$dbw->delete( 'categorylinks', array( 'cl_from' => $id ) );
# Log the deletion
- $log = new LogPage( wfMsg( 'dellogpage' ), wfMsg( 'dellogpagetext' ) );
- $art = $this->mTitle->getPrefixedText();
- $log->addEntry( wfMsg( 'deletedarticle', $art ), $reason );
+ $log = new LogPage( 'delete' );
+ $log->addEntry( 'delete', $this->mTitle, $reason );
# Clear the cached article id so the interface doesn't act like we exist
$this->mTitle->resetArticleID( 0 );
$descTitle->invalidateCache();
}
- $log = new LogPage( wfMsg( 'uploadlogpage' ), wfMsg( 'uploadlogpagetext' ) );
- $da = wfMsg( 'uploadedimage', '[[:' . $wgLang->getNsText(
- Namespace::getImage() ) . ":{$name}|{$name}]]" );
- $ta = wfMsg( 'uploadedimage', $name );
- $log->addEntry( $da, $desc, $ta );
+ $log = new LogPage( 'upload' );
+ $log->addEntry( 'upload', $descTitle, $desc );
}
function wfImageArchiveUrl( $name )
<?php
#$Id$
#
-# Class to simplify the use of log pages
+# Copyright (C) 2002, 2004 Brion Vibber <brion@pobox.com>
+# http://www.mediawiki.org/
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# http://www.gnu.org/copyleft/gpl.html
+
+# Class to simplify the use of log pages.
+# The logs are now kept in a table which is easier to manage and trim
+# than ever-growing wiki pages.
class LogPage {
- /* private */ var $mTitle, $mContent, $mContentLoaded, $mId, $mComment;
- var $mUpdateRecentChanges ;
+ /* private */ var $type, $action, $comment;
+ var $updateRecentChanges = true;
- function LogPage( $title, $defaulttext = "<ul>\n</ul>" )
- {
- # For now, assume title is correct dbkey
- # and log pages always go in Wikipedia namespace
- $this->mTitle = str_replace( ' ', '_', $title );
- $this->mId = 0;
- $this->mUpdateRecentChanges = true ;
- $this->mContentLoaded = false;
- $this->getContent( $defaulttext );
+ function LogPage( $type ) {
+ # Type is one of 'block', 'protect', 'rights', 'delete', 'upload'
+ $this->type = $type;
}
- function getContent( $defaulttext = "<ul>\n</ul>" )
- {
- $fname = 'LogPage::getContent';
-
- $dbw =& wfGetDB( DB_MASTER );
- $s = $dbw->getArray( 'cur',
- array( 'cur_id','cur_text','cur_timestamp' ),
- array( 'cur_namespace' => Namespace::getWikipedia(), 'cur_title' => $this->mTitle ),
- $fname, 'FOR UPDATE'
- );
-
- if( $s !== false ) {
- $this->mId = $s->cur_id;
- $this->mContent = $s->cur_text;
- $this->mTimestamp = wfTimestamp(TS_MW,$s->cur_timestamp);
- } else {
- $this->mId = 0;
- $this->mContent = $defaulttext;
- $this->mTimestamp = wfTimestamp(TS_MW);
- }
- $this->mContentLoaded = true; # Well, sort of
-
- return $this->mContent;
- }
-
- function getTimestamp()
- {
- if( !$this->mContentLoaded ) {
- $this->getContent();
- }
- return $this->mTimestamp;
- }
-
- function saveContent()
- {
+ function saveContent() {
if( wfReadOnly() ) return;
global $wgUser;
$dbw =& wfGetDB( DB_MASTER );
$uid = $wgUser->getID();
- if( !$this->mContentLoaded ) return false;
- $this->mTimestamp = $now = wfTimestampNow();
- $won = wfInvertTimestamp( $now );
- if($this->mId == 0) {
- $seqVal = $dbw->nextSequenceValue( 'cur_cur_id_seq' );
-
- # Note: this query will deadlock if another thread has called getContent(),
- # at least in MySQL 4.0.17 InnoDB
- $dbw->insertArray( 'cur',
- array(
- 'cur_id' => $seqVal,
- 'cur_timestamp' => $dbw->timestamp($now),
- 'cur_user' => $uid,
- 'cur_user_text' => $wgUser->getName(),
- 'cur_namespace' => NS_WIKIPEDIA,
- 'cur_title' => $this->mTitle,
- 'cur_text' => $this->mContent,
- 'cur_comment' => $this->mComment,
- 'cur_restrictions' => 'sysop',
- 'inverse_timestamp' => $won,
- 'cur_touched' => $dbw->timestamp($now),
- ), $fname
- );
- $this->mId = $dbw->insertId();
- } else {
- $dbw->updateArray( 'cur',
- array( /* SET */
- 'cur_timestamp' => $dbw->timestamp($now),
- 'cur_user' => $uid,
- 'cur_user_text' => $wgUser->getName(),
- 'cur_text' => $this->mContent,
- 'cur_comment' => $this->mComment,
- 'cur_restrictions' => 'sysop',
- 'inverse_timestamp' => $won,
- 'cur_touched' => $dbw->timestamp($now),
- ), array( /* WHERE */
- 'cur_id' => $this->mId
- ), $fname
- );
- }
+ $this->timestamp = $now = wfTimestampNow();
+ $dbw->insertArray( 'logging',
+ array(
+ 'log_type' => $this->type,
+ 'log_action' => $this->action,
+ 'log_timestamp' => $dbw->timestamp( $now ),
+ 'log_user' => $uid,
+ 'log_namespace' => $this->target->getNamespace(),
+ 'log_title' => $this->target->getDBkey(),
+ 'log_comment' => $this->comment
+ ), $fname
+ );
# And update recentchanges
- if ( $this->mUpdateRecentChanges ) {
- $titleObj = Title::makeTitle( Namespace::getWikipedia(), $this->mTitle );
- RecentChange::notifyLog( $now, $titleObj, $wgUser, $this->mComment );
+ if ( $this->updateRecentChanges ) {
+ $rcComment = $this->actionText;
+ if( '' != $this->comment ) {
+ $rcComment .= ': ' . $this->comment;
+ }
+ $titleObj = Title::makeTitle( NS_SPECIAL, 'Log/' . $this->type );
+ RecentChange::notifyLog( $now, $titleObj, $wgUser, $rcComment );
}
return true;
}
- function addEntry( $action, $comment, $textaction = '' )
- {
- global $wgLang, $wgUser;
-
- $comment_esc = wfEscapeWikiText( $comment );
-
- $this->getContent();
-
- $ut = $wgUser->getName();
- $uid = $wgUser->getID();
- if( $uid ) {
- $ul = '[[' .
- $wgLang->getNsText( Namespace::getUser() ) .
- ":{$ut}|{$ut}]]";
- } else {
- $ul = $ut;
- }
-
- # Use the wiki-wide default date format instead of the user's setting
- $d = $wgLang->timeanddate( wfTimestampNow(), false, MW_DATE_DEFAULT );
-
- if( preg_match( "/^(.*?)<ul>(.*)$/sD", $this->mContent, $m ) ) {
- $before = $m[1];
- $after = $m[2];
- } else {
- $before = '';
- $after = '';
- }
-
- if($textaction)
- $this->mComment = $textaction;
- else
- $this->mComment = $action;
-
- if ( '' == $comment ) {
- $inline = '';
+ /* static */ function actionText( $type, $action, $titleLink ) {
+ static $actions = array(
+ 'block/block' => 'blocklogentry',
+ 'block/unblock' => 'blocklogentry',
+ 'protect/protect' => 'protectedarticle',
+ 'protect/unprotect' => 'unprotectedarticle',
+ 'rights/rights' => 'bureaucratlogentry',
+ 'delete/delete' => 'deletedarticle',
+ 'delete/restore' => 'undeletedarticle',
+ 'upload/upload' => 'uploadedimage',
+ 'upload/revert' => 'uploadedimage',
+ );
+ $key = "$type/$action";
+ if( isset( $actions[$key] ) ) {
+ return wfMsg( $actions[$key], $titleLink );
} else {
- $inline = " <em>({$comment_esc})</em>";
- # comment gets escaped again, so we use the unescaped version
- $this->mComment .= ': '.$comment;
+ wfDebug( "LogPage::actionText - unknown action $key\n" );
+ return "$action $titleLink";
}
- $this->mContent = "{$before}<ul><li>{$d} {$ul} {$action}{$inline}</li>\n{$after}";
-
- # TODO: automatic log rotation...
-
- return $this->saveContent();
}
- function replaceContent( $text, $comment = '' )
- {
- $this->mContent = $text;
- $this->mComment = $comment;
- $this->mTimestamp = wfTimestampNow();
- return $this->saveContent();
- }
-
- function showAsDisabledPage( $rawhtml = true )
- {
- global $wgLang, $wgOut;
- if( $wgOut->checkLastModified( $this->getTimestamp() ) ){
- # Client cache fresh and headers sent, nothing more to do.
- return;
- }
- $func = ( $rawhtml ? 'addHTML' : 'addWikiText' );
- $wgOut->$func(
- "<p>" . wfMsg( 'perfdisabled' ) . "</p>\n\n" .
- "<p>" . wfMsg( 'perfdisabledsub', $wgLang->timeanddate( $this->getTimestamp() ) ) . "</p>\n\n" .
- "<hr />\n\n" .
- $this->getContent()
- );
- return;
+ function addEntry( $action, &$target, $comment ) {
+ global $wgLang, $wgUser;
+ $this->action = $action;
+ $this->target =& $target;
+ $this->comment = $comment;
+ $this->actionText = LogPage::actionText( $this->type, $action,
+ $target->getPrefixedText() );
+
+ return $this->saveContent();
}
}
$ban->insert();
# Make log entry
- $log = new LogPage( wfMsg( "blocklogpage" ), wfMsg( "blocklogtext" ) );
- $action = wfMsg( "blocklogentry", $this->BlockAddress, $this->BlockExpiry );
- $log->addEntry( $action, $this->BlockReason );
+ $log = new LogPage( 'block' );
+ $log->addEntry( 'block', Title::makeTitle( NS_USER, $this->BlockAddress ), $this->BlockReason );
# Report to the user
$titleObj = Title::makeTitle( NS_SPECIAL, "Blockip" );
$block->delete();
# Make log entry
- $log = new LogPage( wfMsg( "blocklogpage" ), wfMsg( "blocklogtext" ) );
- $action = wfMsg( "unblocklogentry", $this->ip );
- $log->addEntry( $action, $this->reason );
+ $log = new LogPage( 'block' );
+ $log->addEntry( 'unblock', Title::makeTitle( NS_USER, $this->ip ), $this->reason );
# Report to the user
$titleObj = Title::makeTitle( NS_SPECIAL, "Ipblocklist" );
--- /dev/null
+<?php
+# Copyright (C) 2004 Brion Vibber <brion@pobox.com>
+# http://www.mediawiki.org/
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# http://www.gnu.org/copyleft/gpl.html
+
+function wfSpecialLog( $par = '' ) {
+ global $wgRequest;
+ $logReader =& new LogReader( $wgRequest );
+ if( '' == $wgRequest->getVal( 'type' ) && !empty( $par ) ) {
+ $logReader->limitType( $par );
+ }
+ $logViewer =& new LogViewer( $logReader );
+ $logViewer->show();
+ $logReader->cleanUp();
+}
+
+class LogReader {
+ var $db, $joinClauses, $whereClauses;
+ var $type = '', $user = '', $title = null;
+
+ function LogReader( $request ) {
+ $this->db =& wfGetDB( DB_SLAVE );
+ $this->setupQuery( $request );
+ }
+
+ function setupQuery( $request ) {
+ $cur = $this->db->tableName( 'cur' );
+ $user = $this->db->tableName( 'user' );
+ $this->joinClauses = array( "LEFT OUTER JOIN $cur ON log_namespace=cur_namespace AND log_title=cur_title" );
+ $this->whereClauses = array( 'user_id=log_user' );
+
+ $this->limitType( $request->getVal( 'type' ) );
+ $this->limitUser( $request->getText( 'user' ) );
+ $this->limitTitle( $request->getText( 'page' ) );
+ $this->limitTime( $request->getVal( 'from' ), '>=' );
+ $this->limitTime( $request->getVal( 'until' ), '<=' );
+
+ list( $this->limit, $this->offset ) = $request->getLimitOffset();
+ }
+
+ function limitType( $type ) {
+ if( empty( $type ) ) {
+ return false;
+ }
+ $this->type = $type;
+ $safetype = $this->db->strencode( $type );
+ $this->whereClauses[] = "log_type='$safetype'";
+ }
+
+ function limitUser( $name ) {
+ $title = Title::makeTitleSafe( NS_USER, $name );
+ if( empty( $name ) || is_null( $title ) ) {
+ return false;
+ }
+ $this->user = str_replace( '_', ' ', $title->getDBkey() );
+ $safename = $this->db->strencode( $this->user );
+ $user = $this->db->tableName( 'user' );
+ $this->whereClauses[] = "user_name='$safename'";
+ }
+
+ function limitTitle( $page ) {
+ $title = Title::newFromText( $page );
+ if( empty( $page ) || is_null( $title ) ) {
+ return false;
+ }
+ $this->title =& $title;
+ $safetitle = $this->db->strencode( $title->getDBkey() );
+ $ns = $title->getNamespace();
+ $this->whereClauses[] = "log_namespace=$ns AND log_title='$safetitle'";
+ }
+
+ function limitTime( $time, $direction ) {
+ # Direction should be a comparison operator
+ if( empty( $time ) ) {
+ return false;
+ }
+ $safetime = $this->db->strencode( wfTimestamp( TS_MW, $time ) );
+ $this->whereClauses[] = "log_timestamp $direction '$safetime'";
+ }
+
+ function getQuery() {
+ $logging = $this->db->tableName( "logging" );
+ $user = $this->db->tableName( 'user' );
+ $sql = "SELECT log_type, log_action, log_timestamp,
+ log_user, user_name,
+ log_namespace, log_title, cur_id,
+ log_comment FROM $logging, $user ";
+ if( !empty( $this->joinClauses ) ) {
+ $sql .= implode( ',', $this->joinClauses );
+ }
+ if( !empty( $this->whereClauses ) ) {
+ $sql .= " WHERE " . implode( ' AND ', $this->whereClauses );
+ }
+ $sql .= " ORDER BY log_timestamp DESC ";
+ $sql .= $this->db->limitResult( $this->limit, $this->offset );
+ return $sql;
+ }
+
+ function initQuery() {
+ $this->result = $this->db->query( $this->getQuery() );
+ }
+
+ function fetchObject() {
+ return $this->db->fetchObject( $this->result );
+ }
+
+ function cleanUp() {
+ $this->db->freeResult( $this->result );
+ }
+
+ function queryType() {
+ return $this->type;
+ }
+
+ function queryUser() {
+ return $this->user;
+ }
+
+ function queryTitle() {
+ if( is_null( $this->title ) ) {
+ return '';
+ } else {
+ return $this->title->getPrefixedText();
+ }
+ }
+}
+
+class LogViewer {
+ var $reader, $skin;
+ var $typeText = array(
+ '' => array( 'log', 'alllogstext' ),
+ 'block' => array( 'blocklogpage', 'blocklogtext' ),
+ 'protect' => array( 'protectlogpage', 'protectlogtext' ),
+ 'rights' => array( 'bureaucratlog', '' ),
+ 'delete' => array( 'dellogpage', 'dellogpagetext' ),
+ 'upload' => array( 'uploadlogpage', 'uploadlogpagetext' )
+ );
+
+
+ function LogViewer( &$reader ) {
+ global $wgUser;
+ $this->skin =& $wgUser->getSkin();
+ $this->reader =& $reader;
+ }
+
+ function show() {
+ global $wgOut;
+ $this->showHeader( $wgOut );
+ $this->showOptions( $wgOut );
+ $this->showPrevNext( $wgOut );
+ $out = "";
+ $this->reader->initQuery();
+ while( $s = $this->reader->fetchObject() ) {
+ $out .= $this->logLine( $s );
+ }
+ $wgOut->addHTML( $out );
+ $this->showPrevNext( $wgOut );
+ }
+
+ # wfMsg( unprotectedarticle, $text )
+ # wfMsg( 'protectedarticle', $text )
+ # wfMsg( 'deletedarticle', $text )
+ # wfMsg( 'uploadedimage', $text )
+ # wfMsg( "blocklogentry", $this->BlockAddress, $this->BlockExpiry );
+ # wfMsg( "bureaucratlogentry", $this->mUser, implode( " ", $rightsNotation ) );
+ # wfMsg( "undeletedarticle", $this->mTarget ),
+ function logLine( $s ) {
+ global $wgLang;
+ $title = Title::makeTitle( $s->log_namespace, $s->log_title );
+ $user = Title::makeTitleSafe( NS_USER, $s->user_name );
+ $time = $wgLang->timeanddate( $s->log_timestamp );
+ if( $s->cur_id ) {
+ $titleLink = $this->skin->makeKnownLinkObj( $title );
+ } else {
+ $titleLink = $this->skin->makeBrokenLinkObj( $title );
+ }
+ $userLink = $this->skin->makeLinkObj( $user, htmlspecialchars( $s->user_name ) );
+ if( '' === $s->log_comment ) {
+ $comment = '';
+ } else {
+ $comment = '(<em>' . $this->skin->formatComment( $s->log_comment ) . '</em>)';
+ }
+
+ $action = LogPage::actionText( $s->log_type, $s->log_action, $titleLink );
+ $out = "<li>$time $userLink $action $comment</li>\n";
+ return $out;
+ }
+
+ function showHeader( &$out ) {
+ $type = $this->reader->queryType();
+ if( isset( $this->typeText[$type] ) ) {
+ list( $title, $headertext ) = $this->typeText[$type];
+ $out->setPageTitle( str_replace( '_', ' ', wfMsg( $title ) ) );
+ $out->addWikiText( wfMsg( $headertext ) );
+ }
+ }
+
+ function showOptions( &$out ) {
+ global $wgScript;
+ $action = htmlspecialchars( $wgScript );
+ $title = Title::makeTitle( NS_SPECIAL, 'Log' );
+ $special = htmlspecialchars( $title->getPrefixedDBkey() );
+ $out->addHTML( "<form action=\"$action\" method=\"get\">\n" .
+ "<input type='hidden' name='title' value=\"$special\" />\n" .
+ $this->getTypeMenu() .
+ $this->getUserInput() .
+ $this->getTitleInput() .
+ "<input type='submit' />" .
+ "</form>" );
+ }
+
+ function getTypeMenu() {
+ $out = "<select name='type'>\n";
+ foreach( $this->typeText as $type => $msg ) {
+ $text = htmlspecialchars( str_replace( '_', ' ', wfMsg( $msg[0] ) ) );
+ $selected = ($type == $this->reader->queryType()) ? ' selected="selected"' : '';
+ $out .= "<option value=\"$type\"$selected>$text</option>\n";
+ }
+ $out .= "</select>\n";
+ return $out;
+ }
+
+ function getUserInput() {
+ $user = htmlspecialchars( $this->reader->queryUser() );
+ return "User: <input type='text' name='user' size='12' value=\"$user\" />\n";
+ }
+
+ function getTitleInput() {
+ $title = htmlspecialchars( $this->reader->queryTitle() );
+ return "Title: <input type='text' name='page' size='20' value=\"$title\" />\n";
+ }
+
+ function showPrevNext( &$out ) {
+ global $wgLang;
+ $pieces = array();
+ $pieces[] = 'type=' . htmlspecialchars( $this->reader->queryType() );
+ $pieces[] = 'user=' . htmlspecialchars( $this->reader->queryUser() );
+ $pieces[] = 'page=' . htmlspecialchars( $this->reader->queryTitle() );
+ $bits = implode( '&', $pieces );
+ $offset = 0; $limit = 50;
+
+ # TODO: use timestamps instead of offsets to make it more natural
+ # to go huge distances in time
+ $html = wfViewPrevNext( $offset, $limit,
+ $wgLang->specialpage( 'Log' ),
+ $bits,
+ false);
+ $out->addHTML( '<p>' . $html . '</p>' );
+ }
+}
+
+
+?>
\ No newline at end of file
$dbw->query($sql);
$wgMemc->delete( "$dbName:user:id:$id" );
- $bureaucratLog = wfMsg( "bureaucratlog" );
- $action = wfMsg( "bureaucratlogentry", $this->mUser, implode( " ", $rightsNotation ) );
-
- $log = new LogPage( $bureaucratLog );
- $log->addEntry( $action, "" );
+ $log = new LogPage( 'rights' );
+ $log->addEntry( 'rights', Title::makeTitle( NS_USER, $this->mUser ),
+ implode( " ", $rightsNotation ) );
$this->showSuccess();
}
"Version" => new SpecialPage( "Version" ),
"Allmessages" => new SpecialPage( "Allmessages" ),
"Search" => new UnlistedSpecialPage( "Search" ),
+ "Log" => new SpecialPage( "Log" ),
"Blockip" => new SpecialPage( "Blockip", "sysop" ),
"Asksql" => new SpecialPage( "Asksql", "sysop" ),
"Undelete" => new SpecialPage( "Undelete", "sysop" ),
# Touch the log?
- $log = new LogPage( wfMsg( "dellogpage" ), wfMsg( "dellogpagetext" ) );
- $log->addEntry( wfMsg( "undeletedarticle", $this->mTarget ), "" );
+ $log = new LogPage( 'delete' );
+ $log->addEntry( 'restore', Title::makeTitle( $namespace, $title ), "" );
$wgOut->addWikiText( wfMsg( "undeletedtext", $this->mTarget ) );
return 0;
'rfcurl' => "http://www.faqs.org/rfcs/rfc$1.html",
'alphaindexline' => "$1 to $2",
'version' => 'Version',
+'log' => 'Logs',
+'alllogstext' => 'Combined display of upload, deletion, protection, blocking, and sysop logs.
+You can narrow down the view by selecting a log type, the user name, or the affected page.',
# Special:Allpages
'nextpage' => 'Next page ($1)',
--- /dev/null
+-- Add the logging table and adjust recentchanges to accomodate special pages
+-- 2004-08-24
+
+CREATE TABLE logging (
+ -- Symbolic keys for the general log type and the action type
+ -- within the log. The output format will be controlled by the
+ -- action field, but only the type controls categorization.
+ log_type char(10) NOT NULL default '',
+ log_action char(10) NOT NULL default '',
+
+ -- Timestamp. Duh.
+ log_timestamp char(14) NOT NULL default '19700101000000',
+
+ -- The user who performed this action; key to user_id
+ log_user int unsigned NOT NULL default 0,
+
+ -- Key to the page affected. Where a user is the target,
+ -- this will point to the user page.
+ log_namespace tinyint unsigned NOT NULL default 0,
+ log_title varchar(255) NOT NULL default '',
+
+ -- Freeform text. Interpreted as edit history comments.
+ log_comment varchar(255) NOT NULL default '',
+
+ KEY type_time (log_type, log_timestamp),
+ KEY user_time (log_user, log_timestamp),
+ KEY page_time (log_namespace, log_title, log_timestamp)
+);
+
+-- Change from unsigned to signed so we can store special pages
+ALTER TABLE recentchanges
+ MODIFY rc_namespace tinyint(3) NOT NULL default '0';
rc_cur_time varchar(14) binary NOT NULL default '',
rc_user int(10) unsigned NOT NULL default '0',
rc_user_text varchar(255) binary NOT NULL default '',
- rc_namespace tinyint(3) unsigned NOT NULL default '0',
+ rc_namespace tinyint(3) NOT NULL default '0',
rc_title varchar(255) binary NOT NULL default '',
rc_comment varchar(255) binary NOT NULL default '',
rc_minor tinyint(3) unsigned NOT NULL default '0',
`val_value` int(11) default '0',
`val_comment` varchar(255) NOT NULL default '',
KEY `val_user` (`val_user`,`val_title`,`val_timestamp`)
-) TYPE=MyISAM;
+);
+
+
+CREATE TABLE logging (
+ -- Symbolic keys for the general log type and the action type
+ -- within the log. The output format will be controlled by the
+ -- action field, but only the type controls categorization.
+ log_type char(10) NOT NULL default '',
+ log_action char(10) NOT NULL default '',
+
+ -- Timestamp. Duh.
+ log_timestamp char(14) NOT NULL default '19700101000000',
+
+ -- The user who performed this action; key to user_id
+ log_user int unsigned NOT NULL default 0,
+
+ -- Key to the page affected. Where a user is the target,
+ -- this will point to the user page.
+ log_namespace tinyint unsigned NOT NULL default 0,
+ log_title varchar(255) NOT NULL default '',
+
+ -- Freeform text. Interpreted as edit history comments.
+ log_comment varchar(255) NOT NULL default '',
+
+ KEY type_time (log_type, log_timestamp),
+ KEY user_time (log_user, log_timestamp),
+ KEY page_time (log_namespace, log_title, log_timestamp)
+);
echo "ok\n";
}
}
+
+function do_logging_update() {
+ global $wgDatabase;
+ if ( $wgDatabase->tableExists( 'logging' ) ) {
+ echo "...logging table already unique.\n";
+ } else {
+ echo "Creating logging table and adjusting recentchanges... ";
+ dbsource( "maintenance/archives/patch-logging.sql", $wgDatabase );
+ echo "ok\n";
+ }
+}
+
?>