2004-02-18 02:15:00 +00:00
|
|
|
<?php
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* File for articles
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
* @file
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2003-08-02 20:43:11 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2005-04-12 02:18:57 +00:00
|
|
|
* Class representing a MediaWiki article and history.
|
2004-09-02 23:28:24 +00:00
|
|
|
*
|
2005-04-12 02:07:16 +00:00
|
|
|
* See design.txt for an overview.
|
2004-09-02 23:28:24 +00:00
|
|
|
* Note: edit user interface and cache support functions have been
|
2006-10-11 08:25:26 +00:00
|
|
|
* moved to separate EditPage and HTMLFileCache classes.
|
2004-09-03 00:20:26 +00:00
|
|
|
*
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2003-04-14 23:10:40 +00:00
|
|
|
class Article {
|
2007-03-28 14:16:43 +00:00
|
|
|
/**@{{
|
2006-04-19 15:46:24 +00:00
|
|
|
* @private
|
|
|
|
|
*/
|
2008-07-25 20:16:24 +00:00
|
|
|
var $mComment = ''; //!<
|
|
|
|
|
var $mContent; //!<
|
|
|
|
|
var $mContentLoaded = false; //!<
|
|
|
|
|
var $mCounter = -1; //!< Not loaded
|
|
|
|
|
var $mCurID = -1; //!< Not loaded
|
|
|
|
|
var $mDataLoaded = false; //!<
|
|
|
|
|
var $mForUpdate = false; //!<
|
|
|
|
|
var $mGoodAdjustment = 0; //!<
|
|
|
|
|
var $mIsRedirect = false; //!<
|
|
|
|
|
var $mLatest = false; //!<
|
|
|
|
|
var $mMinorEdit; //!<
|
|
|
|
|
var $mOldId; //!<
|
|
|
|
|
var $mPreparedEdit = false; //!< Title object if set
|
|
|
|
|
var $mRedirectedFrom = null; //!< Title object if set
|
|
|
|
|
var $mRedirectTarget = null; //!< Title object if set
|
|
|
|
|
var $mRedirectUrl = false; //!<
|
|
|
|
|
var $mRevIdFetched = 0; //!<
|
|
|
|
|
var $mRevision; //!<
|
|
|
|
|
var $mTimestamp = ''; //!<
|
|
|
|
|
var $mTitle; //!<
|
|
|
|
|
var $mTotalAdjustment = 0; //!<
|
|
|
|
|
var $mTouched = '19700101000000'; //!<
|
|
|
|
|
var $mUser = -1; //!< Not loaded
|
|
|
|
|
var $mUserText = ''; //!<
|
2007-03-28 14:16:43 +00:00
|
|
|
/**@}}*/
|
2004-09-02 23:28:24 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor and clear the article
|
2006-04-19 15:46:24 +00:00
|
|
|
* @param $title Reference to a Title object.
|
|
|
|
|
* @param $oldId Integer revision ID, null to fetch from request, zero for current
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function __construct( Title $title, $oldId = null ) {
|
2003-09-01 08:30:14 +00:00
|
|
|
$this->mTitle =& $title;
|
2005-12-30 09:33:11 +00:00
|
|
|
$this->mOldId = $oldId;
|
2003-09-01 08:30:14 +00:00
|
|
|
}
|
2008-08-21 00:45:13 +00:00
|
|
|
|
2008-08-16 13:34:43 +00:00
|
|
|
/**
|
|
|
|
|
* Constructor from an article article
|
|
|
|
|
* @param $id The article ID to load
|
|
|
|
|
*/
|
|
|
|
|
public static function newFromID( $id ) {
|
|
|
|
|
$t = Title::newFromID( $id );
|
|
|
|
|
return $t == null ? null : new Article( $t );
|
|
|
|
|
}
|
2006-11-20 05:41:53 +00:00
|
|
|
|
2006-01-13 00:29:20 +00:00
|
|
|
/**
|
|
|
|
|
* Tell the page view functions that this view was redirected
|
|
|
|
|
* from another page on the wiki.
|
2006-04-19 15:46:24 +00:00
|
|
|
* @param $from Title object.
|
2006-01-13 00:29:20 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function setRedirectedFrom( $from ) {
|
2006-01-13 00:29:20 +00:00
|
|
|
$this->mRedirectedFrom = $from;
|
|
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2008-04-11 15:20:45 +00:00
|
|
|
/**
|
|
|
|
|
* If this page is a redirect, get its target
|
|
|
|
|
*
|
|
|
|
|
* The target will be fetched from the redirect table if possible.
|
|
|
|
|
* If this page doesn't have an entry there, call insertRedirect()
|
|
|
|
|
* @return mixed Title object, or null if this page is not a redirect
|
|
|
|
|
*/
|
|
|
|
|
public function getRedirectTarget() {
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$this->mTitle || !$this->mTitle->isRedirect() )
|
2008-04-11 15:20:45 +00:00
|
|
|
return null;
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !is_null($this->mRedirectTarget) )
|
2008-04-11 15:20:45 +00:00
|
|
|
return $this->mRedirectTarget;
|
|
|
|
|
# Query the redirect table
|
2008-11-28 14:29:25 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
$res = $dbr->select( 'redirect',
|
|
|
|
|
array('rd_namespace', 'rd_title'),
|
|
|
|
|
array('rd_from' => $this->getID()),
|
|
|
|
|
__METHOD__
|
2008-04-11 15:20:45 +00:00
|
|
|
);
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $row = $dbr->fetchObject($res) ) {
|
2008-04-11 15:20:45 +00:00
|
|
|
return $this->mRedirectTarget = Title::makeTitle($row->rd_namespace, $row->rd_title);
|
2008-11-28 14:29:25 +00:00
|
|
|
}
|
2008-04-11 15:20:45 +00:00
|
|
|
# This page doesn't have an entry in the redirect table
|
|
|
|
|
return $this->mRedirectTarget = $this->insertRedirect();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Insert an entry for this page into the redirect table.
|
|
|
|
|
*
|
|
|
|
|
* Don't call this function directly unless you know what you're doing.
|
|
|
|
|
* @return Title object
|
|
|
|
|
*/
|
|
|
|
|
public function insertRedirect() {
|
2008-11-28 14:29:25 +00:00
|
|
|
$retval = Title::newFromRedirect( $this->getContent() );
|
|
|
|
|
if( !$retval ) {
|
2008-04-11 15:20:45 +00:00
|
|
|
return null;
|
2008-11-28 14:29:25 +00:00
|
|
|
}
|
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
$dbw->replace( 'redirect', array('rd_from'),
|
|
|
|
|
array(
|
2008-04-11 15:20:45 +00:00
|
|
|
'rd_from' => $this->getID(),
|
|
|
|
|
'rd_namespace' => $retval->getNamespace(),
|
2008-07-31 02:44:56 +00:00
|
|
|
'rd_title' => $retval->getDBKey()
|
2008-11-28 14:29:25 +00:00
|
|
|
),
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
2008-04-11 15:20:45 +00:00
|
|
|
return $retval;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-13 00:29:20 +00:00
|
|
|
/**
|
2008-04-15 17:32:23 +00:00
|
|
|
* Get the Title object this page redirects to
|
|
|
|
|
*
|
2006-01-13 00:29:20 +00:00
|
|
|
* @return mixed false, Title of in-wiki target, or string with URL
|
|
|
|
|
*/
|
2008-07-04 09:38:12 +00:00
|
|
|
public function followRedirect() {
|
2008-04-15 18:11:28 +00:00
|
|
|
$text = $this->getContent();
|
2008-08-20 19:13:13 +00:00
|
|
|
return $this->followRedirectText( $text );
|
2008-07-04 09:38:12 +00:00
|
|
|
}
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2008-07-04 09:38:12 +00:00
|
|
|
/**
|
|
|
|
|
* Get the Title object this text redirects to
|
|
|
|
|
*
|
|
|
|
|
* @return mixed false, Title of in-wiki target, or string with URL
|
|
|
|
|
*/
|
|
|
|
|
public function followRedirectText( $text ) {
|
2008-04-15 18:11:28 +00:00
|
|
|
$rt = Title::newFromRedirect( $text );
|
2006-01-13 00:29:20 +00:00
|
|
|
# process if title object is valid and not special:userlogout
|
|
|
|
|
if( $rt ) {
|
|
|
|
|
if( $rt->getInterwiki() != '' ) {
|
|
|
|
|
if( $rt->isLocal() ) {
|
|
|
|
|
// Offsite wikis need an HTTP redirect.
|
|
|
|
|
//
|
|
|
|
|
// This can be hard to reverse and may produce loops,
|
|
|
|
|
// so they may be disabled in the site configuration.
|
|
|
|
|
$source = $this->mTitle->getFullURL( 'redirect=no' );
|
|
|
|
|
return $rt->getFullURL( 'rdfrom=' . urlencode( $source ) );
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if( $rt->getNamespace() == NS_SPECIAL ) {
|
2006-11-23 08:25:56 +00:00
|
|
|
// Gotta handle redirects to special pages differently:
|
2006-01-13 00:29:20 +00:00
|
|
|
// Fill the HTTP response "Location" header and ignore
|
|
|
|
|
// the rest of the page we're on.
|
|
|
|
|
//
|
|
|
|
|
// This can be hard to reverse, so they may be disabled.
|
2006-10-30 06:25:31 +00:00
|
|
|
if( $rt->isSpecial( 'Userlogout' ) ) {
|
2006-01-13 00:29:20 +00:00
|
|
|
// rolleyes
|
|
|
|
|
} else {
|
|
|
|
|
return $rt->getFullURL();
|
|
|
|
|
}
|
2006-03-11 17:13:49 +00:00
|
|
|
}
|
2006-01-14 21:19:17 +00:00
|
|
|
return $rt;
|
2006-01-13 00:29:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// No or invalid redirect
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2004-12-29 01:07:43 +00:00
|
|
|
/**
|
|
|
|
|
* get the title object of the article
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getTitle() {
|
2005-07-01 00:03:31 +00:00
|
|
|
return $this->mTitle;
|
2004-12-29 01:07:43 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2008-11-30 10:10:15 +00:00
|
|
|
* Clear the object
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function clear() {
|
2005-03-18 08:37:50 +00:00
|
|
|
$this->mDataLoaded = false;
|
2003-04-14 23:10:40 +00:00
|
|
|
$this->mContentLoaded = false;
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2004-01-17 05:49:39 +00:00
|
|
|
$this->mCurID = $this->mUser = $this->mCounter = -1; # Not loaded
|
2006-01-13 00:29:20 +00:00
|
|
|
$this->mRedirectedFrom = null; # Title object if set
|
2008-04-11 15:20:45 +00:00
|
|
|
$this->mRedirectTarget = null; # Title object if set
|
2006-01-13 00:29:20 +00:00
|
|
|
$this->mUserText =
|
2006-06-20 09:50:57 +00:00
|
|
|
$this->mTimestamp = $this->mComment = '';
|
2005-06-19 00:21:49 +00:00
|
|
|
$this->mGoodAdjustment = $this->mTotalAdjustment = 0;
|
2004-06-08 19:51:10 +00:00
|
|
|
$this->mTouched = '19700101000000';
|
2004-08-20 14:59:49 +00:00
|
|
|
$this->mForUpdate = false;
|
2005-03-18 08:37:50 +00:00
|
|
|
$this->mIsRedirect = false;
|
2005-03-29 16:38:30 +00:00
|
|
|
$this->mRevIdFetched = 0;
|
2005-12-30 09:33:11 +00:00
|
|
|
$this->mRedirectUrl = false;
|
2006-03-16 02:32:30 +00:00
|
|
|
$this->mLatest = false;
|
2007-11-12 07:30:40 +00:00
|
|
|
$this->mPreparedEdit = false;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2006-01-13 00:29:20 +00:00
|
|
|
* Note that getContent/loadContent do not follow redirects anymore.
|
|
|
|
|
* If you need to fetch redirectable content easily, try
|
|
|
|
|
* the shortcut in Article::followContent()
|
2004-09-02 23:28:24 +00:00
|
|
|
*
|
2004-09-03 00:20:26 +00:00
|
|
|
* @return Return the text of this revision
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getContent() {
|
2008-11-28 18:37:31 +00:00
|
|
|
global $wgUser, $wgContLang, $wgOut, $wgMessageCache;
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $this->getID() === 0 ) {
|
|
|
|
|
# If this is a MediaWiki:x message, then load the messages
|
|
|
|
|
# and return the message value for x.
|
|
|
|
|
if( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
|
2008-11-28 18:37:31 +00:00
|
|
|
# If this is a system message, get the default text.
|
|
|
|
|
list( $message, $lang ) = $wgMessageCache->figureMessage( $wgContLang->lcfirst( $this->mTitle->getText() ) );
|
|
|
|
|
$wgMessageCache->loadAllMessages( $lang );
|
|
|
|
|
$text = wfMsgGetKey( $message, false, $lang, false );
|
|
|
|
|
if( wfEmptyMsg( $message, $text ) )
|
|
|
|
|
$text = '';
|
2005-12-28 14:47:30 +00:00
|
|
|
} else {
|
2009-01-12 08:11:22 +00:00
|
|
|
$text = wfMsgExt( $wgUser->isLoggedIn() ? 'noarticletext' : 'noarticletextanon', 'parsemag' );
|
2005-12-28 14:47:30 +00:00
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return $text;
|
2005-07-03 04:00:33 +00:00
|
|
|
} else {
|
2006-01-13 00:29:20 +00:00
|
|
|
$this->loadContent();
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2006-04-11 08:27:35 +00:00
|
|
|
return $this->mContent;
|
2004-05-13 12:20:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-01-10 13:41:22 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the text of the current revision. No side-effects...
|
|
|
|
|
*
|
|
|
|
|
* @return Return the text of the current revision
|
|
|
|
|
*/
|
|
|
|
|
public function getRawText() {
|
|
|
|
|
// Check process cache for current revision
|
|
|
|
|
if( $this->mContentLoaded && $this->mOldId == 0 ) {
|
|
|
|
|
return $this->mContent;
|
|
|
|
|
}
|
|
|
|
|
$rev = Revision::newFromTitle( $this->mTitle );
|
|
|
|
|
$text = $rev ? $rev->getRawText() : false;
|
|
|
|
|
return $text;
|
|
|
|
|
}
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* This function returns the text of a section, specified by a number ($section).
|
2006-04-19 15:46:24 +00:00
|
|
|
* A section is text under a heading like == Heading == or \<h1\>Heading\</h1\>, or
|
2004-09-02 23:28:24 +00:00
|
|
|
* the first section before any such heading (section 0).
|
|
|
|
|
*
|
|
|
|
|
* If a section contains subsections, these are also returned.
|
2004-09-03 00:20:26 +00:00
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
* @param $text String: text to look in
|
|
|
|
|
* @param $section Integer: section number
|
2004-09-03 00:20:26 +00:00
|
|
|
* @return string text of the requested section
|
2006-07-05 22:45:41 +00:00
|
|
|
* @deprecated
|
2004-09-03 00:20:26 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getSection( $text, $section ) {
|
2006-06-06 00:51:34 +00:00
|
|
|
global $wgParser;
|
|
|
|
|
return $wgParser->getSection( $text, $section );
|
2004-05-13 17:25:34 +00:00
|
|
|
}
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2006-01-07 12:10:04 +00:00
|
|
|
* @return int The oldid of the article that is to be shown, 0 for the
|
|
|
|
|
* current revision
|
2004-11-13 08:40:34 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getOldID() {
|
|
|
|
|
if( is_null( $this->mOldId ) ) {
|
2005-12-30 09:33:11 +00:00
|
|
|
$this->mOldId = $this->getOldIDFromRequest();
|
2004-11-13 08:40:34 +00:00
|
|
|
}
|
2005-12-30 09:33:11 +00:00
|
|
|
return $this->mOldId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets $this->mRedirectUrl to a correct URL if the query parameters are incorrect
|
2006-01-07 12:10:04 +00:00
|
|
|
*
|
|
|
|
|
* @return int The old id for the request
|
2005-12-30 09:33:11 +00:00
|
|
|
*/
|
2008-08-26 00:32:55 +00:00
|
|
|
public function getOldIDFromRequest() {
|
2005-12-30 09:33:11 +00:00
|
|
|
global $wgRequest;
|
|
|
|
|
$this->mRedirectUrl = false;
|
2004-11-13 08:40:34 +00:00
|
|
|
$oldid = $wgRequest->getVal( 'oldid' );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( isset( $oldid ) ) {
|
2005-08-16 23:36:16 +00:00
|
|
|
$oldid = intval( $oldid );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $wgRequest->getVal( 'direction' ) == 'next' ) {
|
2004-10-02 21:36:36 +00:00
|
|
|
$nextid = $this->mTitle->getNextRevisionID( $oldid );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $nextid ) {
|
2004-10-02 21:36:36 +00:00
|
|
|
$oldid = $nextid;
|
|
|
|
|
} else {
|
2005-12-30 09:33:11 +00:00
|
|
|
$this->mRedirectUrl = $this->mTitle->getFullURL( 'redirect=no' );
|
2004-10-02 21:36:36 +00:00
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
} elseif( $wgRequest->getVal( 'direction' ) == 'prev' ) {
|
2004-10-02 21:36:36 +00:00
|
|
|
$previd = $this->mTitle->getPreviousRevisionID( $oldid );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $previd ) {
|
2004-10-02 21:36:36 +00:00
|
|
|
$oldid = $previd;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$oldid ) {
|
2005-12-30 09:33:11 +00:00
|
|
|
$oldid = 0;
|
|
|
|
|
}
|
|
|
|
|
return $oldid;
|
2004-11-13 08:40:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2005-12-30 09:33:11 +00:00
|
|
|
* Load the revision (including text) into this object
|
2004-12-19 08:00:50 +00:00
|
|
|
*/
|
2006-01-13 00:29:20 +00:00
|
|
|
function loadContent() {
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $this->mContentLoaded ) return;
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
2004-11-13 08:40:34 +00:00
|
|
|
# Query variables :P
|
|
|
|
|
$oldid = $this->getOldID();
|
|
|
|
|
# Pre-fill content with error message so that if something
|
|
|
|
|
# fails we'll have something telling us what we intended.
|
2004-12-19 08:00:50 +00:00
|
|
|
$this->mOldId = $oldid;
|
2006-01-13 00:29:20 +00:00
|
|
|
$this->fetchContent( $oldid );
|
2008-11-28 14:29:25 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2004-12-19 08:00:50 +00:00
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
|
|
|
|
|
2005-03-14 10:06:28 +00:00
|
|
|
/**
|
|
|
|
|
* Fetch a page record with the given conditions
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $dbr Database object
|
|
|
|
|
* @param $conditions Array
|
2005-03-14 10:06:28 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
protected function pageData( $dbr, $conditions ) {
|
2005-12-07 10:37:48 +00:00
|
|
|
$fields = array(
|
2005-03-14 10:06:28 +00:00
|
|
|
'page_id',
|
|
|
|
|
'page_namespace',
|
|
|
|
|
'page_title',
|
2007-01-12 01:44:33 +00:00
|
|
|
'page_restrictions',
|
2005-03-14 10:06:28 +00:00
|
|
|
'page_counter',
|
|
|
|
|
'page_is_redirect',
|
|
|
|
|
'page_is_new',
|
|
|
|
|
'page_random',
|
|
|
|
|
'page_touched',
|
|
|
|
|
'page_latest',
|
2007-08-15 22:43:59 +00:00
|
|
|
'page_len',
|
|
|
|
|
);
|
|
|
|
|
wfRunHooks( 'ArticlePageDataBefore', array( &$this, &$fields ) );
|
|
|
|
|
$row = $dbr->selectRow(
|
|
|
|
|
'page',
|
2005-12-07 10:37:48 +00:00
|
|
|
$fields,
|
2005-03-14 10:06:28 +00:00
|
|
|
$conditions,
|
2007-08-15 22:43:59 +00:00
|
|
|
__METHOD__
|
|
|
|
|
);
|
|
|
|
|
wfRunHooks( 'ArticlePageDataAfter', array( &$this, &$row ) );
|
2005-12-07 10:37:48 +00:00
|
|
|
return $row ;
|
2005-03-14 10:06:28 +00:00
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2006-01-07 12:10:04 +00:00
|
|
|
/**
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $dbr Database object
|
|
|
|
|
* @param $title Title object
|
2006-01-07 12:10:04 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function pageDataFromTitle( $dbr, $title ) {
|
2005-03-14 10:06:28 +00:00
|
|
|
return $this->pageData( $dbr, array(
|
|
|
|
|
'page_namespace' => $title->getNamespace(),
|
|
|
|
|
'page_title' => $title->getDBkey() ) );
|
|
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2006-01-07 12:10:04 +00:00
|
|
|
/**
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $dbr Database
|
|
|
|
|
* @param $id Integer
|
2006-01-07 12:10:04 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
protected function pageDataFromId( $dbr, $id ) {
|
2006-01-07 12:10:04 +00:00
|
|
|
return $this->pageData( $dbr, array( 'page_id' => $id ) );
|
2005-03-14 10:06:28 +00:00
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2005-03-18 08:37:50 +00:00
|
|
|
/**
|
|
|
|
|
* Set the general counter, title etc data loaded from
|
|
|
|
|
* some source.
|
|
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $data Database row object or "fromdb"
|
2005-03-18 08:37:50 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function loadPageData( $data = 'fromdb' ) {
|
|
|
|
|
if( $data === 'fromdb' ) {
|
2008-06-16 14:18:41 +00:00
|
|
|
$dbr = wfGetDB( DB_MASTER );
|
2006-03-16 02:32:30 +00:00
|
|
|
$data = $this->pageDataFromId( $dbr, $this->getId() );
|
|
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2008-04-09 18:23:34 +00:00
|
|
|
$lc = LinkCache::singleton();
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $data ) {
|
2008-04-09 05:21:00 +00:00
|
|
|
$lc->addGoodLinkObj( $data->page_id, $this->mTitle, $data->page_len, $data->page_is_redirect );
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2006-03-16 02:32:30 +00:00
|
|
|
$this->mTitle->mArticleID = $data->page_id;
|
|
|
|
|
|
2008-12-09 22:24:21 +00:00
|
|
|
# Old-fashioned restrictions
|
2008-12-09 22:28:34 +00:00
|
|
|
$this->mTitle->loadRestrictions( $data->page_restrictions );
|
2007-01-12 01:44:33 +00:00
|
|
|
|
2006-03-16 02:32:30 +00:00
|
|
|
$this->mCounter = $data->page_counter;
|
|
|
|
|
$this->mTouched = wfTimestamp( TS_MW, $data->page_touched );
|
|
|
|
|
$this->mIsRedirect = $data->page_is_redirect;
|
|
|
|
|
$this->mLatest = $data->page_latest;
|
|
|
|
|
} else {
|
2008-11-28 14:29:25 +00:00
|
|
|
if( is_object( $this->mTitle ) ) {
|
2006-04-02 03:56:51 +00:00
|
|
|
$lc->addBadLinkObj( $this->mTitle );
|
|
|
|
|
}
|
2006-03-16 02:32:30 +00:00
|
|
|
$this->mTitle->mArticleID = 0;
|
|
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2005-12-30 09:33:11 +00:00
|
|
|
$this->mDataLoaded = true;
|
2005-03-18 08:37:50 +00:00
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2004-12-19 08:00:50 +00:00
|
|
|
/**
|
2005-01-11 01:28:18 +00:00
|
|
|
* Get text of an article from database
|
2006-01-13 00:29:20 +00:00
|
|
|
* Does *NOT* follow redirects.
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $oldid Int: 0 for whatever the latest revision is
|
2004-12-19 08:00:50 +00:00
|
|
|
* @return string
|
|
|
|
|
*/
|
2006-01-13 00:29:20 +00:00
|
|
|
function fetchContent( $oldid = 0 ) {
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $this->mContentLoaded ) {
|
2004-12-19 08:00:50 +00:00
|
|
|
return $this->mContent;
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2008-06-16 14:18:41 +00:00
|
|
|
$dbr = wfGetDB( DB_MASTER );
|
2004-12-19 08:00:50 +00:00
|
|
|
|
|
|
|
|
# Pre-fill content with error message so that if something
|
|
|
|
|
# fails we'll have something telling us what we intended.
|
|
|
|
|
$t = $this->mTitle->getPrefixedText();
|
2008-06-05 17:33:31 +00:00
|
|
|
$d = $oldid ? wfMsgExt( 'missingarticle-rev', array( 'escape' ), $oldid ) : '';
|
|
|
|
|
$this->mContent = wfMsg( 'missing-article', $t, $d ) ;
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2005-03-14 10:06:28 +00:00
|
|
|
if( $oldid ) {
|
|
|
|
|
$revision = Revision::newFromId( $oldid );
|
|
|
|
|
if( is_null( $revision ) ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfDebug( __METHOD__." failed to retrieve specified revision, id $oldid\n" );
|
2004-12-19 08:00:50 +00:00
|
|
|
return false;
|
2003-11-02 13:57:24 +00:00
|
|
|
}
|
2005-03-14 10:06:28 +00:00
|
|
|
$data = $this->pageDataFromId( $dbr, $revision->getPage() );
|
|
|
|
|
if( !$data ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfDebug( __METHOD__." failed to get page data linked to revision id $oldid\n" );
|
2005-03-14 10:06:28 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$this->mTitle = Title::makeTitle( $data->page_namespace, $data->page_title );
|
2005-03-18 08:37:50 +00:00
|
|
|
$this->loadPageData( $data );
|
2004-12-19 08:00:50 +00:00
|
|
|
} else {
|
2005-03-18 08:37:50 +00:00
|
|
|
if( !$this->mDataLoaded ) {
|
|
|
|
|
$data = $this->pageDataFromTitle( $dbr, $this->mTitle );
|
|
|
|
|
if( !$data ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfDebug( __METHOD__." failed to find page data for title " . $this->mTitle->getPrefixedText() . "\n" );
|
2005-03-18 08:37:50 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$this->loadPageData( $data );
|
2005-03-18 05:38:49 +00:00
|
|
|
}
|
2005-03-18 08:37:50 +00:00
|
|
|
$revision = Revision::newFromId( $this->mLatest );
|
2005-03-18 05:38:49 +00:00
|
|
|
if( is_null( $revision ) ) {
|
2008-09-16 18:39:13 +00:00
|
|
|
wfDebug( __METHOD__." failed to retrieve current page, rev_id {$this->mLatest}\n" );
|
2005-03-18 05:38:49 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2004-12-19 08:00:50 +00:00
|
|
|
}
|
2004-08-07 03:50:46 +00:00
|
|
|
|
2006-03-16 19:04:25 +00:00
|
|
|
// FIXME: Horrible, horrible! This content-loading interface just plain sucks.
|
|
|
|
|
// We should instead work with the Revision object when we need it...
|
2008-09-24 09:44:45 +00:00
|
|
|
$this->mContent = $revision->getText( Revision::FOR_THIS_USER ); // Loads if user is allowed
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2005-03-14 10:06:28 +00:00
|
|
|
$this->mUser = $revision->getUser();
|
|
|
|
|
$this->mUserText = $revision->getUserText();
|
|
|
|
|
$this->mComment = $revision->getComment();
|
|
|
|
|
$this->mTimestamp = wfTimestamp( TS_MW, $revision->getTimestamp() );
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2008-05-22 15:02:33 +00:00
|
|
|
$this->mRevIdFetched = $revision->getId();
|
2003-04-14 23:10:40 +00:00
|
|
|
$this->mContentLoaded = true;
|
2005-06-29 05:15:32 +00:00
|
|
|
$this->mRevision =& $revision;
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2005-12-21 12:02:18 +00:00
|
|
|
wfRunHooks( 'ArticleAfterFetchContent', array( &$this, &$this->mContent ) ) ;
|
|
|
|
|
|
2004-03-23 10:11:24 +00:00
|
|
|
return $this->mContent;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Read/write accessor to select FOR UPDATE
|
2006-01-07 12:10:04 +00:00
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
* @param $x Mixed: FIXME
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function forUpdate( $x = NULL ) {
|
2004-08-20 14:59:49 +00:00
|
|
|
return wfSetVar( $this->mForUpdate, $x );
|
|
|
|
|
}
|
2004-09-01 02:57:26 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Get the database which should be used for reads
|
2006-01-07 12:10:04 +00:00
|
|
|
*
|
|
|
|
|
* @return Database
|
2008-06-16 14:18:41 +00:00
|
|
|
* @deprecated - just call wfGetDB( DB_MASTER ) instead
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2007-01-22 23:50:42 +00:00
|
|
|
function getDB() {
|
2008-06-16 19:49:58 +00:00
|
|
|
wfDeprecated( __METHOD__ );
|
2007-01-12 10:03:51 +00:00
|
|
|
return wfGetDB( DB_MASTER );
|
2004-08-20 14:59:49 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Get options for all SELECT statements
|
2006-01-07 12:10:04 +00:00
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
* @param $options Array: an optional options array which'll be appended to
|
2006-01-07 12:10:04 +00:00
|
|
|
* the default
|
2006-04-19 15:46:24 +00:00
|
|
|
* @return Array: options
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
protected function getSelectOptions( $options = '' ) {
|
|
|
|
|
if( $this->mForUpdate ) {
|
|
|
|
|
if( is_array( $options ) ) {
|
2004-08-20 14:59:49 +00:00
|
|
|
$options[] = 'FOR UPDATE';
|
|
|
|
|
} else {
|
|
|
|
|
$options = 'FOR UPDATE';
|
|
|
|
|
}
|
2004-09-01 02:57:26 +00:00
|
|
|
}
|
2004-08-20 14:59:49 +00:00
|
|
|
return $options;
|
|
|
|
|
}
|
2004-09-01 02:57:26 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2006-01-07 12:10:04 +00:00
|
|
|
* @return int Page ID
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getID() {
|
2003-11-24 10:24:04 +00:00
|
|
|
if( $this->mTitle ) {
|
|
|
|
|
return $this->mTitle->getArticleID();
|
|
|
|
|
} else {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-07-01 20:36:04 +00:00
|
|
|
|
2005-06-29 23:44:03 +00:00
|
|
|
/**
|
2006-01-07 12:10:04 +00:00
|
|
|
* @return bool Whether or not the page exists in the database
|
2005-06-29 23:44:03 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function exists() {
|
|
|
|
|
return $this->getId() > 0;
|
2005-06-29 23:44:03 +00:00
|
|
|
}
|
2008-12-22 23:38:58 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if this page is something we're going to be showing
|
|
|
|
|
* some sort of sensible content for. If we return false, page
|
|
|
|
|
* views (plain action=view) will return an HTTP 404 response,
|
|
|
|
|
* so spiders and robots can know they're following a bad link.
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function hasViewableContent() {
|
|
|
|
|
return $this->exists() || $this->mTitle->isAlwaysKnown();
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-09-11 11:39:24 +00:00
|
|
|
/**
|
2006-01-07 12:10:04 +00:00
|
|
|
* @return int The view count for the page
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getCount() {
|
|
|
|
|
if( -1 == $this->mCounter ) {
|
2003-04-14 23:10:40 +00:00
|
|
|
$id = $this->getID();
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $id == 0 ) {
|
2006-03-16 02:32:30 +00:00
|
|
|
$this->mCounter = 0;
|
|
|
|
|
} else {
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2008-11-28 14:29:25 +00:00
|
|
|
$this->mCounter = $dbr->selectField( 'page',
|
|
|
|
|
'page_counter',
|
|
|
|
|
array( 'page_id' => $id ),
|
|
|
|
|
__METHOD__,
|
|
|
|
|
$this->getSelectOptions()
|
|
|
|
|
);
|
2006-03-16 02:32:30 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
return $this->mCounter;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2006-01-07 12:10:04 +00:00
|
|
|
* Determine whether a page would be suitable for being counted as an
|
|
|
|
|
* article in the site_stats table based on the title & its content
|
|
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
* @param $text String: text to analyze
|
2006-01-07 12:10:04 +00:00
|
|
|
* @return bool
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function isCountable( $text ) {
|
2007-01-08 16:31:52 +00:00
|
|
|
global $wgUseCommaCount;
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2006-01-07 12:10:04 +00:00
|
|
|
$token = $wgUseCommaCount ? ',' : '[[';
|
2008-11-28 14:29:25 +00:00
|
|
|
return $this->mTitle->isContentPage() && !$this->isRedirect($text) && in_string($token,$text);
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2005-07-01 00:03:31 +00:00
|
|
|
/**
|
2004-09-11 11:39:24 +00:00
|
|
|
* Tests if the article text represents a redirect
|
2006-01-07 12:10:04 +00:00
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
* @param $text String: FIXME
|
2006-01-07 12:10:04 +00:00
|
|
|
* @return bool
|
2004-09-11 11:39:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function isRedirect( $text = false ) {
|
|
|
|
|
if( $text === false ) {
|
|
|
|
|
if( $this->mDataLoaded ) {
|
2008-05-09 10:42:49 +00:00
|
|
|
return $this->mIsRedirect;
|
2008-11-28 14:29:25 +00:00
|
|
|
}
|
2008-05-09 10:42:49 +00:00
|
|
|
// Apparently loadPageData was never called
|
2004-09-11 11:39:24 +00:00
|
|
|
$this->loadContent();
|
2005-06-29 00:31:07 +00:00
|
|
|
$titleObj = Title::newFromRedirect( $this->fetchContent() );
|
2004-09-11 11:39:24 +00:00
|
|
|
} else {
|
|
|
|
|
$titleObj = Title::newFromRedirect( $text );
|
|
|
|
|
}
|
|
|
|
|
return $titleObj !== NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-29 23:44:03 +00:00
|
|
|
/**
|
|
|
|
|
* Returns true if the currently-referenced revision is the current edit
|
|
|
|
|
* to this page (and it exists).
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function isCurrent() {
|
2007-05-07 07:57:29 +00:00
|
|
|
# If no oldid, this is the current version.
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $this->getOldID() == 0 ) {
|
2007-05-07 07:57:29 +00:00
|
|
|
return true;
|
2008-11-28 14:29:25 +00:00
|
|
|
}
|
|
|
|
|
return $this->exists() && isset($this->mRevision) && $this->mRevision->isCurrent();
|
2005-06-29 23:44:03 +00:00
|
|
|
}
|
2005-07-01 20:36:04 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2004-12-19 08:00:50 +00:00
|
|
|
* Loads everything except the text
|
2004-09-02 23:28:24 +00:00
|
|
|
* This isn't necessary for all uses, so it's only done if needed.
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
protected function loadLastEdit() {
|
|
|
|
|
if( -1 != $this->mUser )
|
2004-12-19 08:00:50 +00:00
|
|
|
return;
|
2004-08-09 05:38:11 +00:00
|
|
|
|
2005-02-06 07:28:21 +00:00
|
|
|
# New or non-existent articles have no user information
|
|
|
|
|
$id = $this->getID();
|
2008-11-28 14:29:25 +00:00
|
|
|
if( 0 == $id ) return;
|
2005-02-06 07:28:21 +00:00
|
|
|
|
2008-06-16 14:18:41 +00:00
|
|
|
$this->mLastRevision = Revision::loadFromPageId( wfGetDB( DB_MASTER ), $id );
|
2005-03-18 04:32:55 +00:00
|
|
|
if( !is_null( $this->mLastRevision ) ) {
|
|
|
|
|
$this->mUser = $this->mLastRevision->getUser();
|
|
|
|
|
$this->mUserText = $this->mLastRevision->getUserText();
|
|
|
|
|
$this->mTimestamp = $this->mLastRevision->getTimestamp();
|
|
|
|
|
$this->mComment = $this->mLastRevision->getComment();
|
|
|
|
|
$this->mMinorEdit = $this->mLastRevision->isMinor();
|
2008-05-22 15:02:33 +00:00
|
|
|
$this->mRevIdFetched = $this->mLastRevision->getId();
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getTimestamp() {
|
2006-03-16 02:32:30 +00:00
|
|
|
// Check if the field has been filled by ParserCache::get()
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$this->mTimestamp ) {
|
2006-03-16 02:32:30 +00:00
|
|
|
$this->loadLastEdit();
|
|
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
return wfTimestamp(TS_MW, $this->mTimestamp);
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getUser() {
|
2003-04-14 23:10:40 +00:00
|
|
|
$this->loadLastEdit();
|
|
|
|
|
return $this->mUser;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getUserText() {
|
2003-04-14 23:10:40 +00:00
|
|
|
$this->loadLastEdit();
|
|
|
|
|
return $this->mUserText;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getComment() {
|
2003-04-14 23:10:40 +00:00
|
|
|
$this->loadLastEdit();
|
|
|
|
|
return $this->mComment;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getMinorEdit() {
|
2003-04-14 23:10:40 +00:00
|
|
|
$this->loadLastEdit();
|
|
|
|
|
return $this->mMinorEdit;
|
|
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
/* Use this to fetch the rev ID used on page views */
|
|
|
|
|
public function getRevIdFetched() {
|
2005-03-26 18:24:32 +00:00
|
|
|
$this->loadLastEdit();
|
|
|
|
|
return $this->mRevIdFetched;
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2006-04-19 15:46:24 +00:00
|
|
|
/**
|
|
|
|
|
* @param $limit Integer: default 0.
|
|
|
|
|
* @param $offset Integer: default 0.
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getContributors($limit = 0, $offset = 0) {
|
2004-08-12 14:27:38 +00:00
|
|
|
# XXX: this is expensive; cache this info somewhere.
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2004-08-12 14:27:38 +00:00
|
|
|
$contribs = array();
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2004-12-19 08:00:50 +00:00
|
|
|
$revTable = $dbr->tableName( 'revision' );
|
2004-07-10 03:09:26 +00:00
|
|
|
$userTable = $dbr->tableName( 'user' );
|
|
|
|
|
$user = $this->getUser();
|
2005-01-04 23:49:16 +00:00
|
|
|
$pageId = $this->getId();
|
2004-07-10 03:09:26 +00:00
|
|
|
|
2008-08-18 19:21:55 +00:00
|
|
|
$sql = "SELECT {$userTable}.*, MAX(rev_timestamp) as timestamp
|
2004-12-19 08:00:50 +00:00
|
|
|
FROM $revTable LEFT JOIN $userTable ON rev_user = user_id
|
|
|
|
|
WHERE rev_page = $pageId
|
2005-01-05 22:26:32 +00:00
|
|
|
AND rev_user != $user
|
2004-12-19 08:00:50 +00:00
|
|
|
GROUP BY rev_user, rev_user_text, user_real_name
|
2004-07-10 03:09:26 +00:00
|
|
|
ORDER BY timestamp DESC";
|
2004-04-29 01:58:20 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if($limit > 0) { $sql .= ' LIMIT '.$limit; }
|
|
|
|
|
if($offset > 0) { $sql .= ' OFFSET '.$offset; }
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2004-08-20 14:59:49 +00:00
|
|
|
$sql .= ' '. $this->getSelectOptions();
|
2004-04-29 01:58:20 +00:00
|
|
|
|
2008-08-18 19:21:55 +00:00
|
|
|
$res = $dbr->query($sql, __METHOD__ );
|
2004-09-01 02:57:26 +00:00
|
|
|
|
2008-08-18 19:21:55 +00:00
|
|
|
return new UserArrayFromResult( $res );
|
2004-04-23 21:01:29 +00:00
|
|
|
}
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* This is the default action of the script: just view the page of
|
|
|
|
|
* the given title.
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function view() {
|
2006-05-31 20:39:14 +00:00
|
|
|
global $wgUser, $wgOut, $wgRequest, $wgContLang;
|
2007-10-29 20:38:58 +00:00
|
|
|
global $wgEnableParserCache, $wgStylePath, $wgParser;
|
2007-05-31 23:09:36 +00:00
|
|
|
global $wgUseTrackbacks, $wgNamespaceRobotPolicies, $wgArticleRobotPolicies;
|
2008-02-06 00:55:52 +00:00
|
|
|
global $wgDefaultRobotPolicy;
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2006-06-04 00:25:53 +00:00
|
|
|
|
2004-08-09 05:38:11 +00:00
|
|
|
# Get variables from query string
|
2004-11-13 08:40:34 +00:00
|
|
|
$oldid = $this->getOldID();
|
2005-12-30 09:33:11 +00:00
|
|
|
|
2008-12-09 11:41:31 +00:00
|
|
|
# Try file cache
|
|
|
|
|
if( $oldid === 0 && $this->checkTouched() ) {
|
2008-12-10 05:33:57 +00:00
|
|
|
global $wgUseETag;
|
|
|
|
|
if( $wgUseETag ) {
|
2008-12-10 15:30:46 +00:00
|
|
|
$parserCache = ParserCache::singleton();
|
2008-12-10 05:33:57 +00:00
|
|
|
$wgOut->setETag( $parserCache->getETag($this,$wgUser) );
|
|
|
|
|
}
|
2008-12-11 14:29:16 +00:00
|
|
|
if( $wgOut->checkLastModified( $this->getTouched() ) ) {
|
2008-12-09 11:41:31 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return;
|
|
|
|
|
} else if( $this->tryFileCache() ) {
|
|
|
|
|
# tell wgOut that output is taken care of
|
|
|
|
|
$wgOut->disable();
|
|
|
|
|
$this->viewUpdates();
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-10 15:30:46 +00:00
|
|
|
$ns = $this->mTitle->getNamespace(); # shortcut
|
2008-12-09 11:41:31 +00:00
|
|
|
$sk = $wgUser->getSkin();
|
|
|
|
|
|
2005-12-30 09:33:11 +00:00
|
|
|
# getOldID may want us to redirect somewhere else
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $this->mRedirectUrl ) {
|
2005-12-30 09:33:11 +00:00
|
|
|
$wgOut->redirect( $this->mRedirectUrl );
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2005-12-30 09:33:11 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-29 14:48:07 +00:00
|
|
|
$diff = $wgRequest->getVal( 'diff' );
|
2004-08-09 05:38:11 +00:00
|
|
|
$rcid = $wgRequest->getVal( 'rcid' );
|
2005-03-09 02:02:04 +00:00
|
|
|
$rdfrom = $wgRequest->getVal( 'rdfrom' );
|
2007-01-12 03:36:46 +00:00
|
|
|
$diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) );
|
2007-09-07 23:07:07 +00:00
|
|
|
$purge = $wgRequest->getVal( 'action' ) == 'purge';
|
2008-12-22 23:38:58 +00:00
|
|
|
$return404 = false;
|
2004-03-29 14:48:07 +00:00
|
|
|
|
2003-04-14 23:10:40 +00:00
|
|
|
$wgOut->setArticleFlag( true );
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2007-01-14 21:28:23 +00:00
|
|
|
# Discourage indexing of printable versions, but encourage following
|
|
|
|
|
if( $wgOut->isPrintable() ) {
|
|
|
|
|
$policy = 'noindex,follow';
|
2008-11-28 14:29:25 +00:00
|
|
|
} elseif( isset( $wgArticleRobotPolicies[$this->mTitle->getPrefixedText()] ) ) {
|
2007-05-31 23:09:36 +00:00
|
|
|
$policy = $wgArticleRobotPolicies[$this->mTitle->getPrefixedText()];
|
2007-01-14 21:28:23 +00:00
|
|
|
} elseif( isset( $wgNamespaceRobotPolicies[$ns] ) ) {
|
|
|
|
|
# Honour customised robot policies for this namespace
|
2006-06-04 00:25:53 +00:00
|
|
|
$policy = $wgNamespaceRobotPolicies[$ns];
|
|
|
|
|
} else {
|
2008-02-06 00:55:52 +00:00
|
|
|
$policy = $wgDefaultRobotPolicy;
|
2006-06-04 00:25:53 +00:00
|
|
|
}
|
2007-01-14 21:28:23 +00:00
|
|
|
$wgOut->setRobotPolicy( $policy );
|
2006-06-04 00:25:53 +00:00
|
|
|
|
2003-04-14 23:10:40 +00:00
|
|
|
# If we got diff and oldid in the query, we want to see a
|
|
|
|
|
# diff page instead of the article.
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !is_null( $diff ) ) {
|
2003-09-01 08:30:14 +00:00
|
|
|
$wgOut->setPageTitle( $this->mTitle->getPrefixedText() );
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2008-08-21 00:45:13 +00:00
|
|
|
$diff = $wgRequest->getVal( 'diff' );
|
2008-08-22 16:53:56 +00:00
|
|
|
$htmldiff = $wgRequest->getVal( 'htmldiff' , false);
|
2008-08-21 00:45:13 +00:00
|
|
|
$de = new DifferenceEngine( $this->mTitle, $oldid, $diff, $rcid, $purge, $htmldiff);
|
2005-03-29 16:38:30 +00:00
|
|
|
// DifferenceEngine directly fetched the revision:
|
|
|
|
|
$this->mRevIdFetched = $de->mNewid;
|
2007-01-12 03:36:46 +00:00
|
|
|
$de->showDiffPage( $diffOnly );
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-09-10 21:46:54 +00:00
|
|
|
// Needed to get the page's current revision
|
|
|
|
|
$this->loadPageData();
|
|
|
|
|
if( $diff == 0 || $diff == $this->mLatest ) {
|
2004-08-03 04:52:19 +00:00
|
|
|
# Run view updates for current revision only
|
|
|
|
|
$this->viewUpdates();
|
|
|
|
|
}
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2003-04-14 23:10:40 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2009-01-14 23:42:57 +00:00
|
|
|
|
|
|
|
|
if( $ns == NS_USER || $ns == NS_USER_TALK ) {
|
|
|
|
|
# User/User_talk subpages are not modified. (bug 11443)
|
|
|
|
|
if( !$this->mTitle->isSubpage() ) {
|
|
|
|
|
$block = new Block();
|
|
|
|
|
if( $block->load( $this->mTitle->getBaseText() ) ) {
|
|
|
|
|
$wgOut->setRobotpolicy( 'noindex,nofollow' );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2004-06-04 10:40:44 +00:00
|
|
|
# Should the parser cache be used?
|
2008-07-03 19:05:06 +00:00
|
|
|
$pcache = $this->useParserCache( $oldid );
|
2005-06-29 23:44:03 +00:00
|
|
|
wfDebug( 'Article::view using parser cache: ' . ($pcache ? 'yes' : 'no' ) . "\n" );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $wgUser->getOption( 'stubthreshold' ) ) {
|
2005-12-26 13:01:18 +00:00
|
|
|
wfIncrStats( 'pcache_miss_stub' );
|
|
|
|
|
}
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2006-01-13 00:29:20 +00:00
|
|
|
$wasRedirected = false;
|
2008-11-28 14:29:25 +00:00
|
|
|
if( isset( $this->mRedirectedFrom ) ) {
|
2006-01-13 00:29:20 +00:00
|
|
|
// This is an internally redirected page view.
|
|
|
|
|
// We'll need a backlink to the source page for navigation.
|
2008-11-28 14:29:25 +00:00
|
|
|
if( wfRunHooks( 'ArticleViewRedirect', array( &$this ) ) ) {
|
2006-11-08 07:12:03 +00:00
|
|
|
$redir = $sk->makeKnownLinkObj( $this->mRedirectedFrom, '', 'redirect=no' );
|
2008-12-22 18:30:13 +00:00
|
|
|
$s = wfMsgExt( 'redirectedfrom', array( 'parseinline', 'replaceafter' ), $redir );
|
2006-01-13 00:29:20 +00:00
|
|
|
$wgOut->setSubtitle( $s );
|
2006-12-08 06:09:15 +00:00
|
|
|
|
|
|
|
|
// Set the fragment if one was specified in the redirect
|
2008-11-28 14:29:25 +00:00
|
|
|
if( strval( $this->mTitle->getFragment() ) != '' ) {
|
2006-12-08 06:09:15 +00:00
|
|
|
$fragment = Xml::escapeJsString( $this->mTitle->getFragmentForURL() );
|
|
|
|
|
$wgOut->addInlineScript( "redirectToFragment(\"$fragment\");" );
|
|
|
|
|
}
|
2006-01-13 00:29:20 +00:00
|
|
|
$wasRedirected = true;
|
|
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
} elseif( !empty( $rdfrom ) ) {
|
2006-01-13 00:29:20 +00:00
|
|
|
// This is an externally redirected view, from some other wiki.
|
|
|
|
|
// If it was reported from a trusted site, supply a backlink.
|
|
|
|
|
global $wgRedirectSources;
|
|
|
|
|
if( $wgRedirectSources && preg_match( $wgRedirectSources, $rdfrom ) ) {
|
2006-11-08 07:12:03 +00:00
|
|
|
$redir = $sk->makeExternalLink( $rdfrom, $rdfrom );
|
2008-12-22 18:30:13 +00:00
|
|
|
$s = wfMsgExt( 'redirectedfrom', array( 'parseinline', 'replaceafter' ), $redir );
|
2006-01-13 00:29:20 +00:00
|
|
|
$wgOut->setSubtitle( $s );
|
|
|
|
|
$wasRedirected = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2004-06-04 10:40:44 +00:00
|
|
|
$outputDone = false;
|
2007-06-03 22:31:09 +00:00
|
|
|
wfRunHooks( 'ArticleViewHeader', array( &$this, &$outputDone, &$pcache ) );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $pcache && $wgOut->tryParserCache( $this, $wgUser ) ) {
|
|
|
|
|
// Ensure that UI elements requiring revision ID have
|
|
|
|
|
// the correct version information.
|
|
|
|
|
$wgOut->setRevisionId( $this->mLatest );
|
|
|
|
|
$outputDone = true;
|
2004-06-04 10:40:44 +00:00
|
|
|
}
|
2008-07-03 19:05:06 +00:00
|
|
|
# Fetch content and check for errors
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$outputDone ) {
|
2008-09-16 18:31:55 +00:00
|
|
|
# If the article does not exist and was deleted, show the log
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $this->getID() == 0 ) {
|
|
|
|
|
$this->showDeletionLog();
|
2008-09-16 18:31:55 +00:00
|
|
|
}
|
2008-10-12 13:28:04 +00:00
|
|
|
$text = $this->getContent();
|
2009-01-12 08:11:22 +00:00
|
|
|
// For now, check also for ID until getContent actually returns
|
|
|
|
|
// false for pages that do not exists
|
|
|
|
|
if( $text === false || $this->getID() === 0 ) {
|
2005-12-30 09:33:11 +00:00
|
|
|
# Failed to load, replace text with error message
|
|
|
|
|
$t = $this->mTitle->getPrefixedText();
|
|
|
|
|
if( $oldid ) {
|
2009-01-12 08:11:22 +00:00
|
|
|
$d = wfMsgExt( 'missingarticle-rev', 'escape', $oldid );
|
|
|
|
|
$text = wfMsgExt( 'missing-article', 'parsemag', $t, $d );
|
2009-01-19 16:09:06 +00:00
|
|
|
// Always use page content for pages in the MediaWiki namespace
|
|
|
|
|
// since it contains the default message
|
|
|
|
|
} elseif ( $this->mTitle->getNamespace() != NS_MEDIAWIKI ) {
|
2009-01-12 08:11:22 +00:00
|
|
|
$text = wfMsgExt( 'noarticletext', 'parsemag' );
|
2005-12-30 09:33:11 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-12-22 23:38:58 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
# Non-existent pages
|
|
|
|
|
if( $this->getID() === 0 ) {
|
|
|
|
|
$wgOut->setRobotPolicy( 'noindex,nofollow' );
|
|
|
|
|
$text = "<div class='noarticletext'>\n$text\n</div>";
|
2008-12-22 23:38:58 +00:00
|
|
|
if( !$this->hasViewableContent() ) {
|
|
|
|
|
// If there's no backing content, send a 404 Not Found
|
|
|
|
|
// for better machine handling of broken links.
|
|
|
|
|
$return404 = true;
|
|
|
|
|
}
|
2009-01-13 18:37:46 +00:00
|
|
|
}
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2008-12-22 23:38:58 +00:00
|
|
|
if( $return404 ) {
|
|
|
|
|
$wgRequest->response()->header( "HTTP/1.x 404 Not Found" );
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-13 00:29:20 +00:00
|
|
|
# Another whitelist check in case oldid is altering the title
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$this->mTitle->userCanRead() ) {
|
2004-06-04 10:40:44 +00:00
|
|
|
$wgOut->loginToUse();
|
|
|
|
|
$wgOut->output();
|
2009-01-02 15:56:33 +00:00
|
|
|
$wgOut->disable();
|
2008-04-28 17:05:25 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2009-01-02 15:56:33 +00:00
|
|
|
return;
|
2004-06-04 10:40:44 +00:00
|
|
|
}
|
2009-01-03 05:51:15 +00:00
|
|
|
|
|
|
|
|
# For ?curid=x urls, disallow indexing
|
|
|
|
|
if( $wgRequest->getInt('curid') )
|
|
|
|
|
$wgOut->setRobotPolicy( 'noindex,follow' );
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2004-06-04 10:40:44 +00:00
|
|
|
# We're looking at an old revision
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !empty( $oldid ) ) {
|
2008-07-23 19:05:43 +00:00
|
|
|
$wgOut->setRobotPolicy( 'noindex,nofollow' );
|
2006-03-18 22:23:50 +00:00
|
|
|
if( is_null( $this->mRevision ) ) {
|
|
|
|
|
// FIXME: This would be a nice place to load the 'no such page' text.
|
|
|
|
|
} else {
|
|
|
|
|
$this->setOldSubtitle( isset($this->mOldId) ? $this->mOldId : $oldid );
|
2006-06-23 06:31:46 +00:00
|
|
|
if( $this->mRevision->isDeleted( Revision::DELETED_TEXT ) ) {
|
|
|
|
|
if( !$this->mRevision->userCan( Revision::DELETED_TEXT ) ) {
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->addWikiMsg( 'rev-deleted-text-permission' );
|
2006-03-18 22:23:50 +00:00
|
|
|
$wgOut->setPageTitle( $this->mTitle->getPrefixedText() );
|
2008-04-28 17:02:20 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2006-03-18 22:23:50 +00:00
|
|
|
return;
|
|
|
|
|
} else {
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->addWikiMsg( 'rev-deleted-text-view' );
|
2006-03-18 22:23:50 +00:00
|
|
|
// and we are allowed to see...
|
|
|
|
|
}
|
2006-03-16 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
2004-06-04 10:40:44 +00:00
|
|
|
}
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2006-01-01 22:07:14 +00:00
|
|
|
$wgOut->setRevisionId( $this->getRevIdFetched() );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-06-29 04:31:19 +00:00
|
|
|
// Pages containing custom CSS or JavaScript get special treatment
|
|
|
|
|
if( $this->mTitle->isCssOrJsPage() || $this->mTitle->isCssJsSubpage() ) {
|
2008-11-06 22:20:29 +00:00
|
|
|
$wgOut->addHTML( wfMsgExt( 'clearyourcache', 'parse' ) );
|
2007-07-02 23:22:39 +00:00
|
|
|
// Give hooks a chance to customise the output
|
|
|
|
|
if( wfRunHooks( 'ShowRawCssJs', array( $this->mContent, $this->mTitle, $wgOut ) ) ) {
|
|
|
|
|
// Wrap the whole lot in a <pre> and don't parse
|
2007-08-21 03:57:54 +00:00
|
|
|
$m = array();
|
2007-07-02 23:22:39 +00:00
|
|
|
preg_match( '!\.(css|js)$!u', $this->mTitle->getText(), $m );
|
2008-11-06 22:20:29 +00:00
|
|
|
$wgOut->addHTML( "<pre class=\"mw-code mw-{$m[1]}\" dir=\"ltr\">\n" );
|
|
|
|
|
$wgOut->addHTML( htmlspecialchars( $this->mContent ) );
|
|
|
|
|
$wgOut->addHTML( "\n</pre>\n" );
|
2007-07-02 23:22:39 +00:00
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
} else if( $rt = Title::newFromRedirect( $text ) ) {
|
2008-07-02 10:33:42 +00:00
|
|
|
# Don't append the subtitle if this was an old revision
|
2008-08-02 02:39:09 +00:00
|
|
|
$wgOut->addHTML( $this->viewRedirect( $rt, !$wasRedirected && $this->isCurrent() ) );
|
2005-03-14 07:42:38 +00:00
|
|
|
$parseout = $wgParser->parse($text, $this->mTitle, ParserOptions::newFromUser($wgUser));
|
2006-01-01 21:44:43 +00:00
|
|
|
$wgOut->addParserOutputNoText( $parseout );
|
2008-11-28 14:29:25 +00:00
|
|
|
} else if( $pcache ) {
|
2004-08-07 03:50:46 +00:00
|
|
|
# Display content and save to parser cache
|
2007-01-10 23:32:38 +00:00
|
|
|
$this->outputWikiText( $text );
|
2004-06-04 10:40:44 +00:00
|
|
|
} else {
|
2004-08-07 03:50:46 +00:00
|
|
|
# Display content, don't attempt to save to parser cache
|
2005-06-29 23:44:03 +00:00
|
|
|
# Don't show section-edit links on old revisions... this way lies madness.
|
|
|
|
|
if( !$this->isCurrent() ) {
|
2006-07-26 07:15:39 +00:00
|
|
|
$oldEditSectionSetting = $wgOut->parserOptions()->setEditSection( false );
|
2005-06-29 23:44:03 +00:00
|
|
|
}
|
2006-01-14 23:56:01 +00:00
|
|
|
# Display content and don't save to parser cache
|
2007-01-17 00:54:54 +00:00
|
|
|
# With timing hack -- TS 2006-07-26
|
|
|
|
|
$time = -wfTime();
|
2007-01-10 23:32:38 +00:00
|
|
|
$this->outputWikiText( $text, false );
|
2007-01-17 00:54:54 +00:00
|
|
|
$time += wfTime();
|
|
|
|
|
|
|
|
|
|
# Timing hack
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $time > 3 ) {
|
2007-01-17 22:32:40 +00:00
|
|
|
wfDebugLog( 'slow-parse', sprintf( "%-5.2f %s", $time,
|
2007-01-17 00:54:54 +00:00
|
|
|
$this->mTitle->getPrefixedDBkey()));
|
|
|
|
|
}
|
2005-07-01 20:36:04 +00:00
|
|
|
|
2005-06-29 23:44:03 +00:00
|
|
|
if( !$this->isCurrent() ) {
|
2006-07-26 07:15:39 +00:00
|
|
|
$wgOut->parserOptions()->setEditSection( $oldEditSectionSetting );
|
2005-06-29 23:44:03 +00:00
|
|
|
}
|
2004-06-04 10:40:44 +00:00
|
|
|
}
|
2004-02-27 02:24:14 +00:00
|
|
|
}
|
2005-04-07 23:04:08 +00:00
|
|
|
/* title may have been set from the cache */
|
2005-07-01 00:03:31 +00:00
|
|
|
$t = $wgOut->getPageTitle();
|
2005-04-07 23:04:08 +00:00
|
|
|
if( empty( $t ) ) {
|
|
|
|
|
$wgOut->setPageTitle( $this->mTitle->getPrefixedText() );
|
2008-08-06 19:20:38 +00:00
|
|
|
|
|
|
|
|
# For the main page, overwrite the <title> element with the con-
|
|
|
|
|
# tents of 'pagetitle-view-mainpage' instead of the default (if
|
|
|
|
|
# that's not empty).
|
|
|
|
|
if( $this->mTitle->equals( Title::newMainPage() ) &&
|
|
|
|
|
wfMsgForContent( 'pagetitle-view-mainpage' ) !== '' ) {
|
|
|
|
|
$wgOut->setHTMLTitle( wfMsgForContent( 'pagetitle-view-mainpage' ) );
|
|
|
|
|
}
|
2005-04-07 23:04:08 +00:00
|
|
|
}
|
2006-06-13 11:37:09 +00:00
|
|
|
|
2006-04-11 08:27:35 +00:00
|
|
|
# check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page
|
2008-07-03 19:05:06 +00:00
|
|
|
if( $ns == NS_USER_TALK && IP::isValid( $this->mTitle->getText() ) ) {
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->addWikiMsg('anontalkpagetext');
|
2006-04-11 08:27:35 +00:00
|
|
|
}
|
2005-04-07 23:04:08 +00:00
|
|
|
|
2009-01-15 17:53:19 +00:00
|
|
|
# Only diffs and new page links from RC give rcid params, so if
|
|
|
|
|
# we are just viewing the page normally with no rcid, try to find it.
|
|
|
|
|
# This is more convenient for users.
|
2009-01-16 13:23:23 +00:00
|
|
|
if( empty($rcid) && $this->mTitle->exists() && $this->mTitle->userCan('patrol') ) {
|
2009-01-15 17:53:19 +00:00
|
|
|
$firstRev = $this->mTitle->getFirstRevision();
|
2009-01-16 13:23:23 +00:00
|
|
|
$rcid = $firstRev ? $firstRev->isUnpatrolled() : 0;
|
2009-01-15 17:53:19 +00:00
|
|
|
}
|
2004-08-09 05:38:11 +00:00
|
|
|
# If we have been passed an &rcid= parameter, we want to give the user a
|
|
|
|
|
# chance to mark this new article as patrolled.
|
2008-12-17 07:17:59 +00:00
|
|
|
if( !empty($rcid) && $this->mTitle->exists() && $this->mTitle->userCan('patrol') ) {
|
2005-05-05 21:37:54 +00:00
|
|
|
$wgOut->addHTML(
|
|
|
|
|
"<div class='patrollink'>" .
|
2007-01-17 22:09:30 +00:00
|
|
|
wfMsgHtml( 'markaspatrolledlink',
|
|
|
|
|
$sk->makeKnownLinkObj( $this->mTitle, wfMsgHtml('markaspatrolledtext'),
|
|
|
|
|
"action=markpatrolled&rcid=$rcid" )
|
2005-05-05 21:37:54 +00:00
|
|
|
) .
|
|
|
|
|
'</div>'
|
|
|
|
|
);
|
2004-08-09 05:38:11 +00:00
|
|
|
}
|
|
|
|
|
|
2005-07-23 05:47:25 +00:00
|
|
|
# Trackbacks
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $wgUseTrackbacks ) {
|
2005-07-23 05:47:25 +00:00
|
|
|
$this->addTrackbacks();
|
2008-11-28 14:29:25 +00:00
|
|
|
}
|
2005-07-23 05:47:25 +00:00
|
|
|
|
2003-04-14 23:10:40 +00:00
|
|
|
$this->viewUpdates();
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
|
|
|
|
|
protected function showDeletionLog() {
|
|
|
|
|
global $wgUser, $wgOut;
|
|
|
|
|
$loglist = new LogEventsList( $wgUser->getSkin(), $wgOut );
|
|
|
|
|
$pager = new LogPager( $loglist, 'delete', false, $this->mTitle->getPrefixedText() );
|
|
|
|
|
if( $pager->getNumRows() > 0 ) {
|
|
|
|
|
$pager->mLimit = 10;
|
|
|
|
|
$wgOut->addHTML( '<div class="mw-warning-with-logexcerpt">' );
|
|
|
|
|
$wgOut->addWikiMsg( 'deleted-notice' );
|
|
|
|
|
$wgOut->addHTML(
|
|
|
|
|
$loglist->beginLogEventsList() .
|
|
|
|
|
$pager->getBody() .
|
|
|
|
|
$loglist->endLogEventsList()
|
|
|
|
|
);
|
|
|
|
|
if( $pager->getNumRows() > 10 ) {
|
|
|
|
|
$wgOut->addHTML( $wgUser->getSkin()->link(
|
|
|
|
|
SpecialPage::getTitleFor( 'Log' ),
|
|
|
|
|
wfMsgHtml( 'deletelog-fulllog' ),
|
|
|
|
|
array(),
|
|
|
|
|
array( 'type' => 'delete', 'page' => $this->mTitle->getPrefixedText() )
|
|
|
|
|
) );
|
|
|
|
|
}
|
|
|
|
|
$wgOut->addHTML( '</div>' );
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-08-08 00:01:53 +00:00
|
|
|
|
|
|
|
|
/*
|
2008-07-03 19:05:06 +00:00
|
|
|
* Should the parser cache be used?
|
|
|
|
|
*/
|
|
|
|
|
protected function useParserCache( $oldid ) {
|
|
|
|
|
global $wgUser, $wgEnableParserCache;
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2008-07-03 19:05:06 +00:00
|
|
|
return $wgEnableParserCache
|
|
|
|
|
&& intval( $wgUser->getOption( 'stubthreshold' ) ) == 0
|
|
|
|
|
&& $this->exists()
|
|
|
|
|
&& empty( $oldid )
|
|
|
|
|
&& !$this->mTitle->isCssOrJsPage()
|
|
|
|
|
&& !$this->mTitle->isCssJsSubpage();
|
|
|
|
|
}
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2008-08-02 02:39:09 +00:00
|
|
|
/**
|
|
|
|
|
* View redirect
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $target Title object of destination to redirect
|
|
|
|
|
* @param $appendSubtitle Boolean [optional]
|
|
|
|
|
* @param $forceKnown Boolean: should the image be shown as a bluelink regardless of existence?
|
2008-08-02 02:39:09 +00:00
|
|
|
*/
|
|
|
|
|
public function viewRedirect( $target, $appendSubtitle = true, $forceKnown = false ) {
|
2008-05-11 19:49:08 +00:00
|
|
|
global $wgParser, $wgOut, $wgContLang, $wgStylePath, $wgUser;
|
|
|
|
|
# Display redirect
|
|
|
|
|
$imageDir = $wgContLang->isRTL() ? 'rtl' : 'ltr';
|
|
|
|
|
$imageUrl = $wgStylePath.'/common/images/redirect' . $imageDir . '.png';
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2008-07-02 10:33:42 +00:00
|
|
|
if( $appendSubtitle ) {
|
|
|
|
|
$wgOut->appendSubtitle( wfMsgHtml( 'redirectpagesub' ) );
|
2008-05-11 19:49:08 +00:00
|
|
|
}
|
|
|
|
|
$sk = $wgUser->getSkin();
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $forceKnown ) {
|
2008-05-11 19:49:08 +00:00
|
|
|
$link = $sk->makeKnownLinkObj( $target, htmlspecialchars( $target->getFullText() ) );
|
2008-11-28 14:29:25 +00:00
|
|
|
} else {
|
2008-05-11 19:49:08 +00:00
|
|
|
$link = $sk->makeLinkObj( $target, htmlspecialchars( $target->getFullText() ) );
|
2008-11-28 14:29:25 +00:00
|
|
|
}
|
2008-08-02 02:39:09 +00:00
|
|
|
return '<img src="'.$imageUrl.'" alt="#REDIRECT " />' .
|
|
|
|
|
'<span class="redirectText">'.$link.'</span>';
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2008-05-11 19:49:08 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
public function addTrackbacks() {
|
2005-07-23 06:30:26 +00:00
|
|
|
global $wgOut, $wgUser;
|
2008-11-28 14:29:25 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
$tbs = $dbr->select( 'trackbacks',
|
|
|
|
|
array('tb_id', 'tb_title', 'tb_url', 'tb_ex', 'tb_name'),
|
|
|
|
|
array('tb_page' => $this->getID() )
|
2005-07-23 05:47:25 +00:00
|
|
|
);
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$dbr->numRows($tbs) ) return;
|
2005-07-23 05:47:25 +00:00
|
|
|
|
|
|
|
|
$tbtext = "";
|
2008-11-28 14:29:25 +00:00
|
|
|
while( $o = $dbr->fetchObject($tbs) ) {
|
2005-08-02 13:35:19 +00:00
|
|
|
$rmvtxt = "";
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $wgUser->isAllowed( 'trackback' ) ) {
|
|
|
|
|
$delurl = $this->mTitle->getFullURL("action=deletetrackback&tbid=" .
|
|
|
|
|
$o->tb_id . "&token=" . urlencode( $wgUser->editToken() ) );
|
2007-06-23 10:15:10 +00:00
|
|
|
$rmvtxt = wfMsg( 'trackbackremove', htmlspecialchars( $delurl ) );
|
2005-07-23 06:30:26 +00:00
|
|
|
}
|
2008-03-25 21:50:23 +00:00
|
|
|
$tbtext .= "\n";
|
2005-07-23 05:47:25 +00:00
|
|
|
$tbtext .= wfMsg(strlen($o->tb_ex) ? 'trackbackexcerpt' : 'trackback',
|
|
|
|
|
$o->tb_title,
|
|
|
|
|
$o->tb_url,
|
|
|
|
|
$o->tb_ex,
|
2005-07-23 06:30:26 +00:00
|
|
|
$o->tb_name,
|
|
|
|
|
$rmvtxt);
|
2005-07-23 05:47:25 +00:00
|
|
|
}
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->addWikiMsg( 'trackbackbox', $tbtext );
|
2008-11-28 14:29:25 +00:00
|
|
|
$this->mTitle->invalidateCache();
|
2005-07-23 05:47:25 +00:00
|
|
|
}
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
public function deletetrackback() {
|
2005-07-23 06:30:26 +00:00
|
|
|
global $wgUser, $wgRequest, $wgOut, $wgTitle;
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$wgUser->matchEditToken($wgRequest->getVal('token')) ) {
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->addWikiMsg( 'sessionfailure' );
|
2005-07-23 06:30:26 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-09 08:11:58 +00:00
|
|
|
$permission_errors = $this->mTitle->getUserPermissionsErrors( 'delete', $wgUser );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( count($permission_errors) ) {
|
2007-09-09 08:11:58 +00:00
|
|
|
$wgOut->showPermissionsErrorPage( $permission_errors );
|
2005-07-23 06:30:26 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
$db = wfGetDB( DB_MASTER );
|
|
|
|
|
$db->delete( 'trackbacks', array('tb_id' => $wgRequest->getInt('tbid')) );
|
|
|
|
|
|
|
|
|
|
$wgOut->addWikiMsg( 'trackbackdeleteok' );
|
|
|
|
|
$this->mTitle->invalidateCache();
|
2005-07-23 06:30:26 +00:00
|
|
|
}
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
public function render() {
|
2005-07-03 04:00:33 +00:00
|
|
|
global $wgOut;
|
|
|
|
|
$wgOut->setArticleBodyOnly(true);
|
|
|
|
|
$this->view();
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2006-03-01 01:27:36 +00:00
|
|
|
/**
|
|
|
|
|
* Handle action=purge
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function purge() {
|
2006-03-01 01:27:36 +00:00
|
|
|
global $wgUser, $wgRequest, $wgOut;
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $wgUser->isAllowed( 'purge' ) || $wgRequest->wasPosted() ) {
|
2006-03-01 01:27:36 +00:00
|
|
|
if( wfRunHooks( 'ArticlePurge', array( &$this ) ) ) {
|
|
|
|
|
$this->doPurge();
|
2008-08-19 19:10:07 +00:00
|
|
|
$this->view();
|
2005-11-07 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
2008-10-23 20:44:56 +00:00
|
|
|
$action = htmlspecialchars( $wgRequest->getRequestURL() );
|
|
|
|
|
$button = wfMsgExt( 'confirm_purge_button', array('escapenoentities') );
|
|
|
|
|
$form = "<form method=\"post\" action=\"$action\">\n" .
|
|
|
|
|
"<input type=\"submit\" name=\"submit\" value=\"$button\" />\n" .
|
|
|
|
|
"</form>\n";
|
|
|
|
|
$top = wfMsgExt( 'confirm-purge-top', array('parse') );
|
|
|
|
|
$bottom = wfMsgExt( 'confirm-purge-bottom', array('parse') );
|
2005-11-07 04:14:15 +00:00
|
|
|
$wgOut->setPageTitle( $this->mTitle->getPrefixedText() );
|
2008-07-23 19:05:43 +00:00
|
|
|
$wgOut->setRobotPolicy( 'noindex,nofollow' );
|
2008-10-23 20:44:56 +00:00
|
|
|
$wgOut->addHTML( $top . $form . $bottom );
|
2005-11-07 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-03-01 01:27:36 +00:00
|
|
|
/**
|
|
|
|
|
* Perform the actions of a page purging
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function doPurge() {
|
2006-03-01 01:27:36 +00:00
|
|
|
global $wgUseSquid;
|
|
|
|
|
// Invalidate the cache
|
|
|
|
|
$this->mTitle->invalidateCache();
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $wgUseSquid ) {
|
2006-03-01 01:27:36 +00:00
|
|
|
// Commit the transaction before the purge is sent
|
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
$dbw->immediateCommit();
|
|
|
|
|
|
|
|
|
|
// Send purge
|
|
|
|
|
$update = SquidUpdate::newSimplePurge( $this->mTitle );
|
|
|
|
|
$update->doUpdate();
|
|
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
|
2008-02-09 10:01:35 +00:00
|
|
|
global $wgMessageCache;
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $this->getID() == 0 ) {
|
2008-02-13 05:46:43 +00:00
|
|
|
$text = false;
|
|
|
|
|
} else {
|
2009-01-10 13:41:22 +00:00
|
|
|
$text = $this->getRawText();
|
2008-02-13 05:46:43 +00:00
|
|
|
}
|
2008-02-09 10:01:35 +00:00
|
|
|
$wgMessageCache->replace( $this->mTitle->getDBkey(), $text );
|
|
|
|
|
}
|
2006-03-01 01:27:36 +00:00
|
|
|
}
|
2005-07-03 04:00:33 +00:00
|
|
|
|
2005-03-11 08:38:24 +00:00
|
|
|
/**
|
|
|
|
|
* Insert a new empty page record for this article.
|
|
|
|
|
* This *must* be followed up by creating a revision
|
|
|
|
|
* and running $this->updateToLatest( $rev_id );
|
|
|
|
|
* or else the record will be left in a funky state.
|
|
|
|
|
* Best if all done inside a transaction.
|
|
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $dbw Database
|
|
|
|
|
* @return int The newly created page_id key, or false if the title already existed
|
2006-04-19 15:46:24 +00:00
|
|
|
* @private
|
2005-03-11 08:38:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function insertOn( $dbw ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2005-03-11 08:38:24 +00:00
|
|
|
$page_id = $dbw->nextSequenceValue( 'page_page_id_seq' );
|
|
|
|
|
$dbw->insert( 'page', array(
|
|
|
|
|
'page_id' => $page_id,
|
|
|
|
|
'page_namespace' => $this->mTitle->getNamespace(),
|
|
|
|
|
'page_title' => $this->mTitle->getDBkey(),
|
|
|
|
|
'page_counter' => 0,
|
2007-01-19 09:50:19 +00:00
|
|
|
'page_restrictions' => '',
|
2005-03-11 08:38:24 +00:00
|
|
|
'page_is_redirect' => 0, # Will set this shortly...
|
|
|
|
|
'page_is_new' => 1,
|
|
|
|
|
'page_random' => wfRandom(),
|
|
|
|
|
'page_touched' => $dbw->timestamp(),
|
|
|
|
|
'page_latest' => 0, # Fill this in shortly...
|
2005-10-25 23:26:14 +00:00
|
|
|
'page_len' => 0, # Fill this in shortly...
|
2008-09-25 10:15:19 +00:00
|
|
|
), __METHOD__, 'IGNORE' );
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2008-09-25 10:15:19 +00:00
|
|
|
$affected = $dbw->affectedRows();
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $affected ) {
|
2008-09-25 10:15:19 +00:00
|
|
|
$newid = $dbw->insertId();
|
|
|
|
|
$this->mTitle->resetArticleId( $newid );
|
|
|
|
|
}
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2008-09-25 10:15:19 +00:00
|
|
|
return $affected ? $newid : false;
|
2005-03-11 08:38:24 +00:00
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2005-03-11 08:38:24 +00:00
|
|
|
/**
|
|
|
|
|
* Update the page record to point to a newly saved revision.
|
|
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $dbw Database object
|
|
|
|
|
* @param $revision Revision: For ID number, and text used to set
|
|
|
|
|
length and redirect status fields
|
|
|
|
|
* @param $lastRevision Integer: if given, will not overwrite the page field
|
|
|
|
|
* when different from the currently set value.
|
|
|
|
|
* Giving 0 indicates the new page flag should be set
|
|
|
|
|
* on.
|
|
|
|
|
* @param $lastRevIsRedirect Boolean: if given, will optimize adding and
|
|
|
|
|
* removing rows in redirect table.
|
2005-03-11 08:38:24 +00:00
|
|
|
* @return bool true on success, false on failure
|
2006-04-19 15:46:24 +00:00
|
|
|
* @private
|
2005-03-11 08:38:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function updateRevisionOn( &$dbw, $revision, $lastRevision = null, $lastRevIsRedirect = null ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2006-10-29 21:25:40 +00:00
|
|
|
$text = $revision->getText();
|
|
|
|
|
$rt = Title::newFromRedirect( $text );
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2005-03-12 10:50:51 +00:00
|
|
|
$conditions = array( 'page_id' => $this->getId() );
|
|
|
|
|
if( !is_null( $lastRevision ) ) {
|
|
|
|
|
# An extra check against threads stepping on each other
|
|
|
|
|
$conditions['page_latest'] = $lastRevision;
|
|
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2005-03-11 08:38:24 +00:00
|
|
|
$dbw->update( 'page',
|
|
|
|
|
array( /* SET */
|
2005-03-13 07:49:15 +00:00
|
|
|
'page_latest' => $revision->getId(),
|
2005-03-11 08:38:24 +00:00
|
|
|
'page_touched' => $dbw->timestamp(),
|
2005-06-14 19:24:03 +00:00
|
|
|
'page_is_new' => ($lastRevision === 0) ? 1 : 0,
|
2006-10-29 21:25:40 +00:00
|
|
|
'page_is_redirect' => $rt !== NULL ? 1 : 0,
|
2005-03-12 11:51:02 +00:00
|
|
|
'page_len' => strlen( $text ),
|
2005-03-12 10:50:51 +00:00
|
|
|
),
|
|
|
|
|
$conditions,
|
2006-06-20 09:50:57 +00:00
|
|
|
__METHOD__ );
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2006-10-31 15:57:37 +00:00
|
|
|
$result = $dbw->affectedRows() != 0;
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $result ) {
|
2007-01-17 22:32:40 +00:00
|
|
|
$this->updateRedirectOn( $dbw, $rt, $lastRevIsRedirect );
|
2006-10-31 15:57:37 +00:00
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2006-10-31 15:57:37 +00:00
|
|
|
return $result;
|
2005-03-11 08:38:24 +00:00
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2006-10-29 21:25:40 +00:00
|
|
|
/**
|
2007-01-17 22:32:40 +00:00
|
|
|
* Add row to the redirect table if this is a redirect, remove otherwise.
|
2006-10-29 21:25:40 +00:00
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $dbw Database
|
2006-10-29 21:25:40 +00:00
|
|
|
* @param $redirectTitle a title object pointing to the redirect target,
|
2008-11-30 10:10:15 +00:00
|
|
|
* or NULL if this is not a redirect
|
|
|
|
|
* @param $lastRevIsRedirect If given, will optimize adding and
|
|
|
|
|
* removing rows in redirect table.
|
2006-10-29 21:25:40 +00:00
|
|
|
* @return bool true on success, false on failure
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function updateRedirectOn( &$dbw, $redirectTitle, $lastRevIsRedirect = null ) {
|
2006-10-29 21:25:40 +00:00
|
|
|
// Always update redirects (target link might have changed)
|
|
|
|
|
// Update/Insert if we don't know if the last revision was a redirect or not
|
|
|
|
|
// Delete if changing from redirect to non-redirect
|
|
|
|
|
$isRedirect = !is_null($redirectTitle);
|
2008-11-28 14:29:25 +00:00
|
|
|
if($isRedirect || is_null($lastRevIsRedirect) || $lastRevIsRedirect !== $isRedirect) {
|
2006-10-29 21:25:40 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $isRedirect ) {
|
2006-10-29 21:25:40 +00:00
|
|
|
// This title is a redirect, Add/Update row in the redirect table
|
|
|
|
|
$set = array( /* SET */
|
|
|
|
|
'rd_namespace' => $redirectTitle->getNamespace(),
|
2006-11-01 21:02:00 +00:00
|
|
|
'rd_title' => $redirectTitle->getDBkey(),
|
|
|
|
|
'rd_from' => $this->getId(),
|
2006-10-29 21:25:40 +00:00
|
|
|
);
|
2006-11-01 21:02:00 +00:00
|
|
|
$dbw->replace( 'redirect', array( 'rd_from' ), $set, __METHOD__ );
|
2006-10-29 21:25:40 +00:00
|
|
|
} else {
|
2007-01-17 22:32:40 +00:00
|
|
|
// This is not a redirect, remove row from redirect table
|
2006-11-01 21:02:00 +00:00
|
|
|
$where = array( 'rd_from' => $this->getId() );
|
2006-10-29 21:25:40 +00:00
|
|
|
$dbw->delete( 'redirect', $where, __METHOD__);
|
|
|
|
|
}
|
2008-12-01 17:14:30 +00:00
|
|
|
if( $this->getTitle()->getNamespace() == NS_FILE ) {
|
2008-04-12 18:04:46 +00:00
|
|
|
RepoGroup::singleton()->getLocalRepo()->invalidateImageRedirect( $this->getTitle() );
|
2008-11-28 14:29:25 +00:00
|
|
|
}
|
2006-10-29 21:25:40 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2007-12-31 20:26:53 +00:00
|
|
|
return ( $dbw->affectedRows() != 0 );
|
2006-10-29 21:25:40 +00:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-13 07:22:20 +00:00
|
|
|
/**
|
|
|
|
|
* If the given revision is newer than the currently set page_latest,
|
|
|
|
|
* update the page record. Otherwise, do nothing.
|
|
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $dbw Database object
|
|
|
|
|
* @param $revision Revision object
|
2005-03-13 07:22:20 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function updateIfNewerOn( &$dbw, $revision ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2005-03-13 07:22:20 +00:00
|
|
|
$row = $dbw->selectRow(
|
|
|
|
|
array( 'revision', 'page' ),
|
2006-10-29 21:25:40 +00:00
|
|
|
array( 'rev_id', 'rev_timestamp', 'page_is_redirect' ),
|
2005-03-13 07:22:20 +00:00
|
|
|
array(
|
|
|
|
|
'page_id' => $this->getId(),
|
|
|
|
|
'page_latest=rev_id' ),
|
2006-06-20 09:50:57 +00:00
|
|
|
__METHOD__ );
|
2005-03-13 07:22:20 +00:00
|
|
|
if( $row ) {
|
2005-08-02 13:35:19 +00:00
|
|
|
if( wfTimestamp(TS_MW, $row->rev_timestamp) >= $revision->getTimestamp() ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2005-03-13 07:22:20 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$prev = $row->rev_id;
|
2006-10-31 15:57:37 +00:00
|
|
|
$lastRevIsRedirect = (bool)$row->page_is_redirect;
|
2005-03-13 07:22:20 +00:00
|
|
|
} else {
|
|
|
|
|
# No or missing previous revision; mark the page as new
|
|
|
|
|
$prev = 0;
|
2006-10-29 21:25:40 +00:00
|
|
|
$lastRevIsRedirect = null;
|
2005-03-13 07:22:20 +00:00
|
|
|
}
|
2006-10-29 21:25:40 +00:00
|
|
|
$ret = $this->updateRevisionOn( $dbw, $revision, $prev, $lastRevIsRedirect );
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2005-03-13 07:22:20 +00:00
|
|
|
return $ret;
|
|
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2005-10-28 07:07:21 +00:00
|
|
|
/**
|
2008-12-12 01:05:51 +00:00
|
|
|
* @param $section empty/null/false or a section number (0, 1, 2, T1, T2...)
|
2005-10-28 07:07:21 +00:00
|
|
|
* @return string Complete article text, or null if error
|
|
|
|
|
*/
|
2008-11-29 16:52:10 +00:00
|
|
|
public function replaceSection( $section, $text, $summary = '', $edittime = NULL ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2008-12-12 01:05:51 +00:00
|
|
|
if( strval( $section ) == '' ) {
|
2008-11-28 14:29:25 +00:00
|
|
|
// Whole-page edit; let the whole text through
|
2006-06-06 00:51:34 +00:00
|
|
|
} else {
|
2008-11-28 14:29:25 +00:00
|
|
|
if( is_null($edittime) ) {
|
2005-04-26 09:52:11 +00:00
|
|
|
$rev = Revision::newFromTitle( $this->mTitle );
|
|
|
|
|
} else {
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2005-04-26 09:52:11 +00:00
|
|
|
$rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime );
|
|
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$rev ) {
|
2005-10-28 07:07:21 +00:00
|
|
|
wfDebug( "Article::replaceSection asked for bogus section (page: " .
|
|
|
|
|
$this->getId() . "; section: $section; edittime: $edittime)\n" );
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2005-04-26 09:52:11 +00:00
|
|
|
$oldtext = $rev->getText();
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2006-12-18 19:30:26 +00:00
|
|
|
if( $section == 'new' ) {
|
|
|
|
|
# Inserting a new section
|
2007-09-02 01:41:56 +00:00
|
|
|
$subject = $summary ? wfMsgForContent('newsectionheaderdefaultlevel',$summary) . "\n\n" : '';
|
2006-12-18 19:30:26 +00:00
|
|
|
$text = strlen( trim( $oldtext ) ) > 0
|
|
|
|
|
? "{$oldtext}\n\n{$subject}{$text}"
|
2006-12-18 19:32:41 +00:00
|
|
|
: "{$subject}{$text}";
|
2003-07-21 07:36:52 +00:00
|
|
|
} else {
|
2006-12-18 19:30:26 +00:00
|
|
|
# Replacing an existing section; roll out the big guns
|
2006-06-06 00:51:34 +00:00
|
|
|
global $wgParser;
|
|
|
|
|
$text = $wgParser->replaceSection( $oldtext, $section, $text );
|
2003-07-21 07:36:52 +00:00
|
|
|
}
|
2003-06-30 00:19:35 +00:00
|
|
|
}
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2004-03-14 22:28:52 +00:00
|
|
|
return $text;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2006-06-20 09:50:57 +00:00
|
|
|
* @deprecated use Article::doEdit()
|
|
|
|
|
*/
|
2008-01-10 13:33:23 +00:00
|
|
|
function insertNewArticle( $text, $summary, $isminor, $watchthis, $suppressRC=false, $comment=false, $bot=false ) {
|
2008-11-28 14:29:25 +00:00
|
|
|
wfDeprecated( __METHOD__ );
|
2006-11-08 08:06:51 +00:00
|
|
|
$flags = EDIT_NEW | EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY |
|
2006-06-20 09:50:57 +00:00
|
|
|
( $isminor ? EDIT_MINOR : 0 ) |
|
2008-01-13 17:58:14 +00:00
|
|
|
( $suppressRC ? EDIT_SUPPRESS_RC : 0 ) |
|
|
|
|
|
( $bot ? EDIT_FORCE_BOT : 0 );
|
2006-06-20 09:50:57 +00:00
|
|
|
|
|
|
|
|
# If this is a comment, add the summary as headline
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $comment && $summary != "" ) {
|
2007-09-02 01:41:56 +00:00
|
|
|
$text = wfMsgForContent('newsectionheaderdefaultlevel',$summary) . "\n\n".$text;
|
2006-06-20 09:50:57 +00:00
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
$this->doEdit( $text, $summary, $flags );
|
|
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2008-11-28 14:29:25 +00:00
|
|
|
if($watchthis) {
|
|
|
|
|
if(!$this->mTitle->userIsWatching()) {
|
2006-06-20 09:50:57 +00:00
|
|
|
$dbw->begin();
|
|
|
|
|
$this->doWatch();
|
|
|
|
|
$dbw->commit();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $this->mTitle->userIsWatching() ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
$dbw->begin();
|
|
|
|
|
$this->doUnwatch();
|
|
|
|
|
$dbw->commit();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->doRedirect( $this->isRedirect( $text ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @deprecated use Article::doEdit()
|
|
|
|
|
*/
|
|
|
|
|
function updateArticle( $text, $summary, $minor, $watchthis, $forceBot = false, $sectionanchor = '' ) {
|
2008-11-28 14:29:25 +00:00
|
|
|
wfDeprecated( __METHOD__ );
|
2006-11-08 08:06:51 +00:00
|
|
|
$flags = EDIT_UPDATE | EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY |
|
2006-06-20 09:50:57 +00:00
|
|
|
( $minor ? EDIT_MINOR : 0 ) |
|
|
|
|
|
( $forceBot ? EDIT_FORCE_BOT : 0 );
|
|
|
|
|
|
2008-09-25 10:15:19 +00:00
|
|
|
$status = $this->doEdit( $text, $summary, $flags );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$status->isOK() ) {
|
2008-09-25 10:15:19 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2008-11-29 16:52:10 +00:00
|
|
|
if( $watchthis ) {
|
2008-11-28 14:29:25 +00:00
|
|
|
if(!$this->mTitle->userIsWatching()) {
|
2008-09-25 10:15:19 +00:00
|
|
|
$dbw->begin();
|
|
|
|
|
$this->doWatch();
|
|
|
|
|
$dbw->commit();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $this->mTitle->userIsWatching() ) {
|
2008-09-25 10:15:19 +00:00
|
|
|
$dbw->begin();
|
|
|
|
|
$this->doUnwatch();
|
|
|
|
|
$dbw->commit();
|
2006-06-20 09:50:57 +00:00
|
|
|
}
|
2008-09-25 10:15:19 +00:00
|
|
|
}
|
2006-06-20 09:50:57 +00:00
|
|
|
|
2008-09-25 10:15:19 +00:00
|
|
|
$extraQuery = ''; // Give extensions a chance to modify URL query on update
|
|
|
|
|
wfRunHooks( 'ArticleUpdateBeforeRedirect', array( $this, &$sectionanchor, &$extraQuery ) );
|
2007-08-15 22:13:03 +00:00
|
|
|
|
2008-09-25 10:15:19 +00:00
|
|
|
$this->doRedirect( $this->isRedirect( $text ), $sectionanchor, $extraQuery );
|
|
|
|
|
return true;
|
2006-06-20 09:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Article::doEdit()
|
|
|
|
|
*
|
2007-01-17 22:32:40 +00:00
|
|
|
* Change an existing article or create a new article. Updates RC and all necessary caches,
|
2006-06-20 09:50:57 +00:00
|
|
|
* optionally via the deferred update array.
|
2004-09-11 11:39:24 +00:00
|
|
|
*
|
2006-06-20 09:50:57 +00:00
|
|
|
* $wgUser must be set before calling this function.
|
|
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $text String: new text
|
|
|
|
|
* @param $summary String: edit summary
|
|
|
|
|
* @param $flags Integer bitfield:
|
2006-06-20 09:50:57 +00:00
|
|
|
* 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
|
2006-11-08 08:06:51 +00:00
|
|
|
* EDIT_AUTOSUMMARY
|
|
|
|
|
* Fill in blank summaries with generated text where possible
|
2007-01-17 22:32:40 +00:00
|
|
|
*
|
|
|
|
|
* If neither EDIT_NEW nor EDIT_UPDATE is specified, the status of the article will be detected.
|
2008-09-25 10:15:19 +00:00
|
|
|
* 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.
|
|
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $baseRevId the revision ID this edit was based off, if any
|
|
|
|
|
* @param $user Optional user object, $wgUser will be used if not passed
|
2006-06-20 09:50:57 +00:00
|
|
|
*
|
2008-09-25 10:15:19 +00:00
|
|
|
* @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
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function doEdit( $text, $summary, $flags = 0, $baseRevId = false, $user = null ) {
|
2008-05-24 14:55:54 +00:00
|
|
|
global $wgUser, $wgDBtransactions, $wgUseAutomaticEditSummaries;
|
2008-08-21 00:45:13 +00:00
|
|
|
|
2008-09-21 02:53:24 +00:00
|
|
|
# Low-level sanity check
|
|
|
|
|
if( $this->mTitle->getText() == '' ) {
|
|
|
|
|
throw new MWException( 'Something is trying to edit an article with an empty title' );
|
2008-08-16 13:34:43 +00:00
|
|
|
}
|
2004-08-09 05:38:11 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2008-09-21 02:53:24 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
$user = is_null($user) ? $wgUser : $user;
|
2008-09-25 10:15:19 +00:00
|
|
|
$status = Status::newGood( array() );
|
|
|
|
|
|
|
|
|
|
# Load $this->mTitle->getArticleID() and $this->mLatest if it's not already
|
|
|
|
|
$this->loadPageData();
|
2004-08-09 05:38:11 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !($flags & EDIT_NEW) && !($flags & EDIT_UPDATE) ) {
|
2008-09-25 10:15:19 +00:00
|
|
|
$aid = $this->mTitle->getArticleID();
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $aid ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
$flags |= EDIT_UPDATE;
|
|
|
|
|
} else {
|
|
|
|
|
$flags |= EDIT_NEW;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !wfRunHooks( 'ArticleSave', array( &$this, &$user, &$text, &$summary,
|
|
|
|
|
$flags & EDIT_MINOR, null, null, &$flags, &$status ) ) )
|
2006-06-20 09:50:57 +00:00
|
|
|
{
|
|
|
|
|
wfDebug( __METHOD__ . ": ArticleSave hook aborted save!\n" );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $status->isOK() ) {
|
2008-09-25 10:15:19 +00:00
|
|
|
$status->fatal( 'edit-hook-aborted');
|
|
|
|
|
}
|
|
|
|
|
return $status;
|
2005-08-23 08:15:14 +00:00
|
|
|
}
|
|
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
# Silently ignore EDIT_MINOR if not allowed
|
2008-08-16 13:34:43 +00:00
|
|
|
$isminor = ( $flags & EDIT_MINOR ) && $user->isAllowed('minoredit');
|
2008-01-10 13:33:23 +00:00
|
|
|
$bot = $flags & EDIT_FORCE_BOT;
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2009-01-10 13:41:22 +00:00
|
|
|
$oldtext = $this->getRawText(); // current revision
|
2006-11-20 11:48:03 +00:00
|
|
|
$oldsize = strlen( $oldtext );
|
|
|
|
|
|
2008-05-24 14:55:54 +00:00
|
|
|
# Provide autosummaries if one is not provided and autosummaries are enabled.
|
|
|
|
|
if( $wgUseAutomaticEditSummaries && $flags & EDIT_AUTOSUMMARY && $summary == '' ) {
|
2006-11-20 11:48:03 +00:00
|
|
|
$summary = $this->getAutosummary( $oldtext, $text, $flags );
|
2008-05-24 14:55:54 +00:00
|
|
|
}
|
2006-11-06 17:59:02 +00:00
|
|
|
|
2007-11-12 07:30:40 +00:00
|
|
|
$editInfo = $this->prepareTextForEdit( $text );
|
|
|
|
|
$text = $editInfo->pst;
|
2006-12-20 00:06:15 +00:00
|
|
|
$newsize = strlen( $text );
|
2006-06-20 09:50:57 +00:00
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2005-04-10 18:23:11 +00:00
|
|
|
$now = wfTimestampNow();
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $flags & EDIT_UPDATE ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
# Update article, but only if changed.
|
2008-09-25 10:15:19 +00:00
|
|
|
$status->value['new'] = false;
|
2006-06-20 09:50:57 +00:00
|
|
|
# Make sure the revision is either completely inserted or not inserted at all
|
|
|
|
|
if( !$wgDBtransactions ) {
|
|
|
|
|
$userAbort = ignore_user_abort( true );
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
$revisionId = 0;
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-09-12 15:03:46 +00:00
|
|
|
$changed = ( strcmp( $text, $oldtext ) != 0 );
|
2008-09-21 07:56:09 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $changed ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
$this->mGoodAdjustment = (int)$this->isCountable( $text )
|
|
|
|
|
- (int)$this->isCountable( $oldtext );
|
|
|
|
|
$this->mTotalAdjustment = 0;
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$this->mLatest ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
# Article gone missing
|
|
|
|
|
wfDebug( __METHOD__.": EDIT_UPDATE specified but article doesn't exist\n" );
|
2008-09-25 10:15:19 +00:00
|
|
|
$status->fatal( 'edit-gone-missing' );
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2008-09-25 10:15:19 +00:00
|
|
|
return $status;
|
2006-06-20 09:50:57 +00:00
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
$revision = new Revision( array(
|
|
|
|
|
'page' => $this->getId(),
|
|
|
|
|
'comment' => $summary,
|
|
|
|
|
'minor_edit' => $isminor,
|
2008-04-07 23:53:57 +00:00
|
|
|
'text' => $text,
|
2008-09-25 10:15:19 +00:00
|
|
|
'parent_id' => $this->mLatest,
|
2008-08-28 20:20:52 +00:00
|
|
|
'user' => $user->getId(),
|
|
|
|
|
'user_text' => $user->getName(),
|
2006-06-20 09:50:57 +00:00
|
|
|
) );
|
|
|
|
|
|
2008-09-21 07:56:09 +00:00
|
|
|
$dbw->begin();
|
2008-05-17 15:53:58 +00:00
|
|
|
$revisionId = $revision->insertOn( $dbw );
|
2006-06-20 09:50:57 +00:00
|
|
|
|
|
|
|
|
# Update page
|
2008-09-25 10:15:19 +00:00
|
|
|
#
|
|
|
|
|
# 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 );
|
2006-06-20 09:50:57 +00:00
|
|
|
|
|
|
|
|
if( !$ok ) {
|
|
|
|
|
/* Belated edit conflict! Run away!! */
|
2008-09-25 10:15:19 +00:00
|
|
|
$status->fatal( 'edit-conflict' );
|
|
|
|
|
# Delete the invalid revision if the DB is not transactional
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$wgDBtransactions ) {
|
2008-09-25 10:15:19 +00:00
|
|
|
$dbw->delete( 'revision', array( 'rev_id' => $revisionId ), __METHOD__ );
|
|
|
|
|
}
|
2008-09-23 18:20:50 +00:00
|
|
|
$revisionId = 0;
|
2006-06-20 09:50:57 +00:00
|
|
|
$dbw->rollback();
|
|
|
|
|
} else {
|
2008-11-27 18:55:47 +00:00
|
|
|
global $wgUseRCPatrol;
|
2008-11-27 18:32:29 +00:00
|
|
|
wfRunHooks( 'NewRevisionFromEditComplete', array($this, $revision, $baseRevId, $user) );
|
2006-06-20 09:50:57 +00:00
|
|
|
# Update recentchanges
|
|
|
|
|
if( !( $flags & EDIT_SUPPRESS_RC ) ) {
|
2008-11-27 18:55:47 +00:00
|
|
|
# Mark as patrolled if the user can do so
|
2009-01-01 23:29:30 +00:00
|
|
|
$patrolled = $wgUseRCPatrol && $this->mTitle->userCan('autopatrol');
|
2008-11-27 18:55:47 +00:00
|
|
|
# Add RC row to the DB
|
2008-09-19 00:11:41 +00:00
|
|
|
$rc = RecentChange::notifyEdit( $now, $this->mTitle, $isminor, $user, $summary,
|
2008-09-25 10:15:19 +00:00
|
|
|
$this->mLatest, $this->getTimestamp(), $bot, '', $oldsize, $newsize,
|
2008-11-27 18:55:47 +00:00
|
|
|
$revisionId, $patrolled
|
|
|
|
|
);
|
|
|
|
|
# Log auto-patrolled edits
|
|
|
|
|
if( $patrolled ) {
|
|
|
|
|
PatrolLog::record( $rc, true );
|
2006-06-20 09:50:57 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-08-16 13:34:43 +00:00
|
|
|
$user->incEditCount();
|
2008-09-21 07:56:09 +00:00
|
|
|
$dbw->commit();
|
2006-06-20 09:50:57 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
2008-09-25 10:15:19 +00:00
|
|
|
$status->warning( 'edit-no-change' );
|
2007-08-21 03:21:27 +00:00
|
|
|
$revision = null;
|
2006-06-20 09:50:57 +00:00
|
|
|
// 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();
|
|
|
|
|
}
|
2004-08-09 05:38:11 +00:00
|
|
|
|
2006-11-21 09:37:36 +00:00
|
|
|
if( !$wgDBtransactions ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
ignore_user_abort( $userAbort );
|
|
|
|
|
}
|
2008-09-25 10:15:19 +00:00
|
|
|
// Now that ignore_user_abort is restored, we can respond to fatal errors
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$status->isOK() ) {
|
2008-09-25 10:15:19 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return $status;
|
2006-06-20 09:50:57 +00:00
|
|
|
}
|
2008-09-25 10:15:19 +00:00
|
|
|
|
|
|
|
|
# Invalidate cache of this article and all pages using this article
|
2008-10-13 06:02:32 +00:00
|
|
|
# as a template. Partly deferred. Leave templatelinks for editUpdates().
|
|
|
|
|
Article::onArticleEdit( $this->mTitle, 'skiptransclusions' );
|
2008-09-25 10:15:19 +00:00
|
|
|
# Update links tables, site stats, etc.
|
|
|
|
|
$this->editUpdates( $text, $summary, $isminor, $now, $revisionId, $changed );
|
2006-06-20 09:50:57 +00:00
|
|
|
} else {
|
|
|
|
|
# Create new article
|
2008-09-25 10:15:19 +00:00
|
|
|
$status->value['new'] = true;
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
# Set statistics members
|
2007-01-17 22:32:40 +00:00
|
|
|
# We work out if it's countable after PST to avoid counter drift
|
2006-06-20 09:50:57 +00:00
|
|
|
# when articles are created with {{subst:}}
|
|
|
|
|
$this->mGoodAdjustment = (int)$this->isCountable( $text );
|
|
|
|
|
$this->mTotalAdjustment = 1;
|
2003-08-17 11:58:33 +00:00
|
|
|
|
2008-09-24 18:00:25 +00:00
|
|
|
$dbw->begin();
|
2008-09-25 10:15:19 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
# Add the page record; stake our claim on this title!
|
2008-09-25 10:15:19 +00:00
|
|
|
# This will return false if the article already exists
|
2006-06-20 09:50:57 +00:00
|
|
|
$newid = $this->insertOn( $dbw );
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $newid === false ) {
|
2008-09-25 10:15:19 +00:00
|
|
|
$dbw->rollback();
|
|
|
|
|
$status->fatal( 'edit-already-exists' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
# Save the revision text...
|
2005-03-11 06:00:05 +00:00
|
|
|
$revision = new Revision( array(
|
2006-06-20 09:50:57 +00:00
|
|
|
'page' => $newid,
|
2005-03-11 06:00:05 +00:00
|
|
|
'comment' => $summary,
|
2005-03-11 08:38:24 +00:00
|
|
|
'minor_edit' => $isminor,
|
2008-09-15 05:34:32 +00:00
|
|
|
'text' => $text,
|
|
|
|
|
'user' => $user->getId(),
|
|
|
|
|
'user_text' => $user->getName(),
|
2005-03-11 06:00:05 +00:00
|
|
|
) );
|
2008-05-17 15:53:58 +00:00
|
|
|
$revisionId = $revision->insertOn( $dbw );
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
$this->mTitle->resetArticleID( $newid );
|
2005-03-11 08:38:24 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
# Update the page record with revision data
|
|
|
|
|
$this->updateRevisionOn( $dbw, $revision, 0 );
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2008-11-27 18:32:29 +00:00
|
|
|
wfRunHooks( 'NewRevisionFromEditComplete', array($this, $revision, false, $user) );
|
2008-11-27 18:55:47 +00:00
|
|
|
# Update recentchanges
|
2006-06-20 09:50:57 +00:00
|
|
|
if( !( $flags & EDIT_SUPPRESS_RC ) ) {
|
2008-11-27 18:55:47 +00:00
|
|
|
global $wgUseRCPatrol, $wgUseNPPatrol;
|
|
|
|
|
# Mark as patrolled if the user can do so
|
2009-01-01 23:29:30 +00:00
|
|
|
$patrolled = ($wgUseRCPatrol || $wgUseNPPatrol) && $this->mTitle->userCan('autopatrol');
|
2008-11-27 18:55:47 +00:00
|
|
|
# Add RC row to the DB
|
2008-09-19 00:11:41 +00:00
|
|
|
$rc = RecentChange::notifyNew( $now, $this->mTitle, $isminor, $user, $summary, $bot,
|
2008-11-27 18:55:47 +00:00
|
|
|
'', strlen($text), $revisionId, $patrolled );
|
|
|
|
|
# Log auto-patrolled edits
|
|
|
|
|
if( $patrolled ) {
|
|
|
|
|
PatrolLog::record( $rc, true );
|
2006-03-18 22:47:40 +00:00
|
|
|
}
|
2004-06-11 14:48:31 +00:00
|
|
|
}
|
2008-08-16 13:34:43 +00:00
|
|
|
$user->incEditCount();
|
2008-09-24 18:00:25 +00:00
|
|
|
$dbw->commit();
|
2003-11-28 09:42:13 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
# Update links, etc.
|
2006-06-24 13:08:48 +00:00
|
|
|
$this->editUpdates( $text, $summary, $isminor, $now, $revisionId, true );
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
# Clear caches
|
|
|
|
|
Article::onArticleCreate( $this->mTitle );
|
2005-12-30 09:33:11 +00:00
|
|
|
|
2008-08-16 13:34:43 +00:00
|
|
|
wfRunHooks( 'ArticleInsertComplete', array( &$this, &$user, $text, $summary,
|
2008-09-20 22:48:55 +00:00
|
|
|
$flags & EDIT_MINOR, null, null, &$flags, $revision ) );
|
2004-07-10 03:09:26 +00:00
|
|
|
}
|
2006-06-20 09:50:57 +00:00
|
|
|
|
2008-09-25 10:15:19 +00:00
|
|
|
# Do updates right now unless deferral was requested
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !( $flags & EDIT_DEFER_UPDATES ) ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfDoUpdates();
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-25 10:15:19 +00:00
|
|
|
// 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 ) );
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2008-09-25 10:15:19 +00:00
|
|
|
return $status;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2006-06-18 12:42:16 +00:00
|
|
|
* @deprecated wrapper for doRedirect
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function showArticle( $text, $subtitle , $sectionanchor = '', $me2, $now, $summary, $oldid ) {
|
|
|
|
|
wfDeprecated( __METHOD__ );
|
2006-06-18 12:42:16 +00:00
|
|
|
$this->doRedirect( $this->isRedirect( $text ), $sectionanchor );
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2006-06-18 12:42:16 +00:00
|
|
|
/**
|
|
|
|
|
* Output a redirect back to the article.
|
|
|
|
|
* This is typically used after an edit.
|
|
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $noRedir Boolean: add redirect=no
|
|
|
|
|
* @param $sectionAnchor String: section to redirect to, including "#"
|
|
|
|
|
* @param $extraQuery String: extra query params
|
2006-06-18 12:42:16 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function doRedirect( $noRedir = false, $sectionAnchor = '', $extraQuery = '' ) {
|
2006-06-18 12:42:16 +00:00
|
|
|
global $wgOut;
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $noRedir ) {
|
2006-06-18 12:42:16 +00:00
|
|
|
$query = 'redirect=no';
|
2008-05-23 09:03:49 +00:00
|
|
|
if( $extraQuery )
|
2007-08-15 22:13:03 +00:00
|
|
|
$query .= "&$query";
|
2006-06-18 12:42:16 +00:00
|
|
|
} else {
|
2008-05-23 09:03:49 +00:00
|
|
|
$query = $extraQuery;
|
2006-06-18 12:42:16 +00:00
|
|
|
}
|
|
|
|
|
$wgOut->redirect( $this->mTitle->getFullURL( $query ) . $sectionAnchor );
|
|
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2007-10-29 20:38:58 +00:00
|
|
|
* Mark this particular edit/page as patrolled
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function markpatrolled() {
|
2007-10-29 20:38:58 +00:00
|
|
|
global $wgOut, $wgRequest, $wgUseRCPatrol, $wgUseNPPatrol, $wgUser;
|
2006-12-22 19:43:20 +00:00
|
|
|
$wgOut->setRobotPolicy( 'noindex,nofollow' );
|
2004-08-09 23:30:02 +00:00
|
|
|
|
2007-10-29 20:38:58 +00:00
|
|
|
# If we haven't been given an rc_id value, we can't do anything
|
|
|
|
|
$rcid = (int) $wgRequest->getVal('rcid');
|
2008-09-04 15:17:51 +00:00
|
|
|
$rc = RecentChange::newFromId($rcid);
|
2008-11-28 14:29:25 +00:00
|
|
|
if( is_null($rc) ) {
|
2008-03-24 15:04:55 +00:00
|
|
|
$wgOut->showErrorPage( 'markedaspatrollederror', 'markedaspatrollederrortext' );
|
2007-10-29 20:38:58 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-04 15:17:51 +00:00
|
|
|
#It would be nice to see where the user had actually come from, but for now just guess
|
|
|
|
|
$returnto = $rc->getAttribute( 'rc_type' ) == RC_NEW ? 'Newpages' : 'Recentchanges';
|
|
|
|
|
$return = Title::makeTitle( NS_SPECIAL, $returnto );
|
|
|
|
|
|
2008-09-19 00:11:41 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2008-09-04 15:17:51 +00:00
|
|
|
$errors = $rc->doMarkPatrolled();
|
2008-09-19 00:11:41 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( in_array(array('rcpatroldisabled'), $errors) ) {
|
2008-03-24 15:04:55 +00:00
|
|
|
$wgOut->showErrorPage( 'rcpatroldisabled', 'rcpatroldisabledtext' );
|
2004-08-09 23:30:02 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2008-09-04 15:17:51 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( in_array(array('hookaborted'), $errors) ) {
|
2008-09-04 15:17:51 +00:00
|
|
|
// The hook itself has handled any output
|
2007-09-27 18:20:06 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2008-09-04 15:17:51 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( in_array(array('markedaspatrollederror-noautopatrol'), $errors) ) {
|
2008-09-04 15:17:51 +00:00
|
|
|
$wgOut->setPageTitle( wfMsg( 'markedaspatrollederror' ) );
|
|
|
|
|
$wgOut->addWikiMsg( 'markedaspatrollederror-noautopatrol' );
|
|
|
|
|
$wgOut->returnToMain( false, $return );
|
2006-12-22 19:43:20 +00:00
|
|
|
return;
|
2004-08-09 05:38:11 +00:00
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !empty($errors) ) {
|
2008-09-04 15:17:51 +00:00
|
|
|
$wgOut->showPermissionsErrorPage( $errors );
|
|
|
|
|
return;
|
2008-02-28 21:41:06 +00:00
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-12-22 19:43:20 +00:00
|
|
|
# Inform the user
|
|
|
|
|
$wgOut->setPageTitle( wfMsg( 'markedaspatrolled' ) );
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->addWikiMsg( 'markedaspatrolledtext' );
|
2006-12-22 19:43:20 +00:00
|
|
|
$wgOut->returnToMain( false, $return );
|
2004-08-09 05:38:11 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2006-03-11 07:55:42 +00:00
|
|
|
* User-interface handler for the "watch" action
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
public function watch() {
|
2004-09-24 13:14:52 +00:00
|
|
|
global $wgUser, $wgOut;
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $wgUser->isAnon() ) {
|
2006-06-07 06:40:24 +00:00
|
|
|
$wgOut->showErrorPage( 'watchnologin', 'watchnologintext' );
|
2003-04-14 23:10:40 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
if( wfReadOnly() ) {
|
2003-04-14 23:10:40 +00:00
|
|
|
$wgOut->readOnlyPage();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2006-03-11 07:55:42 +00:00
|
|
|
if( $this->doWatch() ) {
|
2004-11-30 05:45:56 +00:00
|
|
|
$wgOut->setPagetitle( wfMsg( 'addedwatch' ) );
|
2008-07-23 19:05:43 +00:00
|
|
|
$wgOut->setRobotPolicy( 'noindex,nofollow' );
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->addWikiMsg( 'addedwatchtext', $this->mTitle->getPrefixedText() );
|
2004-11-30 05:45:56 +00:00
|
|
|
}
|
2004-08-06 05:51:09 +00:00
|
|
|
$wgOut->returnToMain( true, $this->mTitle->getPrefixedText() );
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2006-03-11 07:55:42 +00:00
|
|
|
* Add this page to $wgUser's watchlist
|
|
|
|
|
* @return bool true on successful watch operation
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function doWatch() {
|
2006-03-11 07:55:42 +00:00
|
|
|
global $wgUser;
|
|
|
|
|
if( $wgUser->isAnon() ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
if( wfRunHooks('WatchArticle', array(&$wgUser, &$this)) ) {
|
2006-03-11 07:55:42 +00:00
|
|
|
$wgUser->addWatch( $this->mTitle );
|
|
|
|
|
return wfRunHooks('WatchArticleComplete', array(&$wgUser, &$this));
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* User interface handler for the "unwatch" action.
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function unwatch() {
|
2004-11-30 05:45:56 +00:00
|
|
|
global $wgUser, $wgOut;
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $wgUser->isAnon() ) {
|
2006-06-07 06:40:24 +00:00
|
|
|
$wgOut->showErrorPage( 'watchnologin', 'watchnologintext' );
|
2004-11-30 05:45:56 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
if( wfReadOnly() ) {
|
2004-11-30 05:45:56 +00:00
|
|
|
$wgOut->readOnlyPage();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2006-03-11 07:55:42 +00:00
|
|
|
if( $this->doUnwatch() ) {
|
2004-11-30 05:45:56 +00:00
|
|
|
$wgOut->setPagetitle( wfMsg( 'removedwatch' ) );
|
2008-07-23 19:05:43 +00:00
|
|
|
$wgOut->setRobotPolicy( 'noindex,nofollow' );
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->addWikiMsg( 'removedwatchtext', $this->mTitle->getPrefixedText() );
|
2004-11-30 05:45:56 +00:00
|
|
|
}
|
|
|
|
|
$wgOut->returnToMain( true, $this->mTitle->getPrefixedText() );
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-03-11 07:55:42 +00:00
|
|
|
/**
|
|
|
|
|
* Stop watching a page
|
|
|
|
|
* @return bool true on successful unwatch
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function doUnwatch() {
|
2006-03-11 07:55:42 +00:00
|
|
|
global $wgUser;
|
|
|
|
|
if( $wgUser->isAnon() ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
if( wfRunHooks('UnwatchArticle', array(&$wgUser, &$this)) ) {
|
2006-03-11 07:55:42 +00:00
|
|
|
$wgUser->removeWatch( $this->mTitle );
|
|
|
|
|
return wfRunHooks('UnwatchArticleComplete', array(&$wgUser, &$this));
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2005-12-22 05:41:06 +00:00
|
|
|
* action=protect handler
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function protect() {
|
2005-12-22 05:41:06 +00:00
|
|
|
$form = new ProtectionForm( $this );
|
2007-01-22 20:59:00 +00:00
|
|
|
$form->execute();
|
2005-12-22 05:41:06 +00:00
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2005-12-22 05:41:06 +00:00
|
|
|
/**
|
|
|
|
|
* action=unprotect handler (alias)
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function unprotect() {
|
2005-12-22 05:41:06 +00:00
|
|
|
$this->protect();
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2005-12-22 05:41:06 +00:00
|
|
|
/**
|
|
|
|
|
* Update the article's restriction field, and leave a log entry.
|
|
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $limit Array: set of restriction keys
|
|
|
|
|
* @param $reason String
|
2008-12-10 22:39:41 +00:00
|
|
|
* @param &$cascade Integer. Set to false if cascading protection isn't allowed.
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $expiry Array: per restriction type expiration
|
2005-12-22 05:41:06 +00:00
|
|
|
* @return bool true on success
|
|
|
|
|
*/
|
2008-12-10 22:39:41 +00:00
|
|
|
public function updateRestrictions( $limit = array(), $reason = '', &$cascade = 0, $expiry = array() ) {
|
2007-10-01 19:50:25 +00:00
|
|
|
global $wgUser, $wgRestrictionTypes, $wgContLang;
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2003-09-01 08:30:14 +00:00
|
|
|
$id = $this->mTitle->getArticleID();
|
2008-12-09 22:12:29 +00:00
|
|
|
if( $id <= 0 || wfReadOnly() || !$this->mTitle->userCan('protect') ) {
|
2005-12-22 05:41:06 +00:00
|
|
|
return false;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2004-04-21 16:17:49 +00:00
|
|
|
|
2008-09-10 19:44:56 +00:00
|
|
|
if( !$cascade ) {
|
2007-01-11 01:17:19 +00:00
|
|
|
$cascade = false;
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-22 08:26:41 +00:00
|
|
|
// Take this opportunity to purge out expired restrictions
|
|
|
|
|
Title::purgeExpiredRestrictions();
|
|
|
|
|
|
2006-04-08 20:50:08 +00:00
|
|
|
# FIXME: Same limitations as described in ProtectionForm.php (line 37);
|
|
|
|
|
# we expect a single selection, but the schema allows otherwise.
|
|
|
|
|
$current = array();
|
2008-09-13 05:33:24 +00:00
|
|
|
$updated = Article::flattenRestrictions( $limit );
|
|
|
|
|
$changed = false;
|
|
|
|
|
foreach( $wgRestrictionTypes as $action ) {
|
2008-12-10 22:39:41 +00:00
|
|
|
if( isset( $expiry[$action] ) ) {
|
2008-12-12 04:55:11 +00:00
|
|
|
# Get current restrictions on $action
|
|
|
|
|
$aLimits = $this->mTitle->getRestrictions( $action );
|
|
|
|
|
$current[$action] = implode( '', $aLimits );
|
|
|
|
|
# Are any actual restrictions being dealt with here?
|
|
|
|
|
$aRChanged = count($aLimits) || !empty($limit[$action]);
|
|
|
|
|
# If something changed, we need to log it. Checking $aRChanged
|
|
|
|
|
# assures that "unprotecting" a page that is not protected does
|
|
|
|
|
# not log just because the expiry was "changed".
|
|
|
|
|
if( $aRChanged && $this->mTitle->mRestrictionsExpiry[$action] != $expiry[$action] ) {
|
|
|
|
|
$changed = true;
|
|
|
|
|
}
|
2008-12-10 22:39:41 +00:00
|
|
|
}
|
2008-09-13 05:33:24 +00:00
|
|
|
}
|
2004-11-28 00:20:37 +00:00
|
|
|
|
2006-04-08 20:50:08 +00:00
|
|
|
$current = Article::flattenRestrictions( $current );
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2008-12-12 04:55:11 +00:00
|
|
|
$changed = ($changed || $current != $updated );
|
2008-04-12 00:30:01 +00:00
|
|
|
$changed = $changed || ($updated && $this->mTitle->areRestrictionsCascading() != $cascade);
|
2006-04-08 20:50:08 +00:00
|
|
|
$protect = ( $updated != '' );
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-04-08 20:50:08 +00:00
|
|
|
# If nothing's changed, do nothing
|
|
|
|
|
if( $changed ) {
|
|
|
|
|
if( wfRunHooks( 'ArticleProtect', array( &$this, &$wgUser, $limit, $reason ) ) ) {
|
2006-04-08 21:13:11 +00:00
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2008-09-10 21:03:57 +00:00
|
|
|
|
2006-04-08 21:13:11 +00:00
|
|
|
# Prepare a null revision to be added to the history
|
2007-06-13 11:08:57 +00:00
|
|
|
$modified = $current != '' && $protect;
|
2008-09-10 21:03:57 +00:00
|
|
|
if( $protect ) {
|
2007-06-13 11:08:57 +00:00
|
|
|
$comment_type = $modified ? 'modifiedarticleprotection' : 'protectedarticle';
|
|
|
|
|
} else {
|
|
|
|
|
$comment_type = 'unprotectedarticle';
|
|
|
|
|
}
|
|
|
|
|
$comment = $wgContLang->ucfirst( wfMsgForContent( $comment_type, $this->mTitle->getPrefixedText() ) );
|
2007-01-23 10:51:33 +00:00
|
|
|
|
2008-06-21 03:17:35 +00:00
|
|
|
# Only restrictions with the 'protect' right can cascade...
|
2008-06-19 20:40:41 +00:00
|
|
|
# Otherwise, people who cannot normally protect can "protect" pages via transclusion
|
2008-12-11 21:37:48 +00:00
|
|
|
$editrestriction = isset( $limit['edit'] ) ? array( $limit['edit'] ) : $this->mTitle->getRestrictions( 'edit' );
|
|
|
|
|
# The schema allows multiple restrictions
|
|
|
|
|
if(!in_array('protect', $editrestriction) && !in_array('sysop', $editrestriction))
|
|
|
|
|
$cascade = false;
|
2008-09-10 21:03:57 +00:00
|
|
|
$cascade_description = '';
|
|
|
|
|
if( $cascade ) {
|
2008-09-11 10:57:56 +00:00
|
|
|
$cascade_description = ' ['.wfMsgForContent('protect-summary-cascade').']';
|
2008-09-10 21:03:57 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2006-04-08 21:13:11 +00:00
|
|
|
if( $reason )
|
|
|
|
|
$comment .= ": $reason";
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-09-10 21:03:57 +00:00
|
|
|
$editComment = $comment;
|
2008-09-13 05:33:24 +00:00
|
|
|
$encodedExpiry = array();
|
|
|
|
|
$protect_description = '';
|
|
|
|
|
foreach( $limit as $action => $restrictions ) {
|
|
|
|
|
$encodedExpiry[$action] = Block::encodeExpiry($expiry[$action], $dbw );
|
2008-09-19 13:49:10 +00:00
|
|
|
if( $restrictions != '' ) {
|
2008-09-13 05:33:24 +00:00
|
|
|
$protect_description .= "[$action=$restrictions] (";
|
|
|
|
|
if( $encodedExpiry[$action] != 'infinity' ) {
|
2008-09-19 13:46:26 +00:00
|
|
|
$protect_description .= wfMsgForContent( 'protect-expiring',
|
2009-01-04 14:37:35 +00:00
|
|
|
$wgContLang->timeanddate( $expiry[$action], false, false ) ,
|
|
|
|
|
$wgContLang->date( $expiry[$action], false, false ) ,
|
|
|
|
|
$wgContLang->time( $expiry[$action], false, false ) );
|
2008-09-13 05:33:24 +00:00
|
|
|
} else {
|
|
|
|
|
$protect_description .= wfMsgForContent( 'protect-expiry-indefinite' );
|
|
|
|
|
}
|
2008-09-19 13:49:10 +00:00
|
|
|
$protect_description .= ') ';
|
2008-09-13 05:33:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-09-19 13:49:10 +00:00
|
|
|
$protect_description = trim($protect_description);
|
2008-09-13 05:33:24 +00:00
|
|
|
|
|
|
|
|
if( $protect_description && $protect )
|
2008-09-13 15:04:41 +00:00
|
|
|
$editComment .= " ($protect_description)";
|
2008-09-10 21:03:57 +00:00
|
|
|
if( $cascade )
|
|
|
|
|
$editComment .= "$cascade_description";
|
2007-01-10 23:32:38 +00:00
|
|
|
# Update restrictions table
|
|
|
|
|
foreach( $limit as $action => $restrictions ) {
|
2008-11-28 14:29:25 +00:00
|
|
|
if($restrictions != '' ) {
|
2007-03-08 01:46:12 +00:00
|
|
|
$dbw->replace( 'page_restrictions', array(array('pr_page', 'pr_type')),
|
2008-09-13 15:04:41 +00:00
|
|
|
array( 'pr_page' => $id,
|
|
|
|
|
'pr_type' => $action,
|
|
|
|
|
'pr_level' => $restrictions,
|
|
|
|
|
'pr_cascade' => ($cascade && $action == 'edit') ? 1 : 0,
|
|
|
|
|
'pr_expiry' => $encodedExpiry[$action] ), __METHOD__ );
|
2007-01-10 23:32:38 +00:00
|
|
|
} else {
|
|
|
|
|
$dbw->delete( 'page_restrictions', array( 'pr_page' => $id,
|
|
|
|
|
'pr_type' => $action ), __METHOD__ );
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-01-21 15:04:49 +00:00
|
|
|
|
|
|
|
|
# Insert a null revision
|
2008-09-10 21:03:57 +00:00
|
|
|
$nullRevision = Revision::newNullRevision( $dbw, $id, $editComment, true );
|
2008-01-21 15:04:49 +00:00
|
|
|
$nullRevId = $nullRevision->insertOn( $dbw );
|
2007-01-12 01:44:33 +00:00
|
|
|
|
2008-07-27 19:24:35 +00:00
|
|
|
$latest = $this->getLatest();
|
2007-01-14 12:03:56 +00:00
|
|
|
# Update page record
|
|
|
|
|
$dbw->update( 'page',
|
|
|
|
|
array( /* SET */
|
|
|
|
|
'page_touched' => $dbw->timestamp(),
|
|
|
|
|
'page_restrictions' => '',
|
|
|
|
|
'page_latest' => $nullRevId
|
|
|
|
|
), array( /* WHERE */
|
|
|
|
|
'page_id' => $id
|
2008-06-21 03:17:35 +00:00
|
|
|
), 'Article::protect'
|
2007-01-14 12:03:56 +00:00
|
|
|
);
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2008-11-27 18:32:29 +00:00
|
|
|
wfRunHooks( 'NewRevisionFromEditComplete', array($this, $nullRevision, $latest, $wgUser) );
|
2006-04-08 20:50:08 +00:00
|
|
|
wfRunHooks( 'ArticleProtectComplete', array( &$this, &$wgUser, $limit, $reason ) );
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-04-08 20:50:08 +00:00
|
|
|
# Update the protection log
|
|
|
|
|
$log = new LogPage( 'protect' );
|
|
|
|
|
if( $protect ) {
|
2008-09-13 05:33:24 +00:00
|
|
|
$params = array($protect_description,$cascade ? 'cascade' : '');
|
2008-09-10 19:44:56 +00:00
|
|
|
$log->addEntry( $modified ? 'modify' : 'protect', $this->mTitle, trim( $reason), $params );
|
2006-04-08 20:50:08 +00:00
|
|
|
} else {
|
|
|
|
|
$log->addEntry( 'unprotect', $this->mTitle, $reason );
|
|
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-04-08 20:50:08 +00:00
|
|
|
} # End hook
|
|
|
|
|
} # End "changed" check
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2005-12-22 05:41:06 +00:00
|
|
|
return true;
|
2004-04-21 16:17:49 +00:00
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2005-12-22 05:41:06 +00:00
|
|
|
* Take an array of page restrictions and flatten it to a string
|
|
|
|
|
* suitable for insertion into the page_restrictions field.
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $limit Array
|
|
|
|
|
* @return String
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
protected static function flattenRestrictions( $limit ) {
|
2005-12-22 05:41:06 +00:00
|
|
|
if( !is_array( $limit ) ) {
|
2006-06-07 06:40:24 +00:00
|
|
|
throw new MWException( 'Article::flattenRestrictions given non-array restriction set' );
|
2005-12-22 05:41:06 +00:00
|
|
|
}
|
|
|
|
|
$bits = array();
|
2006-04-08 20:50:08 +00:00
|
|
|
ksort( $limit );
|
2005-12-22 05:41:06 +00:00
|
|
|
foreach( $limit as $action => $restrictions ) {
|
|
|
|
|
if( $restrictions != '' ) {
|
|
|
|
|
$bits[] = "$action=$restrictions";
|
|
|
|
|
}
|
2005-12-15 21:25:52 +00:00
|
|
|
}
|
2005-12-22 05:41:06 +00:00
|
|
|
return implode( ':', $bits );
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-11-07 19:06:15 +00:00
|
|
|
/**
|
|
|
|
|
* Auto-generates a deletion reason
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param &$hasHistory Boolean: whether the page has a history
|
2007-11-07 19:06:15 +00:00
|
|
|
*/
|
2008-09-21 02:53:16 +00:00
|
|
|
public function generateReason( &$hasHistory ) {
|
2007-11-07 19:06:15 +00:00
|
|
|
global $wgContLang;
|
2008-09-21 02:53:16 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2007-11-07 19:06:15 +00:00
|
|
|
// Get the last revision
|
2008-09-21 02:53:16 +00:00
|
|
|
$rev = Revision::newFromTitle( $this->mTitle );
|
|
|
|
|
if( is_null( $rev ) )
|
2007-11-07 19:06:15 +00:00
|
|
|
return false;
|
2008-09-21 02:53:16 +00:00
|
|
|
|
2007-11-07 19:06:15 +00:00
|
|
|
// Get the article's contents
|
|
|
|
|
$contents = $rev->getText();
|
|
|
|
|
$blank = false;
|
|
|
|
|
// If the page is blank, use the text from the previous revision,
|
|
|
|
|
// which can only be blank if there's a move/import/protect dummy revision involved
|
2008-09-21 02:53:16 +00:00
|
|
|
if( $contents == '' ) {
|
2007-11-07 19:06:15 +00:00
|
|
|
$prev = $rev->getPrevious();
|
2008-09-21 02:53:16 +00:00
|
|
|
if( $prev ) {
|
2007-11-07 19:06:15 +00:00
|
|
|
$contents = $prev->getText();
|
|
|
|
|
$blank = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find out if there was only one contributor
|
|
|
|
|
// Only scan the last 20 revisions
|
|
|
|
|
$limit = 20;
|
2008-09-21 02:53:16 +00:00
|
|
|
$res = $dbw->select( 'revision', 'rev_user_text',
|
|
|
|
|
array( 'rev_page' => $this->getID() ), __METHOD__,
|
|
|
|
|
array( 'LIMIT' => $limit )
|
|
|
|
|
);
|
|
|
|
|
if( $res === false )
|
2007-11-07 19:06:15 +00:00
|
|
|
// This page has no revisions, which is very weird
|
|
|
|
|
return false;
|
2008-09-21 02:53:16 +00:00
|
|
|
if( $res->numRows() > 1 )
|
2007-11-07 19:06:15 +00:00
|
|
|
$hasHistory = true;
|
|
|
|
|
else
|
|
|
|
|
$hasHistory = false;
|
2008-09-21 02:53:16 +00:00
|
|
|
$row = $dbw->fetchObject( $res );
|
2007-11-07 19:06:15 +00:00
|
|
|
$onlyAuthor = $row->rev_user_text;
|
|
|
|
|
// Try to find a second contributor
|
2008-07-27 18:59:46 +00:00
|
|
|
foreach( $res as $row ) {
|
2008-09-21 02:53:16 +00:00
|
|
|
if( $row->rev_user_text != $onlyAuthor ) {
|
2007-11-07 19:06:15 +00:00
|
|
|
$onlyAuthor = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-01-09 21:40:40 +00:00
|
|
|
}
|
2008-09-21 02:53:16 +00:00
|
|
|
$dbw->freeResult( $res );
|
2007-11-07 19:06:15 +00:00
|
|
|
|
|
|
|
|
// Generate the summary with a '$1' placeholder
|
2008-09-21 02:53:16 +00:00
|
|
|
if( $blank ) {
|
2007-11-07 19:06:15 +00:00
|
|
|
// The current revision is blank and the one before is also
|
|
|
|
|
// blank. It's just not our lucky day
|
2008-09-21 02:53:16 +00:00
|
|
|
$reason = wfMsgForContent( 'exbeforeblank', '$1' );
|
2008-01-09 21:40:40 +00:00
|
|
|
} else {
|
2008-09-21 02:53:16 +00:00
|
|
|
if( $onlyAuthor )
|
|
|
|
|
$reason = wfMsgForContent( 'excontentauthor', '$1', $onlyAuthor );
|
2007-11-07 19:06:15 +00:00
|
|
|
else
|
2008-09-21 02:53:16 +00:00
|
|
|
$reason = wfMsgForContent( 'excontent', '$1' );
|
2007-11-07 19:06:15 +00:00
|
|
|
}
|
2008-12-01 20:12:01 +00:00
|
|
|
|
|
|
|
|
if( $reason == '-' ) {
|
|
|
|
|
// Allow these UI messages to be blanked out cleanly
|
|
|
|
|
return '';
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-11-07 19:06:15 +00:00
|
|
|
// Replace newlines with spaces to prevent uglyness
|
2008-09-21 02:53:16 +00:00
|
|
|
$contents = preg_replace( "/[\n\r]/", ' ', $contents );
|
2007-11-07 19:06:15 +00:00
|
|
|
// Calculate the maximum amount of chars to get
|
|
|
|
|
// Max content length = max comment length - length of the comment (excl. $1) - '...'
|
2008-09-21 02:53:16 +00:00
|
|
|
$maxLength = 255 - (strlen( $reason ) - 2) - 3;
|
|
|
|
|
$contents = $wgContLang->truncate( $contents, $maxLength, '...' );
|
2007-11-07 19:06:15 +00:00
|
|
|
// Remove possible unfinished links
|
|
|
|
|
$contents = preg_replace( '/\[\[([^\]]*)\]?$/', '$1', $contents );
|
|
|
|
|
// Now replace the '$1' placeholder
|
|
|
|
|
$reason = str_replace( '$1', $contents, $reason );
|
|
|
|
|
return $reason;
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/*
|
|
|
|
|
* UI entry point for page deletion
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function delete() {
|
2005-12-04 18:27:59 +00:00
|
|
|
global $wgUser, $wgOut, $wgRequest;
|
2007-12-03 00:14:36 +00:00
|
|
|
|
2005-03-11 04:38:01 +00:00
|
|
|
$confirm = $wgRequest->wasPosted() &&
|
2007-12-03 00:14:36 +00:00
|
|
|
$wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-12-03 00:14:36 +00:00
|
|
|
$this->DeleteReasonList = $wgRequest->getText( 'wpDeleteReasonList', 'other' );
|
2007-11-25 17:02:28 +00:00
|
|
|
$this->DeleteReason = $wgRequest->getText( 'wpReason' );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-11-25 17:02:28 +00:00
|
|
|
$reason = $this->DeleteReasonList;
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-12-22 18:30:13 +00:00
|
|
|
if( $reason != 'other' && $this->DeleteReason != '' ) {
|
2007-11-25 17:02:28 +00:00
|
|
|
// Entry from drop down menu + additional comment
|
2009-01-07 22:49:54 +00:00
|
|
|
$reason .= wfMsgForContent( 'colon-separator' ) . $this->DeleteReason;
|
2008-11-28 14:29:25 +00:00
|
|
|
} elseif( $reason == 'other' ) {
|
2007-11-25 17:02:28 +00:00
|
|
|
$reason = $this->DeleteReason;
|
|
|
|
|
}
|
2008-03-09 02:18:50 +00:00
|
|
|
# Flag to hide all contents of the archived revisions
|
2008-12-22 18:30:13 +00:00
|
|
|
$suppress = $wgRequest->getVal( 'wpSuppress' ) && $wgUser->isAllowed( 'suppressrevision' );
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2003-11-09 11:45:12 +00:00
|
|
|
# This code desperately needs to be totally rewritten
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2008-01-15 01:55:48 +00:00
|
|
|
# Read-only check...
|
2008-11-28 14:29:25 +00:00
|
|
|
if( wfReadOnly() ) {
|
2008-01-15 01:55:48 +00:00
|
|
|
$wgOut->readOnlyPage();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2004-03-29 14:48:07 +00:00
|
|
|
# Check permissions
|
2007-09-09 08:11:58 +00:00
|
|
|
$permission_errors = $this->mTitle->getUserPermissionsErrors( 'delete', $wgUser );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2008-12-22 18:30:13 +00:00
|
|
|
if( count( $permission_errors ) > 0 ) {
|
2007-09-09 08:11:58 +00:00
|
|
|
$wgOut->showPermissionsErrorPage( $permission_errors );
|
2003-04-14 23:10:40 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-29 16:32:49 +00:00
|
|
|
$wgOut->setPagetitle( wfMsg( 'delete-confirm', $this->mTitle->getPrefixedText() ) );
|
|
|
|
|
|
2006-01-08 01:25:50 +00:00
|
|
|
# Better double-check that it hasn't been deleted yet!
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2006-01-08 01:25:50 +00:00
|
|
|
$conds = $this->mTitle->pageCond();
|
2006-06-20 09:50:57 +00:00
|
|
|
$latest = $dbw->selectField( 'page', 'page_latest', $conds, __METHOD__ );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $latest === false ) {
|
2008-12-22 18:30:13 +00:00
|
|
|
$wgOut->showFatalError( wfMsgExt( 'cannotdelete', array( 'parse' ) ) );
|
2009-01-02 20:22:28 +00:00
|
|
|
$wgOut->addHTML( Xml::element( 'h2', null, LogPage::logName( 'delete' ) ) );
|
|
|
|
|
LogEventsList::showLogExtract( $wgOut, 'delete', $this->mTitle->getPrefixedText() );
|
2003-09-01 09:59:53 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2003-05-23 04:26:51 +00:00
|
|
|
|
2008-01-17 00:29:05 +00:00
|
|
|
# Hack for big sites
|
|
|
|
|
$bigHistory = $this->isBigDeletion();
|
|
|
|
|
if( $bigHistory && !$this->mTitle->userCan( 'bigdelete' ) ) {
|
|
|
|
|
global $wgLang, $wgDeleteRevisionsLimit;
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div class='error'>\n$1</div>\n",
|
|
|
|
|
array( 'delete-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) ) );
|
2008-01-17 00:29:05 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-18 09:45:18 +00:00
|
|
|
if( $confirm ) {
|
2008-03-09 02:18:50 +00:00
|
|
|
$this->doDelete( $reason, $suppress );
|
2006-12-16 21:36:01 +00:00
|
|
|
if( $wgRequest->getCheck( 'wpWatch' ) ) {
|
|
|
|
|
$this->doWatch();
|
|
|
|
|
} elseif( $this->mTitle->userIsWatching() ) {
|
|
|
|
|
$this->doUnwatch();
|
|
|
|
|
}
|
2003-11-15 12:38:02 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-07 19:06:15 +00:00
|
|
|
// Generate deletion reason
|
|
|
|
|
$hasHistory = false;
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$reason ) $reason = $this->generateReason($hasHistory);
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2007-11-07 19:06:15 +00:00
|
|
|
// If the page has a history, insert a warning
|
|
|
|
|
if( $hasHistory && !$confirm ) {
|
2008-12-22 18:30:13 +00:00
|
|
|
$skin = $wgUser->getSkin();
|
|
|
|
|
$wgOut->addHTML( '<strong>' . wfMsgExt( 'historywarning', array( 'parseinline' ) ) . ' ' . $skin->historyLink() . '</strong>' );
|
2008-01-17 00:29:05 +00:00
|
|
|
if( $bigHistory ) {
|
|
|
|
|
global $wgLang, $wgDeleteRevisionsLimit;
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div class='error'>\n$1</div>\n",
|
|
|
|
|
array( 'delete-warning-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) ) );
|
2008-01-17 00:29:05 +00:00
|
|
|
}
|
2003-09-01 09:59:53 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-07-07 16:56:32 +00:00
|
|
|
return $this->confirmDelete( $reason );
|
2003-09-01 09:59:53 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-01-16 23:08:19 +00:00
|
|
|
/**
|
|
|
|
|
* @return bool whether or not the page surpasses $wgDeleteRevisionsLimit revisions
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function isBigDeletion() {
|
2008-01-16 23:08:19 +00:00
|
|
|
global $wgDeleteRevisionsLimit;
|
|
|
|
|
if( $wgDeleteRevisionsLimit ) {
|
|
|
|
|
$revCount = $this->estimateRevisionCount();
|
|
|
|
|
return $revCount > $wgDeleteRevisionsLimit;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-01-16 23:08:19 +00:00
|
|
|
/**
|
|
|
|
|
* @return int approximate revision count
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function estimateRevisionCount() {
|
2008-09-21 08:44:20 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2008-01-16 23:08:19 +00:00
|
|
|
// For an exact count...
|
|
|
|
|
//return $dbr->selectField( 'revision', 'COUNT(*)',
|
|
|
|
|
// array( 'rev_page' => $this->getId() ), __METHOD__ );
|
|
|
|
|
return $dbr->estimateRowCount( 'revision', '*',
|
|
|
|
|
array( 'rev_page' => $this->getId() ), __METHOD__ );
|
|
|
|
|
}
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2006-01-08 01:25:50 +00:00
|
|
|
/**
|
2006-03-11 17:13:49 +00:00
|
|
|
* Get the last N authors
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $num Integer: number of revisions to get
|
|
|
|
|
* @param $revLatest String: the latest rev_id, selected from the master (optional)
|
2006-01-08 01:25:50 +00:00
|
|
|
* @return array Array of authors, duplicates not removed
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getLastNAuthors( $num, $revLatest = 0 ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2006-01-08 01:25:50 +00:00
|
|
|
// First try the slave
|
|
|
|
|
// If that doesn't have the latest revision, try the master
|
|
|
|
|
$continue = 2;
|
2007-01-22 23:50:42 +00:00
|
|
|
$db = wfGetDB( DB_SLAVE );
|
2006-01-08 01:25:50 +00:00
|
|
|
do {
|
|
|
|
|
$res = $db->select( array( 'page', 'revision' ),
|
|
|
|
|
array( 'rev_id', 'rev_user_text' ),
|
|
|
|
|
array(
|
|
|
|
|
'page_namespace' => $this->mTitle->getNamespace(),
|
|
|
|
|
'page_title' => $this->mTitle->getDBkey(),
|
|
|
|
|
'rev_page = page_id'
|
2006-06-20 09:50:57 +00:00
|
|
|
), __METHOD__, $this->getSelectOptions( array(
|
2006-01-08 01:25:50 +00:00
|
|
|
'ORDER BY' => 'rev_timestamp DESC',
|
|
|
|
|
'LIMIT' => $num
|
|
|
|
|
) )
|
|
|
|
|
);
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$res ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2006-01-08 01:25:50 +00:00
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
$row = $db->fetchObject( $res );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $continue == 2 && $revLatest && $row->rev_id != $revLatest ) {
|
2007-01-22 23:50:42 +00:00
|
|
|
$db = wfGetDB( DB_MASTER );
|
2006-01-08 01:25:50 +00:00
|
|
|
$continue--;
|
|
|
|
|
} else {
|
|
|
|
|
$continue = 0;
|
|
|
|
|
}
|
|
|
|
|
} while ( $continue );
|
|
|
|
|
|
|
|
|
|
$authors = array( $row->rev_user_text );
|
|
|
|
|
while ( $row = $db->fetchObject( $res ) ) {
|
|
|
|
|
$authors[] = $row->rev_user_text;
|
|
|
|
|
}
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2006-01-08 01:25:50 +00:00
|
|
|
return $authors;
|
|
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Output deletion confirmation dialog
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $reason String: prefilled reason
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function confirmDelete( $reason ) {
|
2008-10-06 16:02:30 +00:00
|
|
|
global $wgOut, $wgUser;
|
2003-11-15 12:38:02 +00:00
|
|
|
|
|
|
|
|
wfDebug( "Article::confirmDelete\n" );
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2008-12-22 18:30:13 +00:00
|
|
|
$wgOut->setSubtitle( wfMsgHtml( 'delete-backlink', $wgUser->getSkin()->makeKnownLinkObj( $this->mTitle ) ) );
|
2008-07-23 19:05:43 +00:00
|
|
|
$wgOut->setRobotPolicy( 'noindex,nofollow' );
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->addWikiMsg( 'confirmdeletetext' );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2008-05-25 00:31:28 +00:00
|
|
|
if( $wgUser->isAllowed( 'suppressrevision' ) ) {
|
2008-10-06 16:02:30 +00:00
|
|
|
$suppress = "<tr id=\"wpDeleteSuppressRow\" name=\"wpDeleteSuppressRow\">
|
|
|
|
|
<td></td>
|
|
|
|
|
<td class='mw-input'>" .
|
|
|
|
|
Xml::checkLabel( wfMsg( 'revdelete-suppress' ),
|
|
|
|
|
'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '4' ) ) .
|
|
|
|
|
"</td>
|
|
|
|
|
</tr>";
|
2008-03-09 02:18:50 +00:00
|
|
|
} else {
|
|
|
|
|
$suppress = '';
|
|
|
|
|
}
|
2008-09-25 06:33:58 +00:00
|
|
|
$checkWatch = $wgUser->getBoolOption( 'watchdeletion' ) || $this->mTitle->userIsWatching();
|
2008-03-09 02:18:50 +00:00
|
|
|
|
2008-09-25 06:33:58 +00:00
|
|
|
$form = Xml::openElement( 'form', array( 'method' => 'post',
|
|
|
|
|
'action' => $this->mTitle->getLocalURL( 'action=delete' ), 'id' => 'deleteconfirm' ) ) .
|
2008-03-13 20:36:52 +00:00
|
|
|
Xml::openElement( 'fieldset', array( 'id' => 'mw-delete-table' ) ) .
|
2008-06-12 12:02:28 +00:00
|
|
|
Xml::tags( 'legend', null, wfMsgExt( 'delete-legend', array( 'parsemag', 'escapenoentities' ) ) ) .
|
2008-10-06 16:02:30 +00:00
|
|
|
Xml::openElement( 'table', array( 'id' => 'mw-deleteconfirm-table' ) ) .
|
2008-02-03 09:27:13 +00:00
|
|
|
"<tr id=\"wpDeleteReasonListRow\">
|
2008-10-06 16:02:30 +00:00
|
|
|
<td class='mw-label'>" .
|
2008-01-29 16:32:49 +00:00
|
|
|
Xml::label( wfMsg( 'deletecomment' ), 'wpDeleteReasonList' ) .
|
|
|
|
|
"</td>
|
2008-10-06 16:02:30 +00:00
|
|
|
<td class='mw-input'>" .
|
2008-01-29 16:32:49 +00:00
|
|
|
Xml::listDropDown( 'wpDeleteReasonList',
|
2008-04-14 07:45:50 +00:00
|
|
|
wfMsgForContent( 'deletereason-dropdown' ),
|
2008-01-29 16:32:49 +00:00
|
|
|
wfMsgForContent( 'deletereasonotherlist' ), '', 'wpReasonDropDown', 1 ) .
|
|
|
|
|
"</td>
|
|
|
|
|
</tr>
|
2008-02-03 09:27:13 +00:00
|
|
|
<tr id=\"wpDeleteReasonRow\">
|
2008-10-06 16:02:30 +00:00
|
|
|
<td class='mw-label'>" .
|
2008-01-29 16:32:49 +00:00
|
|
|
Xml::label( wfMsg( 'deleteotherreason' ), 'wpReason' ) .
|
|
|
|
|
"</td>
|
2008-10-06 16:02:30 +00:00
|
|
|
<td class='mw-input'>" .
|
2008-09-25 06:33:58 +00:00
|
|
|
Xml::input( 'wpReason', 60, $reason, array( 'type' => 'text', 'maxlength' => '255',
|
|
|
|
|
'tabindex' => '2', 'id' => 'wpReason' ) ) .
|
2008-01-29 16:32:49 +00:00
|
|
|
"</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td></td>
|
2008-10-06 16:02:30 +00:00
|
|
|
<td class='mw-input'>" .
|
|
|
|
|
Xml::checkLabel( wfMsg( 'watchthis' ),
|
|
|
|
|
'wpWatch', 'wpWatch', $checkWatch, array( 'tabindex' => '3' ) ) .
|
2008-01-29 16:32:49 +00:00
|
|
|
"</td>
|
|
|
|
|
</tr>
|
2008-03-09 02:18:50 +00:00
|
|
|
$suppress
|
2008-01-29 16:32:49 +00:00
|
|
|
<tr>
|
|
|
|
|
<td></td>
|
2008-10-06 16:02:30 +00:00
|
|
|
<td class='mw-submit'>" .
|
|
|
|
|
Xml::submitButton( wfMsg( 'deletepage' ),
|
|
|
|
|
array( 'name' => 'wpConfirmB', 'id' => 'wpConfirmB', 'tabindex' => '5' ) ) .
|
2008-01-29 16:32:49 +00:00
|
|
|
"</td>
|
|
|
|
|
</tr>" .
|
|
|
|
|
Xml::closeElement( 'table' ) .
|
|
|
|
|
Xml::closeElement( 'fieldset' ) .
|
|
|
|
|
Xml::hidden( 'wpEditToken', $wgUser->editToken() ) .
|
|
|
|
|
Xml::closeElement( 'form' );
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $wgUser->isAllowed( 'editinterface' ) ) {
|
2008-03-06 14:59:28 +00:00
|
|
|
$skin = $wgUser->getSkin();
|
2008-03-06 16:52:10 +00:00
|
|
|
$link = $skin->makeLink ( 'MediaWiki:Deletereason-dropdown', wfMsgHtml( 'delete-edit-reasonlist' ) );
|
2008-03-06 14:59:28 +00:00
|
|
|
$form .= '<p class="mw-delete-editreasons">' . $link . '</p>';
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-29 16:32:49 +00:00
|
|
|
$wgOut->addHTML( $form );
|
2008-11-28 14:29:25 +00:00
|
|
|
LogEventsList::showLogExtract( $wgOut, 'delete', $this->mTitle->getPrefixedText() );
|
2007-03-06 00:10:37 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Perform a deletion and output success or failure messages
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function doDelete( $reason, $suppress = false ) {
|
2006-03-07 01:10:39 +00:00
|
|
|
global $wgOut, $wgUser;
|
2008-09-16 17:08:08 +00:00
|
|
|
$id = $this->mTitle->getArticleID( GAID_FOR_UPDATE );
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2008-06-27 06:24:42 +00:00
|
|
|
$error = '';
|
2008-11-28 14:29:25 +00:00
|
|
|
if( wfRunHooks('ArticleDelete', array(&$this, &$wgUser, &$reason, &$error)) ) {
|
|
|
|
|
if( $this->doDeleteArticle( $reason, $suppress, $id ) ) {
|
2008-02-18 07:25:35 +00:00
|
|
|
$deleted = $this->mTitle->getPrefixedText();
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2004-11-28 06:15:22 +00:00
|
|
|
$wgOut->setPagetitle( wfMsg( 'actioncomplete' ) );
|
2008-07-23 19:05:43 +00:00
|
|
|
$wgOut->setRobotPolicy( 'noindex,nofollow' );
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2008-02-18 07:25:35 +00:00
|
|
|
$loglink = '[[Special:Log/delete|' . wfMsgNoTrans( 'deletionlog' ) . ']]';
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->addWikiMsg( 'deletedtext', $deleted, $loglink );
|
2004-11-28 06:15:22 +00:00
|
|
|
$wgOut->returnToMain( false );
|
2008-04-28 12:34:27 +00:00
|
|
|
wfRunHooks('ArticleDeleteComplete', array(&$this, &$wgUser, $reason, $id));
|
2004-11-28 06:15:22 +00:00
|
|
|
} else {
|
2009-01-02 20:22:28 +00:00
|
|
|
if( $error == '' ) {
|
2008-12-22 18:30:13 +00:00
|
|
|
$wgOut->showFatalError( wfMsgExt( 'cannotdelete', array( 'parse' ) ) );
|
2009-01-02 20:22:28 +00:00
|
|
|
$wgOut->addHTML( Xml::element( 'h2', null, LogPage::logName( 'delete' ) ) );
|
|
|
|
|
LogEventsList::showLogExtract( $wgOut, 'delete', $this->mTitle->getPrefixedText() );
|
|
|
|
|
} else {
|
2008-06-27 06:24:42 +00:00
|
|
|
$wgOut->showFatalError( $error );
|
2009-01-02 20:22:28 +00:00
|
|
|
}
|
2004-11-28 06:15:22 +00:00
|
|
|
}
|
2004-03-20 15:03:26 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Back-end article deletion
|
|
|
|
|
* Deletes the article with database consistency, writes logs, purges caches
|
|
|
|
|
* Returns success
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function doDeleteArticle( $reason, $suppress = false, $id = 0 ) {
|
2006-03-07 01:10:39 +00:00
|
|
|
global $wgUseSquid, $wgDeferredUpdateList;
|
2006-11-23 08:25:56 +00:00
|
|
|
global $wgUseTrackbacks;
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
wfDebug( __METHOD__."\n" );
|
2004-08-09 05:38:11 +00:00
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2004-03-20 15:03:26 +00:00
|
|
|
$ns = $this->mTitle->getNamespace();
|
2004-07-10 03:09:26 +00:00
|
|
|
$t = $this->mTitle->getDBkey();
|
2008-09-16 17:08:08 +00:00
|
|
|
$id = $id ? $id : $this->mTitle->getArticleID( GAID_FOR_UPDATE );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $t == '' || $id == 0 ) {
|
2004-03-20 15:03:26 +00:00
|
|
|
return false;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-10 13:41:22 +00:00
|
|
|
$u = new SiteStatsUpdate( 0, 1, -(int)$this->isCountable( $this->getRawText() ), -1 );
|
2003-04-14 23:10:40 +00:00
|
|
|
array_push( $wgDeferredUpdateList, $u );
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2008-03-09 02:18:50 +00:00
|
|
|
// Bitfields to further suppress the content
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $suppress ) {
|
2008-03-09 02:18:50 +00:00
|
|
|
$bitfield = 0;
|
|
|
|
|
// This should be 15...
|
|
|
|
|
$bitfield |= Revision::DELETED_TEXT;
|
|
|
|
|
$bitfield |= Revision::DELETED_COMMENT;
|
|
|
|
|
$bitfield |= Revision::DELETED_USER;
|
|
|
|
|
$bitfield |= Revision::DELETED_RESTRICTED;
|
|
|
|
|
} else {
|
|
|
|
|
$bitfield = 'rev_deleted';
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-04-15 23:34:45 +00:00
|
|
|
$dbw->begin();
|
2005-05-01 08:07:25 +00:00
|
|
|
// For now, shunt the revision data into the archive table.
|
|
|
|
|
// Text is *not* removed from the text table; bulk storage
|
|
|
|
|
// is left intact to avoid breaking block-compression or
|
|
|
|
|
// immutable storage schemes.
|
|
|
|
|
//
|
|
|
|
|
// For backwards compatibility, note that some older archive
|
|
|
|
|
// table entries will have ar_text and ar_flags fields still.
|
|
|
|
|
//
|
|
|
|
|
// In the future, we may keep revisions and mark them with
|
|
|
|
|
// the rev_deleted field, which is reserved for this purpose.
|
|
|
|
|
$dbw->insertSelect( 'archive', array( 'page', 'revision' ),
|
2004-07-10 03:09:26 +00:00
|
|
|
array(
|
2005-03-12 08:06:46 +00:00
|
|
|
'ar_namespace' => 'page_namespace',
|
|
|
|
|
'ar_title' => 'page_title',
|
|
|
|
|
'ar_comment' => 'rev_comment',
|
|
|
|
|
'ar_user' => 'rev_user',
|
|
|
|
|
'ar_user_text' => 'rev_user_text',
|
|
|
|
|
'ar_timestamp' => 'rev_timestamp',
|
2005-01-30 19:46:48 +00:00
|
|
|
'ar_minor_edit' => 'rev_minor_edit',
|
2005-03-12 08:06:46 +00:00
|
|
|
'ar_rev_id' => 'rev_id',
|
2005-05-01 08:07:25 +00:00
|
|
|
'ar_text_id' => 'rev_text_id',
|
2006-12-21 21:40:43 +00:00
|
|
|
'ar_text' => '\'\'', // Be explicit to appease
|
|
|
|
|
'ar_flags' => '\'\'', // MySQL's "strict mode"...
|
2008-03-09 21:08:42 +00:00
|
|
|
'ar_len' => 'rev_len',
|
2007-08-11 14:43:47 +00:00
|
|
|
'ar_page_id' => 'page_id',
|
2008-03-09 02:18:50 +00:00
|
|
|
'ar_deleted' => $bitfield
|
2004-07-10 03:09:26 +00:00
|
|
|
), array(
|
2005-05-01 08:07:25 +00:00
|
|
|
'page_id' => $id,
|
|
|
|
|
'page_id = rev_page'
|
2006-06-20 09:50:57 +00:00
|
|
|
), __METHOD__
|
2004-07-10 03:09:26 +00:00
|
|
|
);
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2007-01-10 23:32:38 +00:00
|
|
|
# Delete restrictions for it
|
2008-12-31 18:56:16 +00:00
|
|
|
$dbw->delete( 'page_restrictions', array ( 'pr_page' => $id ), __METHOD__ );
|
2007-01-10 23:32:38 +00:00
|
|
|
|
2003-04-14 23:10:40 +00:00
|
|
|
# Now that it's safely backed up, delete it
|
2006-06-20 09:50:57 +00:00
|
|
|
$dbw->delete( 'page', array( 'page_id' => $id ), __METHOD__);
|
2008-04-27 23:45:31 +00:00
|
|
|
$ok = ( $dbw->affectedRows() > 0 ); // getArticleId() uses slave, could be laggy
|
2008-04-15 23:34:45 +00:00
|
|
|
if( !$ok ) {
|
|
|
|
|
$dbw->rollback();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2006-07-17 00:54:40 +00:00
|
|
|
# If using cascading deletes, we can skip some explicit deletes
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$dbw->cascadingDeletes() ) {
|
2006-07-17 00:54:40 +00:00
|
|
|
$dbw->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ );
|
2005-07-23 06:12:48 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if($wgUseTrackbacks)
|
2006-07-17 00:54:40 +00:00
|
|
|
$dbw->delete( 'trackbacks', array( 'tb_page' => $id ), __METHOD__ );
|
|
|
|
|
|
|
|
|
|
# Delete outgoing links
|
|
|
|
|
$dbw->delete( 'pagelinks', array( 'pl_from' => $id ) );
|
|
|
|
|
$dbw->delete( 'imagelinks', array( 'il_from' => $id ) );
|
|
|
|
|
$dbw->delete( 'categorylinks', array( 'cl_from' => $id ) );
|
|
|
|
|
$dbw->delete( 'templatelinks', array( 'tl_from' => $id ) );
|
|
|
|
|
$dbw->delete( 'externallinks', array( 'el_from' => $id ) );
|
|
|
|
|
$dbw->delete( 'langlinks', array( 'll_from' => $id ) );
|
2006-11-02 11:39:13 +00:00
|
|
|
$dbw->delete( 'redirect', array( 'rd_from' => $id ) );
|
2006-07-17 00:54:40 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2006-07-17 00:54:40 +00:00
|
|
|
# If using cleanup triggers, we can skip some manual deletes
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$dbw->cleanupTriggers() ) {
|
2006-07-17 00:54:40 +00:00
|
|
|
# Clean up recentchanges entries...
|
2008-10-04 22:00:44 +00:00
|
|
|
$dbw->delete( 'recentchanges',
|
|
|
|
|
array( 'rc_type != '.RC_LOG,
|
|
|
|
|
'rc_namespace' => $this->mTitle->getNamespace(),
|
|
|
|
|
'rc_title' => $this->mTitle->getDBKey() ),
|
|
|
|
|
__METHOD__ );
|
2008-04-14 07:45:50 +00:00
|
|
|
$dbw->delete( 'recentchanges',
|
2008-09-20 14:19:42 +00:00
|
|
|
array( 'rc_type != '.RC_LOG, 'rc_cur_id' => $id ),
|
2008-04-14 01:04:10 +00:00
|
|
|
__METHOD__ );
|
2006-07-17 00:54:40 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2006-06-18 12:42:16 +00:00
|
|
|
# Clear caches
|
2004-03-20 15:03:26 +00:00
|
|
|
Article::onArticleDelete( $this->mTitle );
|
2008-09-18 23:43:41 +00:00
|
|
|
|
|
|
|
|
# Fix category table counts
|
|
|
|
|
$cats = array();
|
|
|
|
|
$res = $dbw->select( 'categorylinks', 'cl_to', array( 'cl_from' => $id ), __METHOD__ );
|
|
|
|
|
foreach( $res as $row ) {
|
|
|
|
|
$cats []= $row->cl_to;
|
|
|
|
|
}
|
|
|
|
|
$this->updateCategoryCounts( array(), $cats );
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2008-04-11 23:42:09 +00:00
|
|
|
# Clear the cached article id so the interface doesn't act like we exist
|
|
|
|
|
$this->mTitle->resetArticleID( 0 );
|
|
|
|
|
$this->mTitle->mArticleID = 0;
|
|
|
|
|
|
2008-03-09 02:18:50 +00:00
|
|
|
# Log the deletion, if the page was suppressed, log it at Oversight instead
|
2008-04-01 22:50:53 +00:00
|
|
|
$logtype = $suppress ? 'suppress' : 'delete';
|
2008-03-09 02:18:50 +00:00
|
|
|
$log = new LogPage( $logtype );
|
2008-04-27 23:45:31 +00:00
|
|
|
|
2008-04-15 23:34:45 +00:00
|
|
|
# Make sure logging got through
|
2008-04-27 23:45:31 +00:00
|
|
|
$log->addEntry( 'delete', $this->mTitle, $reason, array() );
|
2008-09-18 23:43:41 +00:00
|
|
|
|
|
|
|
|
$dbw->commit();
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2004-03-20 15:03:26 +00:00
|
|
|
return true;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2007-07-09 08:12:44 +00:00
|
|
|
/**
|
2008-01-14 20:17:05 +00:00
|
|
|
* Roll back the most recent consecutive set of edits to a page
|
|
|
|
|
* from the same user; fails if there are no eligible edits to
|
2008-01-15 17:31:07 +00:00
|
|
|
* roll back to, e.g. user is the sole contributor. This function
|
|
|
|
|
* performs permissions checks on $wgUser, then calls commitRollback()
|
|
|
|
|
* to do the dirty work
|
2007-07-09 08:12:44 +00:00
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $fromP String: Name of the user whose edits to rollback.
|
|
|
|
|
* @param $summary String: Custom summary. Set to default summary if empty.
|
|
|
|
|
* @param $token String: Rollback token.
|
|
|
|
|
* @param $bot Boolean: If true, mark all reverted edits as bot.
|
2008-04-14 07:45:50 +00:00
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $resultDetails Array: contains result-specific array of additional values
|
2008-01-15 17:31:07 +00:00
|
|
|
* 'alreadyrolled' : 'current' (rev)
|
|
|
|
|
* success : 'summary' (str), 'current' (rev), 'target' (rev)
|
2008-04-14 07:45:50 +00:00
|
|
|
*
|
2008-01-16 00:06:42 +00:00
|
|
|
* @return array of errors, each error formatted as
|
|
|
|
|
* array(messagekey, param1, param2, ...).
|
|
|
|
|
* On success, the array is empty. This array can also be passed to
|
2008-01-18 15:52:40 +00:00
|
|
|
* OutputPage::showPermissionsErrorPage().
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2007-07-09 08:12:44 +00:00
|
|
|
public function doRollback( $fromP, $summary, $token, $bot, &$resultDetails ) {
|
2008-01-15 17:31:07 +00:00
|
|
|
global $wgUser;
|
2007-07-07 07:32:34 +00:00
|
|
|
$resultDetails = null;
|
2007-09-10 07:48:20 +00:00
|
|
|
|
2008-01-15 17:31:07 +00:00
|
|
|
# Check permissions
|
2008-12-06 21:16:55 +00:00
|
|
|
$editErrors = $this->mTitle->getUserPermissionsErrors( 'edit', $wgUser );
|
|
|
|
|
$rollbackErrors = $this->mTitle->getUserPermissionsErrors( 'rollback', $wgUser );
|
|
|
|
|
$errors = array_merge( $editErrors, wfArrayDiff2( $rollbackErrors, $editErrors ) );
|
|
|
|
|
|
2007-07-09 08:12:44 +00:00
|
|
|
if( !$wgUser->matchEditToken( $token, array( $this->mTitle->getPrefixedText(), $fromP ) ) )
|
2008-01-15 17:31:07 +00:00
|
|
|
$errors[] = array( 'sessionfailure' );
|
2007-06-29 20:02:26 +00:00
|
|
|
|
2008-12-06 21:16:55 +00:00
|
|
|
if( $wgUser->pingLimiter( 'rollback' ) || $wgUser->pingLimiter() ) {
|
2008-01-15 17:31:07 +00:00
|
|
|
$errors[] = array( 'actionthrottledtext' );
|
2007-11-20 08:34:59 +00:00
|
|
|
}
|
2008-01-15 17:31:07 +00:00
|
|
|
# If there were errors, bail out now
|
2008-12-06 21:16:55 +00:00
|
|
|
if( !empty( $errors ) )
|
2008-01-15 17:31:07 +00:00
|
|
|
return $errors;
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-01-15 17:31:07 +00:00
|
|
|
return $this->commitRollback($fromP, $summary, $bot, $resultDetails);
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-01-15 17:31:07 +00:00
|
|
|
/**
|
2008-01-16 00:06:42 +00:00
|
|
|
* Backend implementation of doRollback(), please refer there for parameter
|
|
|
|
|
* and return value documentation
|
2008-01-15 17:31:07 +00:00
|
|
|
*
|
2008-01-16 00:06:42 +00:00
|
|
|
* NOTE: This function does NOT check ANY permissions, it just commits the
|
|
|
|
|
* rollback to the DB Therefore, you should only call this function direct-
|
|
|
|
|
* ly if you want to use custom permissions checks. If you don't, use
|
|
|
|
|
* doRollback() instead.
|
2008-04-14 07:45:50 +00:00
|
|
|
*/
|
2008-01-15 17:31:07 +00:00
|
|
|
public function commitRollback($fromP, $summary, $bot, &$resultDetails) {
|
2008-05-03 16:07:57 +00:00
|
|
|
global $wgUseRCPatrol, $wgUser, $wgLang;
|
2007-07-09 08:12:44 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2007-06-29 20:02:26 +00:00
|
|
|
|
2008-01-16 00:06:42 +00:00
|
|
|
if( wfReadOnly() ) {
|
|
|
|
|
return array( array( 'readonlytext' ) );
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-29 20:02:26 +00:00
|
|
|
# Get the last editor
|
|
|
|
|
$current = Revision::newFromTitle( $this->mTitle );
|
|
|
|
|
if( is_null( $current ) ) {
|
|
|
|
|
# Something wrong... no page?
|
2008-01-15 17:31:07 +00:00
|
|
|
return array(array('notanarticle'));
|
2007-06-29 20:02:26 +00:00
|
|
|
}
|
|
|
|
|
|
2007-07-07 07:32:34 +00:00
|
|
|
$from = str_replace( '_', ' ', $fromP );
|
2007-06-29 20:02:26 +00:00
|
|
|
if( $from != $current->getUserText() ) {
|
2007-07-09 08:12:44 +00:00
|
|
|
$resultDetails = array( 'current' => $current );
|
2008-01-15 17:31:07 +00:00
|
|
|
return array(array('alreadyrolled',
|
|
|
|
|
htmlspecialchars($this->mTitle->getPrefixedText()),
|
|
|
|
|
htmlspecialchars($fromP),
|
|
|
|
|
htmlspecialchars($current->getUserText())
|
|
|
|
|
));
|
2007-06-29 20:02:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Get the last edit not by this guy
|
|
|
|
|
$user = intval( $current->getUser() );
|
|
|
|
|
$user_text = $dbw->addQuotes( $current->getUserText() );
|
|
|
|
|
$s = $dbw->selectRow( 'revision',
|
2008-03-09 02:18:50 +00:00
|
|
|
array( 'rev_id', 'rev_timestamp', 'rev_deleted' ),
|
2008-01-15 17:31:07 +00:00
|
|
|
array( 'rev_page' => $current->getPage(),
|
2008-11-28 14:29:25 +00:00
|
|
|
"rev_user != {$user} OR rev_user_text != {$user_text}"
|
2006-06-20 09:50:57 +00:00
|
|
|
), __METHOD__,
|
2008-01-15 17:31:07 +00:00
|
|
|
array( 'USE INDEX' => 'page_timestamp',
|
2007-06-29 20:02:26 +00:00
|
|
|
'ORDER BY' => 'rev_timestamp DESC' )
|
|
|
|
|
);
|
|
|
|
|
if( $s === false ) {
|
2008-01-15 17:31:07 +00:00
|
|
|
# No one else ever edited this page
|
|
|
|
|
return array(array('cantrollback'));
|
2008-03-09 02:18:50 +00:00
|
|
|
} else if( $s->rev_deleted & REVISION::DELETED_TEXT || $s->rev_deleted & REVISION::DELETED_USER ) {
|
|
|
|
|
# Only admins can see this text
|
|
|
|
|
return array(array('notvisiblerev'));
|
2007-06-29 20:02:26 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2005-12-17 00:44:23 +00:00
|
|
|
$set = array();
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $bot && $wgUser->isAllowed('markbotedits') ) {
|
2007-06-29 20:02:26 +00:00
|
|
|
# Mark all reverted edits as bot
|
2005-12-17 00:44:23 +00:00
|
|
|
$set['rc_bot'] = 1;
|
2007-06-29 20:02:26 +00:00
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $wgUseRCPatrol ) {
|
2007-06-29 20:02:26 +00:00
|
|
|
# Mark all reverted edits as patrolled
|
2005-12-17 00:44:23 +00:00
|
|
|
$set['rc_patrolled'] = 1;
|
2007-06-29 20:02:26 +00:00
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $set ) {
|
2007-06-29 20:02:26 +00:00
|
|
|
$dbw->update( 'recentchanges', $set,
|
2007-07-07 07:32:34 +00:00
|
|
|
array( /* WHERE */
|
|
|
|
|
'rc_cur_id' => $current->getPage(),
|
|
|
|
|
'rc_user_text' => $current->getUserText(),
|
|
|
|
|
"rc_timestamp > '{$s->rev_timestamp}'",
|
|
|
|
|
), __METHOD__
|
|
|
|
|
);
|
2007-06-29 19:55:46 +00:00
|
|
|
}
|
2007-06-29 20:02:26 +00:00
|
|
|
|
2008-01-15 17:31:07 +00:00
|
|
|
# Generate the edit summary if necessary
|
2007-10-01 19:50:25 +00:00
|
|
|
$target = Revision::newFromId( $s->rev_id );
|
2008-05-03 16:07:57 +00:00
|
|
|
if( empty( $summary ) ){
|
|
|
|
|
$summary = wfMsgForContent( 'revertpage' );
|
2008-01-15 15:38:30 +00:00
|
|
|
}
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2008-05-03 16:07:57 +00:00
|
|
|
# Allow the custom summary to use the same args as the default message
|
|
|
|
|
$args = array(
|
|
|
|
|
$target->getUserText(), $from, $s->rev_id,
|
|
|
|
|
$wgLang->timeanddate(wfTimestamp(TS_MW, $s->rev_timestamp), true),
|
|
|
|
|
$current->getId(), $wgLang->timeanddate($current->getTimestamp())
|
|
|
|
|
);
|
2008-08-08 00:01:53 +00:00
|
|
|
$summary = wfMsgReplaceArgs( $summary, $args );
|
2007-06-29 20:02:26 +00:00
|
|
|
|
2007-07-07 00:17:51 +00:00
|
|
|
# Save
|
2007-12-07 09:44:47 +00:00
|
|
|
$flags = EDIT_UPDATE;
|
|
|
|
|
|
2008-09-23 18:20:50 +00:00
|
|
|
if( $wgUser->isAllowed('minoredit') )
|
2007-12-07 09:44:47 +00:00
|
|
|
$flags |= EDIT_MINOR;
|
|
|
|
|
|
2008-01-10 19:27:49 +00:00
|
|
|
if( $bot && ($wgUser->isAllowed('markbotedits') || $wgUser->isAllowed('bot')) )
|
2007-07-06 09:06:55 +00:00
|
|
|
$flags |= EDIT_FORCE_BOT;
|
2008-09-23 18:20:50 +00:00
|
|
|
# Actually store the edit
|
2008-09-25 10:15:19 +00:00
|
|
|
$status = $this->doEdit( $target->getText(), $summary, $flags, $target->getId() );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !empty( $status->value['revision'] ) ) {
|
2008-09-25 10:15:19 +00:00
|
|
|
$revId = $status->value['revision']->getId();
|
|
|
|
|
} else {
|
|
|
|
|
$revId = false;
|
|
|
|
|
}
|
2007-07-07 00:17:51 +00:00
|
|
|
|
2009-01-04 12:27:08 +00:00
|
|
|
wfRunHooks( 'ArticleRollbackComplete', array( $this, $wgUser, $target, $current ) );
|
2007-10-30 07:58:15 +00:00
|
|
|
|
2007-07-07 07:32:34 +00:00
|
|
|
$resultDetails = array(
|
|
|
|
|
'summary' => $summary,
|
|
|
|
|
'current' => $current,
|
2007-07-09 08:12:44 +00:00
|
|
|
'target' => $target,
|
2008-09-23 18:20:50 +00:00
|
|
|
'newid' => $revId
|
2007-07-09 08:12:44 +00:00
|
|
|
);
|
2008-01-15 17:31:07 +00:00
|
|
|
return array();
|
2007-07-07 07:32:34 +00:00
|
|
|
}
|
2007-06-29 20:02:26 +00:00
|
|
|
|
2007-07-09 08:12:44 +00:00
|
|
|
/**
|
|
|
|
|
* User interface for rollback operations
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function rollback() {
|
2007-07-07 07:32:34 +00:00
|
|
|
global $wgUser, $wgOut, $wgRequest, $wgUseRCPatrol;
|
2007-07-09 08:12:44 +00:00
|
|
|
$details = null;
|
2007-09-10 07:48:20 +00:00
|
|
|
|
2007-07-09 08:12:44 +00:00
|
|
|
$result = $this->doRollback(
|
|
|
|
|
$wgRequest->getVal( 'from' ),
|
|
|
|
|
$wgRequest->getText( 'summary' ),
|
|
|
|
|
$wgRequest->getVal( 'token' ),
|
2008-01-10 07:52:09 +00:00
|
|
|
$wgRequest->getBool( 'bot' ),
|
2007-07-09 08:12:44 +00:00
|
|
|
$details
|
|
|
|
|
);
|
2008-01-16 00:06:42 +00:00
|
|
|
|
|
|
|
|
if( in_array( array( 'actionthrottledtext' ), $result ) ) {
|
2008-01-15 17:31:07 +00:00
|
|
|
$wgOut->rateLimited();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2008-09-23 18:20:50 +00:00
|
|
|
if( isset( $result[0][0] ) && ( $result[0][0] == 'alreadyrolled' || $result[0][0] == 'cantrollback' ) ) {
|
2008-03-05 13:50:17 +00:00
|
|
|
$wgOut->setPageTitle( wfMsg( 'rollbackfailed' ) );
|
|
|
|
|
$errArray = $result[0];
|
|
|
|
|
$errMsg = array_shift( $errArray );
|
|
|
|
|
$wgOut->addWikiMsgArray( $errMsg, $errArray );
|
|
|
|
|
if( isset( $details['current'] ) ){
|
|
|
|
|
$current = $details['current'];
|
|
|
|
|
if( $current->getComment() != '' ) {
|
2008-09-23 18:20:50 +00:00
|
|
|
$wgOut->addWikiMsgArray( 'editcomment', array(
|
|
|
|
|
$wgUser->getSkin()->formatComment( $current->getComment() ) ), array( 'replaceafter' ) );
|
2008-03-05 13:50:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2008-01-16 00:06:42 +00:00
|
|
|
# Display permissions errors before read-only message -- there's no
|
|
|
|
|
# point in misleading the user into thinking the inability to rollback
|
|
|
|
|
# is only temporary.
|
2008-12-06 21:16:55 +00:00
|
|
|
if( !empty( $result ) && $result !== array( array( 'readonlytext' ) ) ) {
|
2008-01-16 00:06:42 +00:00
|
|
|
# array_diff is completely broken for arrays of arrays, sigh. Re-
|
|
|
|
|
# move any 'readonlytext' error manually.
|
|
|
|
|
$out = array();
|
|
|
|
|
foreach( $result as $error ) {
|
|
|
|
|
if( $error != array( 'readonlytext' ) ) {
|
|
|
|
|
$out []= $error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$wgOut->showPermissionsErrorPage( $out );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2008-12-06 21:16:55 +00:00
|
|
|
if( $result == array( array( 'readonlytext' ) ) ) {
|
2008-01-16 00:06:42 +00:00
|
|
|
$wgOut->readOnlyPage();
|
2008-01-15 17:31:07 +00:00
|
|
|
return;
|
2007-07-07 07:32:34 +00:00
|
|
|
}
|
2007-07-09 08:12:44 +00:00
|
|
|
|
2008-01-15 17:31:07 +00:00
|
|
|
$current = $details['current'];
|
|
|
|
|
$target = $details['target'];
|
2008-09-23 18:20:50 +00:00
|
|
|
$newId = $details['newid'];
|
2008-01-15 17:31:07 +00:00
|
|
|
$wgOut->setPageTitle( wfMsg( 'actioncomplete' ) );
|
|
|
|
|
$wgOut->setRobotPolicy( 'noindex,nofollow' );
|
|
|
|
|
$old = $wgUser->getSkin()->userLink( $current->getUser(), $current->getUserText() )
|
|
|
|
|
. $wgUser->getSkin()->userToolLinks( $current->getUser(), $current->getUserText() );
|
|
|
|
|
$new = $wgUser->getSkin()->userLink( $target->getUser(), $target->getUserText() )
|
|
|
|
|
. $wgUser->getSkin()->userToolLinks( $target->getUser(), $target->getUserText() );
|
2008-11-06 22:20:29 +00:00
|
|
|
$wgOut->addHTML( wfMsgExt( 'rollback-success', array( 'parse', 'replaceafter' ), $old, $new ) );
|
2008-01-15 17:31:07 +00:00
|
|
|
$wgOut->returnToMain( false, $this->mTitle );
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2008-11-02 23:44:18 +00:00
|
|
|
if( !$wgRequest->getBool( 'hidediff', false ) && !$wgUser->getBoolOption( 'norollbackdiff', false ) ) {
|
2008-09-23 18:20:50 +00:00
|
|
|
$de = new DifferenceEngine( $this->mTitle, $current->getId(), $newId, false, true );
|
2008-06-02 00:13:08 +00:00
|
|
|
$de->showDiff( '', '' );
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2007-06-29 20:02:26 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Do standard deferred updates after page view
|
|
|
|
|
*/
|
2008-12-11 14:29:16 +00:00
|
|
|
public function viewUpdates() {
|
|
|
|
|
global $wgDeferredUpdateList, $wgDisableCounters, $wgUser;
|
|
|
|
|
# Don't update page view counters on views from bot users (bug 14044)
|
|
|
|
|
if( !$wgDisableCounters && !$wgUser->isAllowed('bot') && $this->getID() ) {
|
|
|
|
|
Article::incViewCount( $this->getID() );
|
|
|
|
|
$u = new SiteStatsUpdate( 1, 0, 0 );
|
|
|
|
|
array_push( $wgDeferredUpdateList, $u );
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2005-12-07 11:52:34 +00:00
|
|
|
# Update newtalk / watchlist notification status
|
|
|
|
|
$wgUser->clearNotification( $this->mTitle );
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2007-11-12 07:30:40 +00:00
|
|
|
/**
|
|
|
|
|
* Prepare text which is about to be saved.
|
2008-06-11 02:51:30 +00:00
|
|
|
* Returns a stdclass with source, pst and output members
|
2007-11-12 07:30:40 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function prepareTextForEdit( $text, $revid=null ) {
|
|
|
|
|
if( $this->mPreparedEdit && $this->mPreparedEdit->newText == $text && $this->mPreparedEdit->revid == $revid) {
|
2007-11-12 07:30:40 +00:00
|
|
|
// Already prepared
|
|
|
|
|
return $this->mPreparedEdit;
|
|
|
|
|
}
|
|
|
|
|
global $wgParser;
|
|
|
|
|
$edit = (object)array();
|
2007-11-15 02:54:28 +00:00
|
|
|
$edit->revid = $revid;
|
2007-11-12 07:30:40 +00:00
|
|
|
$edit->newText = $text;
|
|
|
|
|
$edit->pst = $this->preSaveTransform( $text );
|
2008-06-11 02:51:30 +00:00
|
|
|
$options = new ParserOptions;
|
2007-11-12 07:30:40 +00:00
|
|
|
$options->setTidy( true );
|
2007-11-30 14:50:48 +00:00
|
|
|
$options->enableLimitReport();
|
2007-11-15 02:54:28 +00:00
|
|
|
$edit->output = $wgParser->parse( $edit->pst, $this->mTitle, $options, true, true, $revid );
|
2007-11-12 07:30:40 +00:00
|
|
|
$edit->oldText = $this->getContent();
|
|
|
|
|
$this->mPreparedEdit = $edit;
|
|
|
|
|
return $edit;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Do standard deferred updates after page edit.
|
2006-06-18 12:42:16 +00:00
|
|
|
* Update links tables, site stats, search index and message cache.
|
2008-09-20 22:48:55 +00:00
|
|
|
* Purges pages that include this page if the text was changed here.
|
2007-09-02 18:23:43 +00:00
|
|
|
* Every 100th edit, prune the recent changes table.
|
2007-01-17 22:32:40 +00:00
|
|
|
*
|
2006-04-19 15:46:24 +00:00
|
|
|
* @private
|
2006-06-24 13:08:48 +00:00
|
|
|
* @param $text New text of the article
|
|
|
|
|
* @param $summary Edit summary
|
|
|
|
|
* @param $minoredit Minor edit
|
|
|
|
|
* @param $timestamp_of_pagechange Timestamp associated with the page change
|
|
|
|
|
* @param $newid rev_id value of the new revision
|
|
|
|
|
* @param $changed Whether or not the content actually changed
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function editUpdates( $text, $summary, $minoredit, $timestamp_of_pagechange, $newid, $changed = true ) {
|
2008-01-16 02:20:49 +00:00
|
|
|
global $wgDeferredUpdateList, $wgMessageCache, $wgUser, $wgParser, $wgEnableParserCache;
|
2005-12-30 09:33:11 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2005-12-30 09:33:11 +00:00
|
|
|
# Parse the text
|
2007-11-12 07:30:40 +00:00
|
|
|
# Be careful not to double-PST: $text is usually already PST-ed once
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$this->mPreparedEdit || $this->mPreparedEdit->output->getFlag( 'vary-revision' ) ) {
|
2007-11-15 02:54:28 +00:00
|
|
|
wfDebug( __METHOD__ . ": No prepared edit or vary-revision is set...\n" );
|
|
|
|
|
$editInfo = $this->prepareTextForEdit( $text, $newid );
|
2007-11-12 07:30:40 +00:00
|
|
|
} else {
|
2007-11-15 02:54:28 +00:00
|
|
|
wfDebug( __METHOD__ . ": No vary-revision, using prepared edit...\n" );
|
2007-11-12 07:30:40 +00:00
|
|
|
$editInfo = $this->mPreparedEdit;
|
|
|
|
|
}
|
2005-12-30 09:33:11 +00:00
|
|
|
|
|
|
|
|
# Save it to the parser cache
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $wgEnableParserCache ) {
|
2008-04-09 18:23:34 +00:00
|
|
|
$parserCache = ParserCache::singleton();
|
2008-06-11 02:51:30 +00:00
|
|
|
$parserCache->save( $editInfo->output, $this, $wgUser );
|
2008-01-16 02:20:49 +00:00
|
|
|
}
|
2005-12-30 09:33:11 +00:00
|
|
|
|
|
|
|
|
# Update the links tables
|
2008-09-20 22:48:55 +00:00
|
|
|
$u = new LinksUpdate( $this->mTitle, $editInfo->output, false );
|
|
|
|
|
$u->setRecursiveTouch( $changed ); // refresh/invalidate including pages too
|
2005-12-30 09:33:11 +00:00
|
|
|
$u->doUpdate();
|
2008-09-27 10:52:49 +00:00
|
|
|
|
|
|
|
|
wfRunHooks( 'ArticleEditUpdates', array( &$this, &$editInfo, $changed ) );
|
2004-08-09 05:38:11 +00:00
|
|
|
|
2007-08-22 07:24:30 +00:00
|
|
|
if( wfRunHooks( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) {
|
2008-11-28 14:29:25 +00:00
|
|
|
if( 0 == mt_rand( 0, 99 ) ) {
|
2007-08-22 07:24:30 +00:00
|
|
|
// Flush old entries from the `recentchanges` table; we do this on
|
|
|
|
|
// random requests so as to avoid an increase in writes for no good reason
|
2005-10-08 19:24:47 +00:00
|
|
|
global $wgRCMaxAge;
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2005-10-08 19:24:47 +00:00
|
|
|
$cutoff = $dbw->timestamp( time() - $wgRCMaxAge );
|
|
|
|
|
$recentchanges = $dbw->tableName( 'recentchanges' );
|
|
|
|
|
$sql = "DELETE FROM $recentchanges WHERE rc_timestamp < '{$cutoff}'";
|
|
|
|
|
$dbw->query( $sql );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-31 16:59:08 +00:00
|
|
|
$id = $this->getID();
|
|
|
|
|
$title = $this->mTitle->getPrefixedDBkey();
|
|
|
|
|
$shortTitle = $this->mTitle->getDBkey();
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( 0 == $id ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2005-12-30 09:33:11 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2005-12-30 09:33:11 +00:00
|
|
|
$u = new SiteStatsUpdate( 0, 1, $this->mGoodAdjustment, $this->mTotalAdjustment );
|
|
|
|
|
array_push( $wgDeferredUpdateList, $u );
|
|
|
|
|
$u = new SearchUpdate( $id, $title, $text );
|
|
|
|
|
array_push( $wgDeferredUpdateList, $u );
|
|
|
|
|
|
|
|
|
|
# If this is another user's talk page, update newtalk
|
2006-06-24 13:08:48 +00:00
|
|
|
# Don't do this if $changed = false otherwise some idiot can null-edit a
|
2006-10-29 12:11:58 +00:00
|
|
|
# load of user talk pages and piss people off, nor if it's a minor edit
|
|
|
|
|
# by a properly-flagged bot.
|
|
|
|
|
if( $this->mTitle->getNamespace() == NS_USER_TALK && $shortTitle != $wgUser->getTitleKey() && $changed
|
2008-09-04 23:25:53 +00:00
|
|
|
&& !( $minoredit && $wgUser->isAllowed( 'nominornewtalk' ) ) ) {
|
|
|
|
|
if( wfRunHooks('ArticleEditUpdateNewTalk', array( &$this ) ) ) {
|
|
|
|
|
$other = User::newFromName( $shortTitle, false );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$other ) {
|
2008-08-08 09:47:36 +00:00
|
|
|
wfDebug( __METHOD__.": invalid username\n" );
|
|
|
|
|
} elseif( User::isIP( $shortTitle ) ) {
|
2006-02-14 21:10:31 +00:00
|
|
|
// An anonymous user
|
|
|
|
|
$other->setNewtalk( true );
|
2008-08-08 09:47:36 +00:00
|
|
|
} elseif( $other->isLoggedIn() ) {
|
2008-08-07 10:39:19 +00:00
|
|
|
$other->setNewtalk( true );
|
|
|
|
|
} else {
|
|
|
|
|
wfDebug( __METHOD__. ": don't need to notify a nonexistent user\n" );
|
2006-02-14 21:10:31 +00:00
|
|
|
}
|
2004-01-31 16:59:08 +00:00
|
|
|
}
|
|
|
|
|
}
|
2005-12-30 09:33:11 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
|
2005-12-30 09:33:11 +00:00
|
|
|
$wgMessageCache->replace( $shortTitle, $text );
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2004-01-31 16:59:08 +00:00
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-10-09 02:15:12 +00:00
|
|
|
/**
|
|
|
|
|
* Perform article updates on a special page creation.
|
|
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $rev Revision object
|
2006-10-09 02:15:12 +00:00
|
|
|
*
|
2007-09-07 13:30:28 +00:00
|
|
|
* @todo This is a shitty interface function. Kill it and replace the
|
|
|
|
|
* other shitty functions like editUpdates and such so it's not needed
|
2006-10-09 02:15:12 +00:00
|
|
|
* anymore.
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function createUpdates( $rev ) {
|
2006-10-09 02:15:12 +00:00
|
|
|
$this->mGoodAdjustment = $this->isCountable( $rev->getText() );
|
|
|
|
|
$this->mTotalAdjustment = 1;
|
|
|
|
|
$this->editUpdates( $rev->getText(), $rev->getComment(),
|
|
|
|
|
$rev->isMinor(), wfTimestamp(), $rev->getId(), true );
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2006-01-16 18:34:11 +00:00
|
|
|
* Generate the navigation links when browsing through an article revisions
|
|
|
|
|
* It shows the information as:
|
2006-04-19 15:46:24 +00:00
|
|
|
* Revision as of \<date\>; view current revision
|
|
|
|
|
* \<- Previous version | Next Version -\>
|
2006-01-16 18:34:11 +00:00
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $oldid String: revision ID of this article revision
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-12-22 18:30:13 +00:00
|
|
|
public function setOldSubtitle( $oldid = 0 ) {
|
2006-11-08 07:12:03 +00:00
|
|
|
global $wgLang, $wgOut, $wgUser;
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2008-12-22 18:30:13 +00:00
|
|
|
if( !wfRunHooks( 'DisplayOldSubtitle', array( &$this, &$oldid ) ) ) {
|
2008-11-28 14:29:25 +00:00
|
|
|
return;
|
2007-01-17 22:32:40 +00:00
|
|
|
}
|
2006-07-27 18:51:52 +00:00
|
|
|
|
2006-06-20 15:19:13 +00:00
|
|
|
$revision = Revision::newFromId( $oldid );
|
|
|
|
|
|
2005-06-29 23:44:03 +00:00
|
|
|
$current = ( $oldid == $this->mLatest );
|
2003-04-14 23:10:40 +00:00
|
|
|
$td = $wgLang->timeanddate( $this->mTimestamp, true );
|
2006-11-08 07:12:03 +00:00
|
|
|
$sk = $wgUser->getSkin();
|
2005-06-29 23:44:03 +00:00
|
|
|
$lnk = $current
|
2008-12-22 18:30:13 +00:00
|
|
|
? wfMsgHtml( 'currentrevisionlink' )
|
|
|
|
|
: $sk->makeKnownLinkObj( $this->mTitle, wfMsgHtml( 'currentrevisionlink' ) );
|
2006-11-16 05:44:59 +00:00
|
|
|
$curdiff = $current
|
2008-12-22 18:30:13 +00:00
|
|
|
? wfMsgHtml( 'diff' )
|
|
|
|
|
: $sk->makeKnownLinkObj( $this->mTitle, wfMsgHtml( 'diff' ), 'diff=cur&oldid='.$oldid );
|
2006-01-16 18:34:11 +00:00
|
|
|
$prev = $this->mTitle->getPreviousRevisionID( $oldid ) ;
|
|
|
|
|
$prevlink = $prev
|
2008-12-22 18:30:13 +00:00
|
|
|
? $sk->makeKnownLinkObj( $this->mTitle, wfMsgHtml( 'previousrevision' ), 'direction=prev&oldid='.$oldid )
|
|
|
|
|
: wfMsgHtml( 'previousrevision' );
|
2006-07-01 18:47:36 +00:00
|
|
|
$prevdiff = $prev
|
2008-12-22 18:30:13 +00:00
|
|
|
? $sk->makeKnownLinkObj( $this->mTitle, wfMsgHtml( 'diff' ), 'diff=prev&oldid='.$oldid )
|
|
|
|
|
: wfMsgHtml( 'diff' );
|
2005-06-29 23:44:03 +00:00
|
|
|
$nextlink = $current
|
2008-12-22 18:30:13 +00:00
|
|
|
? wfMsgHtml( 'nextrevision' )
|
|
|
|
|
: $sk->makeKnownLinkObj( $this->mTitle, wfMsgHtml( 'nextrevision' ), 'direction=next&oldid='.$oldid );
|
2006-07-01 18:47:36 +00:00
|
|
|
$nextdiff = $current
|
2008-12-22 18:30:13 +00:00
|
|
|
? wfMsgHtml( 'diff' )
|
|
|
|
|
: $sk->makeKnownLinkObj( $this->mTitle, wfMsgHtml( 'diff' ), 'diff=next&oldid='.$oldid );
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2008-03-09 02:18:50 +00:00
|
|
|
$cdel='';
|
2008-04-14 07:45:50 +00:00
|
|
|
if( $wgUser->isAllowed( 'deleterevision' ) ) {
|
2008-03-09 02:18:50 +00:00
|
|
|
$revdel = SpecialPage::getTitleFor( 'Revisiondelete' );
|
|
|
|
|
if( $revision->isCurrent() ) {
|
|
|
|
|
// We don't handle top deleted edits too well
|
2008-12-22 18:30:13 +00:00
|
|
|
$cdel = wfMsgHtml( 'rev-delundel' );
|
2008-03-09 02:18:50 +00:00
|
|
|
} else if( !$revision->userCan( Revision::DELETED_RESTRICTED ) ) {
|
|
|
|
|
// If revision was hidden from sysops
|
2008-12-22 18:30:13 +00:00
|
|
|
$cdel = wfMsgHtml( 'rev-delundel' );
|
2008-03-09 02:18:50 +00:00
|
|
|
} else {
|
|
|
|
|
$cdel = $sk->makeKnownLinkObj( $revdel,
|
|
|
|
|
wfMsgHtml('rev-delundel'),
|
|
|
|
|
'target=' . urlencode( $this->mTitle->getPrefixedDbkey() ) .
|
|
|
|
|
'&oldid=' . urlencode( $oldid ) );
|
|
|
|
|
// Bolden oversighted content
|
|
|
|
|
if( $revision->isDeleted( Revision::DELETED_RESTRICTED ) )
|
|
|
|
|
$cdel = "<strong>$cdel</strong>";
|
|
|
|
|
}
|
|
|
|
|
$cdel = "(<small>$cdel</small>) ";
|
|
|
|
|
}
|
2008-03-16 21:24:52 +00:00
|
|
|
# Show user links if allowed to see them. Normally they
|
|
|
|
|
# are hidden regardless, but since we can already see the text here...
|
|
|
|
|
$userlinks = $sk->revUserTools( $revision, false );
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2007-06-20 07:28:45 +00:00
|
|
|
$m = wfMsg( 'revision-info-current' );
|
|
|
|
|
$infomsg = $current && !wfEmptyMsg( 'revision-info-current', $m ) && $m != '-'
|
|
|
|
|
? 'revision-info-current'
|
|
|
|
|
: 'revision-info';
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-12-22 18:30:13 +00:00
|
|
|
$r = "\n\t\t\t\t<div id=\"mw-{$infomsg}\">" . wfMsgExt( $infomsg, array( 'parseinline', 'replaceafter' ), $td, $userlinks, $revision->getID() ) . "</div>\n" .
|
2008-12-06 18:24:03 +00:00
|
|
|
|
2008-12-22 18:30:13 +00:00
|
|
|
"\n\t\t\t\t<div id=\"mw-revision-nav\">" . $cdel . wfMsgHtml( 'revision-nav', $prevdiff,
|
2008-09-20 22:48:55 +00:00
|
|
|
$prevlink, $lnk, $curdiff, $nextlink, $nextdiff ) . "</div>\n\t\t\t";
|
2004-09-01 03:01:37 +00:00
|
|
|
$wgOut->setSubtitle( $r );
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* This function is called right before saving the wikitext,
|
|
|
|
|
* so we can do things like signatures and links-in-context.
|
2004-09-03 00:20:26 +00:00
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $text String
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function preSaveTransform( $text ) {
|
2004-03-06 01:49:16 +00:00
|
|
|
global $wgParser, $wgUser;
|
|
|
|
|
return $wgParser->preSaveTransform( $text, $this->mTitle, $wgUser, ParserOptions::newFromUser( $wgUser ) );
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2003-05-16 13:39:22 +00:00
|
|
|
/* Caching functions */
|
2003-12-11 20:16:34 +00:00
|
|
|
|
2004-09-03 00:20:26 +00:00
|
|
|
/**
|
|
|
|
|
* checkLastModified returns true if it has taken care of all
|
|
|
|
|
* output to the client that is necessary for this request.
|
|
|
|
|
* (that is, it has sent a cached version of the page)
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
protected function tryFileCache() {
|
2003-11-24 08:41:40 +00:00
|
|
|
static $called = false;
|
|
|
|
|
if( $called ) {
|
2006-07-03 16:45:51 +00:00
|
|
|
wfDebug( "Article::tryFileCache(): called twice!?\n" );
|
2008-09-25 23:02:35 +00:00
|
|
|
return false;
|
2003-11-24 08:41:40 +00:00
|
|
|
}
|
|
|
|
|
$called = true;
|
2008-09-25 23:02:35 +00:00
|
|
|
if( $this->isFileCacheable() ) {
|
2006-10-11 08:25:26 +00:00
|
|
|
$cache = new HTMLFileCache( $this->mTitle );
|
2008-12-09 21:40:06 +00:00
|
|
|
if( $cache->isFileCacheGood( $this->mTouched ) ) {
|
2006-07-03 16:45:51 +00:00
|
|
|
wfDebug( "Article::tryFileCache(): about to load file\n" );
|
2003-08-02 10:13:27 +00:00
|
|
|
$cache->loadFromFileCache();
|
2003-12-11 20:16:34 +00:00
|
|
|
return true;
|
2003-05-16 13:39:22 +00:00
|
|
|
} else {
|
2006-07-03 16:45:51 +00:00
|
|
|
wfDebug( "Article::tryFileCache(): starting buffer\n" );
|
2003-08-02 10:13:27 +00:00
|
|
|
ob_start( array(&$cache, 'saveToFileCache' ) );
|
2003-05-16 13:39:22 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
2006-07-03 16:45:51 +00:00
|
|
|
wfDebug( "Article::tryFileCache(): not cacheable\n" );
|
2003-05-16 13:39:22 +00:00
|
|
|
}
|
2008-09-25 23:02:35 +00:00
|
|
|
return false;
|
2003-05-16 13:39:22 +00:00
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2004-09-03 00:20:26 +00:00
|
|
|
/**
|
|
|
|
|
* Check if the page can be cached
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function isFileCacheable() {
|
2008-12-11 14:29:16 +00:00
|
|
|
$cacheable = false;
|
|
|
|
|
if( HTMLFileCache::useFileCache() ) {
|
|
|
|
|
$cacheable = $this->getID() && !$this->mRedirectedFrom;
|
|
|
|
|
// Extension may have reason to disable file caching on some pages.
|
|
|
|
|
if( $cacheable ) {
|
|
|
|
|
$cacheable = wfRunHooks( 'IsFileCacheable', array( &$this ) );
|
2008-09-25 23:02:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
2007-04-25 13:07:29 +00:00
|
|
|
return $cacheable;
|
2003-05-16 13:39:22 +00:00
|
|
|
}
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2004-09-03 00:20:26 +00:00
|
|
|
/**
|
2005-12-30 09:33:11 +00:00
|
|
|
* Loads page_touched and returns a value indicating if it should be used
|
2004-09-03 00:20:26 +00:00
|
|
|
*
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function checkTouched() {
|
2005-03-18 08:37:50 +00:00
|
|
|
if( !$this->mDataLoaded ) {
|
2006-03-16 02:32:30 +00:00
|
|
|
$this->loadPageData();
|
2003-11-09 11:45:12 +00:00
|
|
|
}
|
2005-03-18 08:37:50 +00:00
|
|
|
return !$this->mIsRedirect;
|
2003-11-09 11:45:12 +00:00
|
|
|
}
|
2004-05-27 15:24:04 +00:00
|
|
|
|
2005-12-30 09:33:11 +00:00
|
|
|
/**
|
|
|
|
|
* Get the page_touched field
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getTouched() {
|
2005-12-30 09:33:11 +00:00
|
|
|
# Ensure that page data has been loaded
|
|
|
|
|
if( !$this->mDataLoaded ) {
|
2006-03-16 02:32:30 +00:00
|
|
|
$this->loadPageData();
|
2005-12-30 09:33:11 +00:00
|
|
|
}
|
|
|
|
|
return $this->mTouched;
|
|
|
|
|
}
|
|
|
|
|
|
2006-03-16 02:32:30 +00:00
|
|
|
/**
|
|
|
|
|
* Get the page_latest field
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function getLatest() {
|
|
|
|
|
if( !$this->mDataLoaded ) {
|
2006-03-16 02:32:30 +00:00
|
|
|
$this->loadPageData();
|
|
|
|
|
}
|
|
|
|
|
return $this->mLatest;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-03 00:20:26 +00:00
|
|
|
/**
|
|
|
|
|
* Edit an article without doing all that other stuff
|
2005-03-12 10:50:51 +00:00
|
|
|
* The article must already exist; link tables etc
|
|
|
|
|
* are not updated, caches are not flushed.
|
2004-09-03 00:20:26 +00:00
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $text String: text submitted
|
|
|
|
|
* @param $comment String: comment submitted
|
|
|
|
|
* @param $minor Boolean: whereas it's a minor modification
|
2004-09-03 00:20:26 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function quickEdit( $text, $comment = '', $minor = 0 ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2004-06-02 13:14:40 +00:00
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2005-03-12 10:50:51 +00:00
|
|
|
$revision = new Revision( array(
|
|
|
|
|
'page' => $this->getId(),
|
|
|
|
|
'text' => $text,
|
|
|
|
|
'comment' => $comment,
|
|
|
|
|
'minor_edit' => $minor ? 1 : 0,
|
|
|
|
|
) );
|
2006-11-23 08:25:56 +00:00
|
|
|
$revision->insertOn( $dbw );
|
2005-03-13 07:49:15 +00:00
|
|
|
$this->updateRevisionOn( $dbw, $revision );
|
2008-08-08 00:01:53 +00:00
|
|
|
|
2008-11-27 18:32:29 +00:00
|
|
|
wfRunHooks( 'NewRevisionFromEditComplete', array($this, $revision, false, $wgUser) );
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2006-06-20 09:50:57 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2004-06-02 13:14:40 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-03 00:20:26 +00:00
|
|
|
/**
|
|
|
|
|
* Used to increment the view counter
|
|
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $id Integer: article id
|
2004-09-03 00:20:26 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public static function incViewCount( $id ) {
|
2003-12-13 21:32:32 +00:00
|
|
|
$id = intval( $id );
|
2006-04-12 08:15:28 +00:00
|
|
|
global $wgHitcounterUpdateFreq, $wgDBtype;
|
2004-01-17 19:59:42 +00:00
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2004-12-19 08:00:50 +00:00
|
|
|
$pageTable = $dbw->tableName( 'page' );
|
2004-07-10 03:09:26 +00:00
|
|
|
$hitcounterTable = $dbw->tableName( 'hitcounter' );
|
|
|
|
|
$acchitsTable = $dbw->tableName( 'acchits' );
|
2004-08-09 05:38:11 +00:00
|
|
|
|
2006-11-28 21:32:59 +00:00
|
|
|
if( $wgHitcounterUpdateFreq <= 1 ) {
|
2008-11-19 12:05:33 +00:00
|
|
|
$dbw->query( "UPDATE $pageTable SET page_counter = page_counter + 1 WHERE page_id = $id" );
|
2004-01-17 19:59:42 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2003-12-13 21:32:32 +00:00
|
|
|
|
|
|
|
|
# Not important enough to warrant an error page in case of failure
|
2004-08-09 05:38:11 +00:00
|
|
|
$oldignore = $dbw->ignoreErrors( true );
|
2003-12-13 21:32:32 +00:00
|
|
|
|
2004-07-10 03:09:26 +00:00
|
|
|
$dbw->query( "INSERT INTO $hitcounterTable (hc_id) VALUES ({$id})" );
|
2003-12-13 21:32:32 +00:00
|
|
|
|
2004-01-17 19:59:42 +00:00
|
|
|
$checkfreq = intval( $wgHitcounterUpdateFreq/25 + 1 );
|
2004-07-10 03:09:26 +00:00
|
|
|
if( (rand() % $checkfreq != 0) or ($dbw->lastErrno() != 0) ){
|
2003-12-13 21:32:32 +00:00
|
|
|
# Most of the time (or on SQL errors), skip row count check
|
2004-08-05 07:48:20 +00:00
|
|
|
$dbw->ignoreErrors( $oldignore );
|
2003-12-13 21:32:32 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2004-07-10 03:09:26 +00:00
|
|
|
$res = $dbw->query("SELECT COUNT(*) as n FROM $hitcounterTable");
|
|
|
|
|
$row = $dbw->fetchObject( $res );
|
2003-12-13 21:32:32 +00:00
|
|
|
$rown = intval( $row->n );
|
2004-07-08 14:53:54 +00:00
|
|
|
if( $rown >= $wgHitcounterUpdateFreq ){
|
2004-06-08 19:51:10 +00:00
|
|
|
wfProfileIn( 'Article::incViewCount-collect' );
|
2003-12-13 21:32:32 +00:00
|
|
|
$old_user_abort = ignore_user_abort( true );
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if($wgDBtype == 'mysql')
|
2006-04-12 08:15:28 +00:00
|
|
|
$dbw->query("LOCK TABLES $hitcounterTable WRITE");
|
|
|
|
|
$tabletype = $wgDBtype == 'mysql' ? "ENGINE=HEAP " : '';
|
2006-12-31 23:59:23 +00:00
|
|
|
$dbw->query("CREATE TEMPORARY TABLE $acchitsTable $tabletype AS ".
|
2004-07-10 03:09:26 +00:00
|
|
|
"SELECT hc_id,COUNT(*) AS hc_n FROM $hitcounterTable ".
|
|
|
|
|
'GROUP BY hc_id');
|
|
|
|
|
$dbw->query("DELETE FROM $hitcounterTable");
|
2008-11-28 14:29:25 +00:00
|
|
|
if($wgDBtype == 'mysql') {
|
2006-04-12 08:15:28 +00:00
|
|
|
$dbw->query('UNLOCK TABLES');
|
2006-11-28 21:32:59 +00:00
|
|
|
$dbw->query("UPDATE $pageTable,$acchitsTable SET page_counter=page_counter + hc_n ".
|
|
|
|
|
'WHERE page_id = hc_id');
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$dbw->query("UPDATE $pageTable SET page_counter=page_counter + hc_n ".
|
|
|
|
|
"FROM $acchitsTable WHERE page_id = hc_id");
|
|
|
|
|
}
|
2004-07-10 03:09:26 +00:00
|
|
|
$dbw->query("DROP TABLE $acchitsTable");
|
2003-12-13 21:32:32 +00:00
|
|
|
|
|
|
|
|
ignore_user_abort( $old_user_abort );
|
2004-06-08 19:51:10 +00:00
|
|
|
wfProfileOut( 'Article::incViewCount-collect' );
|
2003-12-13 21:32:32 +00:00
|
|
|
}
|
2004-08-05 07:48:20 +00:00
|
|
|
$dbw->ignoreErrors( $oldignore );
|
2003-12-13 21:32:32 +00:00
|
|
|
}
|
2004-01-05 23:32:39 +00:00
|
|
|
|
2004-09-03 00:20:26 +00:00
|
|
|
/**#@+
|
2004-09-02 23:28:24 +00:00
|
|
|
* The onArticle*() functions are supposed to be a kind of hooks
|
|
|
|
|
* which should be called whenever any of the specified actions
|
|
|
|
|
* are done.
|
2005-07-01 00:03:31 +00:00
|
|
|
*
|
2004-09-02 23:28:24 +00:00
|
|
|
* This is a good place to put code to clear caches, for instance.
|
2005-07-01 00:03:31 +00:00
|
|
|
*
|
2004-09-02 23:28:24 +00:00
|
|
|
* This is called on page move and undelete, as well as edit
|
2008-11-30 10:10:15 +00:00
|
|
|
*
|
|
|
|
|
* @param $title a title object
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2004-09-03 00:20:26 +00:00
|
|
|
|
2008-09-20 22:48:55 +00:00
|
|
|
public static function onArticleCreate( $title ) {
|
|
|
|
|
# Update existence markers on article/talk tabs...
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $title->isTalkPage() ) {
|
2006-06-20 09:50:57 +00:00
|
|
|
$other = $title->getSubjectPage();
|
|
|
|
|
} else {
|
|
|
|
|
$other = $title->getTalkPage();
|
|
|
|
|
}
|
|
|
|
|
$other->invalidateCache();
|
|
|
|
|
$other->purgeSquid();
|
|
|
|
|
|
2006-06-18 12:42:16 +00:00
|
|
|
$title->touchLinks();
|
|
|
|
|
$title->purgeSquid();
|
2007-12-11 09:51:56 +00:00
|
|
|
$title->deleteTitleProtection();
|
2004-01-05 23:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
2008-09-20 14:19:42 +00:00
|
|
|
public static function onArticleDelete( $title ) {
|
2008-12-28 14:19:39 +00:00
|
|
|
global $wgMessageCache;
|
2008-09-20 22:48:55 +00:00
|
|
|
# Update existence markers on article/talk tabs...
|
2008-03-25 00:14:32 +00:00
|
|
|
if( $title->isTalkPage() ) {
|
|
|
|
|
$other = $title->getSubjectPage();
|
|
|
|
|
} else {
|
|
|
|
|
$other = $title->getTalkPage();
|
|
|
|
|
}
|
|
|
|
|
$other->invalidateCache();
|
|
|
|
|
$other->purgeSquid();
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2005-10-05 01:32:55 +00:00
|
|
|
$title->touchLinks();
|
2006-06-18 12:42:16 +00:00
|
|
|
$title->purgeSquid();
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2006-06-18 12:42:16 +00:00
|
|
|
# File cache
|
2008-12-28 14:19:39 +00:00
|
|
|
HTMLFileCache::clearFileCache( $title );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2008-05-21 05:23:20 +00:00
|
|
|
# Messages
|
|
|
|
|
if( $title->getNamespace() == NS_MEDIAWIKI ) {
|
2005-10-05 01:32:55 +00:00
|
|
|
$wgMessageCache->replace( $title->getDBkey(), false );
|
|
|
|
|
}
|
2008-05-21 05:23:20 +00:00
|
|
|
# Images
|
2008-12-01 17:14:30 +00:00
|
|
|
if( $title->getNamespace() == NS_FILE ) {
|
2008-01-26 18:45:54 +00:00
|
|
|
$update = new HTMLCacheUpdate( $title, 'imagelinks' );
|
|
|
|
|
$update->doUpdate();
|
|
|
|
|
}
|
2008-05-21 05:23:20 +00:00
|
|
|
# User talk pages
|
|
|
|
|
if( $title->getNamespace() == NS_USER_TALK ) {
|
|
|
|
|
$user = User::newFromName( $title->getText(), false );
|
|
|
|
|
$user->setNewtalk( false );
|
|
|
|
|
}
|
2004-01-05 23:32:39 +00:00
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2005-12-08 01:36:33 +00:00
|
|
|
/**
|
|
|
|
|
* Purge caches on page update etc
|
|
|
|
|
*/
|
2008-10-13 06:02:32 +00:00
|
|
|
public static function onArticleEdit( $title, $transclusions = 'transclusions' ) {
|
2008-12-28 14:19:39 +00:00
|
|
|
global $wgDeferredUpdateList;
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2006-06-18 12:42:16 +00:00
|
|
|
// Invalidate caches of articles which include this page
|
2008-10-13 06:02:32 +00:00
|
|
|
if( $transclusions !== 'skiptransclusions' )
|
2008-09-20 22:48:55 +00:00
|
|
|
$wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'templatelinks' );
|
2005-12-08 01:36:33 +00:00
|
|
|
|
2008-01-17 12:31:54 +00:00
|
|
|
// Invalidate the caches of all pages which redirect here
|
|
|
|
|
$wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'redirect' );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2006-06-18 12:42:16 +00:00
|
|
|
# Purge squid for this page only
|
|
|
|
|
$title->purgeSquid();
|
2005-12-08 01:36:33 +00:00
|
|
|
|
2008-09-20 14:19:42 +00:00
|
|
|
# Clear file cache for this page only
|
2008-12-28 14:19:39 +00:00
|
|
|
HTMLFileCache::clearFileCache( $title );
|
2004-01-05 23:32:39 +00:00
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2004-09-03 00:20:26 +00:00
|
|
|
/**#@-*/
|
2004-08-12 14:27:38 +00:00
|
|
|
|
2008-03-01 15:54:07 +00:00
|
|
|
/**
|
|
|
|
|
* Overriden by ImagePage class, only present here to avoid a fatal error
|
|
|
|
|
* Called for ?action=revert
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function revert() {
|
2008-03-01 15:54:07 +00:00
|
|
|
global $wgOut;
|
|
|
|
|
$wgOut->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Info about this page
|
2005-02-28 04:52:37 +00:00
|
|
|
* Called for ?action=info when $wgAllowPageInfo is on.
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
public function info() {
|
2005-10-06 14:20:45 +00:00
|
|
|
global $wgLang, $wgOut, $wgAllowPageInfo, $wgUser;
|
2004-08-09 05:38:11 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( !$wgAllowPageInfo ) {
|
2006-06-07 06:40:24 +00:00
|
|
|
$wgOut->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
|
2004-07-09 11:42:24 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2004-08-09 05:38:11 +00:00
|
|
|
|
2005-02-28 04:52:37 +00:00
|
|
|
$page = $this->mTitle->getSubjectPage();
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2005-02-28 04:52:37 +00:00
|
|
|
$wgOut->setPagetitle( $page->getPrefixedText() );
|
2007-07-22 14:45:12 +00:00
|
|
|
$wgOut->setPageTitleActionText( wfMsg( 'info_short' ) );
|
2008-12-22 18:30:13 +00:00
|
|
|
$wgOut->setSubtitle( wfMsgHtml( 'infosubtitle' ) );
|
2007-08-01 01:23:44 +00:00
|
|
|
|
|
|
|
|
if( !$this->mTitle->exists() ) {
|
2008-11-06 22:20:29 +00:00
|
|
|
$wgOut->addHTML( '<div class="noarticletext">' );
|
2007-08-01 01:23:44 +00:00
|
|
|
if( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
|
|
|
|
|
// This doesn't quite make sense; the user is asking for
|
|
|
|
|
// information about the _page_, not the message... -- RC
|
2008-11-06 22:20:29 +00:00
|
|
|
$wgOut->addHTML( htmlspecialchars( wfMsgWeirdKey( $this->mTitle->getText() ) ) );
|
2005-12-28 14:47:30 +00:00
|
|
|
} else {
|
2007-08-01 01:23:44 +00:00
|
|
|
$msg = $wgUser->isLoggedIn()
|
|
|
|
|
? 'noarticletext'
|
|
|
|
|
: 'noarticletextanon';
|
2008-11-06 22:20:29 +00:00
|
|
|
$wgOut->addHTML( wfMsgExt( $msg, 'parse' ) );
|
2005-12-28 14:47:30 +00:00
|
|
|
}
|
2008-11-06 22:20:29 +00:00
|
|
|
$wgOut->addHTML( '</div>' );
|
2004-07-08 14:53:54 +00:00
|
|
|
} else {
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2005-02-28 04:52:37 +00:00
|
|
|
$wl_clause = array(
|
|
|
|
|
'wl_title' => $page->getDBkey(),
|
|
|
|
|
'wl_namespace' => $page->getNamespace() );
|
|
|
|
|
$numwatchers = $dbr->selectField(
|
|
|
|
|
'watchlist',
|
|
|
|
|
'COUNT(*)',
|
|
|
|
|
$wl_clause,
|
2006-06-20 09:50:57 +00:00
|
|
|
__METHOD__,
|
2004-08-20 14:59:49 +00:00
|
|
|
$this->getSelectOptions() );
|
2004-07-08 14:53:54 +00:00
|
|
|
|
2005-02-28 04:52:37 +00:00
|
|
|
$pageInfo = $this->pageCountInfo( $page );
|
|
|
|
|
$talkInfo = $this->pageCountInfo( $page->getTalkPage() );
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2005-02-28 04:52:37 +00:00
|
|
|
$wgOut->addHTML( "<ul><li>" . wfMsg("numwatchers", $wgLang->formatNum( $numwatchers ) ) . '</li>' );
|
|
|
|
|
$wgOut->addHTML( "<li>" . wfMsg('numedits', $wgLang->formatNum( $pageInfo['edits'] ) ) . '</li>');
|
|
|
|
|
if( $talkInfo ) {
|
|
|
|
|
$wgOut->addHTML( '<li>' . wfMsg("numtalkedits", $wgLang->formatNum( $talkInfo['edits'] ) ) . '</li>');
|
2004-07-08 14:53:54 +00:00
|
|
|
}
|
2005-02-28 04:52:37 +00:00
|
|
|
$wgOut->addHTML( '<li>' . wfMsg("numauthors", $wgLang->formatNum( $pageInfo['authors'] ) ) . '</li>' );
|
|
|
|
|
if( $talkInfo ) {
|
|
|
|
|
$wgOut->addHTML( '<li>' . wfMsg('numtalkauthors', $wgLang->formatNum( $talkInfo['authors'] ) ) . '</li>' );
|
2004-07-08 14:53:54 +00:00
|
|
|
}
|
2005-02-28 04:52:37 +00:00
|
|
|
$wgOut->addHTML( '</ul>' );
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-07-01 00:03:31 +00:00
|
|
|
|
2005-02-28 04:52:37 +00:00
|
|
|
/**
|
|
|
|
|
* Return the total number of edits and number of unique editors
|
|
|
|
|
* on a given page. If page does not exist, returns false.
|
|
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $title Title object
|
2005-02-28 04:52:37 +00:00
|
|
|
* @return array
|
|
|
|
|
*/
|
2008-11-28 14:29:25 +00:00
|
|
|
protected function pageCountInfo( $title ) {
|
2005-02-28 04:52:37 +00:00
|
|
|
$id = $title->getArticleId();
|
|
|
|
|
if( $id == 0 ) {
|
|
|
|
|
return false;
|
2004-07-08 14:53:54 +00:00
|
|
|
}
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2005-02-28 04:52:37 +00:00
|
|
|
$rev_clause = array( 'rev_page' => $id );
|
|
|
|
|
$edits = $dbr->selectField(
|
|
|
|
|
'revision',
|
|
|
|
|
'COUNT(rev_page)',
|
|
|
|
|
$rev_clause,
|
2006-06-20 09:50:57 +00:00
|
|
|
__METHOD__,
|
2008-11-28 14:29:25 +00:00
|
|
|
$this->getSelectOptions()
|
|
|
|
|
);
|
2005-02-28 04:52:37 +00:00
|
|
|
$authors = $dbr->selectField(
|
|
|
|
|
'revision',
|
|
|
|
|
'COUNT(DISTINCT rev_user_text)',
|
|
|
|
|
$rev_clause,
|
2006-06-20 09:50:57 +00:00
|
|
|
__METHOD__,
|
2008-11-28 14:29:25 +00:00
|
|
|
$this->getSelectOptions()
|
|
|
|
|
);
|
2005-02-28 04:52:37 +00:00
|
|
|
return array( 'edits' => $edits, 'authors' => $authors );
|
2004-07-08 14:53:54 +00:00
|
|
|
}
|
2005-04-03 07:01:29 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return a list of templates used by this article.
|
2005-12-30 09:33:11 +00:00
|
|
|
* Uses the templatelinks table
|
2005-04-03 07:01:29 +00:00
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @return Array of Title objects
|
2005-04-03 07:01:29 +00:00
|
|
|
*/
|
2008-09-20 14:19:42 +00:00
|
|
|
public function getUsedTemplates() {
|
2005-04-03 07:01:29 +00:00
|
|
|
$result = array();
|
|
|
|
|
$id = $this->mTitle->getArticleID();
|
2006-03-07 04:23:09 +00:00
|
|
|
if( $id == 0 ) {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2005-12-30 09:33:11 +00:00
|
|
|
$res = $dbr->select( array( 'templatelinks' ),
|
|
|
|
|
array( 'tl_namespace', 'tl_title' ),
|
|
|
|
|
array( 'tl_from' => $id ),
|
2008-07-25 19:36:13 +00:00
|
|
|
__METHOD__ );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $res !== false ) {
|
2008-07-27 18:59:46 +00:00
|
|
|
foreach( $res as $row ) {
|
|
|
|
|
$result[] = Title::makeTitle( $row->tl_namespace, $row->tl_title );
|
2005-04-03 07:01:29 +00:00
|
|
|
}
|
|
|
|
|
}
|
2005-12-30 09:33:11 +00:00
|
|
|
$dbr->freeResult( $res );
|
2005-04-03 07:01:29 +00:00
|
|
|
return $result;
|
|
|
|
|
}
|
2007-01-17 22:32:40 +00:00
|
|
|
|
2008-02-25 13:38:21 +00:00
|
|
|
/**
|
|
|
|
|
* Returns a list of hidden categories this page is a member of.
|
|
|
|
|
* Uses the page_props and categorylinks tables.
|
|
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @return Array of Title objects
|
2008-02-25 13:38:21 +00:00
|
|
|
*/
|
2008-09-20 14:19:42 +00:00
|
|
|
public function getHiddenCategories() {
|
2008-02-25 13:38:21 +00:00
|
|
|
$result = array();
|
|
|
|
|
$id = $this->mTitle->getArticleID();
|
|
|
|
|
if( $id == 0 ) {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
$res = $dbr->select( array( 'categorylinks', 'page_props', 'page' ),
|
|
|
|
|
array( 'cl_to' ),
|
2008-04-14 07:45:50 +00:00
|
|
|
array( 'cl_from' => $id, 'pp_page=page_id', 'pp_propname' => 'hiddencat',
|
2008-02-25 13:38:21 +00:00
|
|
|
'page_namespace' => NS_CATEGORY, 'page_title=cl_to'),
|
2008-07-25 19:36:13 +00:00
|
|
|
__METHOD__ );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $res !== false ) {
|
2008-07-27 18:59:46 +00:00
|
|
|
foreach( $res as $row ) {
|
|
|
|
|
$result[] = Title::makeTitle( NS_CATEGORY, $row->cl_to );
|
2008-02-25 13:38:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$dbr->freeResult( $res );
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
2006-11-20 11:48:03 +00:00
|
|
|
/**
|
|
|
|
|
* Return an applicable autosummary if one exists for the given edit.
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $oldtext String: the previous text of the page.
|
|
|
|
|
* @param $newtext String: The submitted text of the page.
|
|
|
|
|
* @param $flags Bitmask: a bitmask of flags submitted for the edit.
|
2006-11-20 11:48:03 +00:00
|
|
|
* @return string An appropriate autosummary, or an empty string.
|
|
|
|
|
*/
|
|
|
|
|
public static function getAutosummary( $oldtext, $newtext, $flags ) {
|
2008-05-24 14:55:54 +00:00
|
|
|
# Decide what kind of autosummary is needed.
|
2006-11-20 11:48:03 +00:00
|
|
|
|
2008-05-24 14:55:54 +00:00
|
|
|
# Redirect autosummaries
|
2008-11-08 20:36:21 +00:00
|
|
|
$ot = Title::newFromRedirect( $oldtext );
|
2008-05-24 14:55:54 +00:00
|
|
|
$rt = Title::newFromRedirect( $newtext );
|
2008-11-09 14:35:17 +00:00
|
|
|
if( is_object( $rt ) && ( !is_object( $ot ) || !$rt->equals( $ot ) || $ot->getFragment() != $rt->getFragment() ) ) {
|
2008-05-24 14:55:54 +00:00
|
|
|
return wfMsgForContent( 'autoredircomment', $rt->getFullText() );
|
|
|
|
|
}
|
2006-11-20 11:48:03 +00:00
|
|
|
|
2008-05-24 14:55:54 +00:00
|
|
|
# New page autosummaries
|
|
|
|
|
if( $flags & EDIT_NEW && strlen( $newtext ) ) {
|
|
|
|
|
# If they're making a new article, give its text, truncated, in the summary.
|
2006-11-23 09:32:28 +00:00
|
|
|
global $wgContLang;
|
2006-12-22 19:58:25 +00:00
|
|
|
$truncatedtext = $wgContLang->truncate(
|
|
|
|
|
str_replace("\n", ' ', $newtext),
|
2008-11-08 20:36:21 +00:00
|
|
|
max( 0, 200 - strlen( wfMsgForContent( 'autosumm-new' ) ) ),
|
2006-12-22 19:58:25 +00:00
|
|
|
'...' );
|
2008-05-24 14:55:54 +00:00
|
|
|
return wfMsgForContent( 'autosumm-new', $truncatedtext );
|
2006-11-23 09:32:28 +00:00
|
|
|
}
|
|
|
|
|
|
2008-05-24 14:55:54 +00:00
|
|
|
# Blanking autosummaries
|
|
|
|
|
if( $oldtext != '' && $newtext == '' ) {
|
2008-11-08 20:36:21 +00:00
|
|
|
return wfMsgForContent( 'autosumm-blank' );
|
2008-05-24 14:55:54 +00:00
|
|
|
} elseif( strlen( $oldtext ) > 10 * strlen( $newtext ) && strlen( $newtext ) < 500) {
|
|
|
|
|
# Removing more than 90% of the article
|
|
|
|
|
global $wgContLang;
|
|
|
|
|
$truncatedtext = $wgContLang->truncate(
|
|
|
|
|
$newtext,
|
|
|
|
|
max( 0, 200 - strlen( wfMsgForContent( 'autosumm-replace' ) ) ),
|
|
|
|
|
'...'
|
|
|
|
|
);
|
|
|
|
|
return wfMsgForContent( 'autosumm-replace', $truncatedtext );
|
|
|
|
|
}
|
2006-11-20 11:48:03 +00:00
|
|
|
|
2008-05-24 14:55:54 +00:00
|
|
|
# If we reach this point, there's no applicable autosummary for our case, so our
|
|
|
|
|
# autosummary is empty.
|
|
|
|
|
return '';
|
2006-11-20 11:48:03 +00:00
|
|
|
}
|
2007-01-10 23:32:38 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add the primary page-view wikitext to the output buffer
|
|
|
|
|
* Saves the text into the parser cache if possible.
|
2007-01-11 00:31:04 +00:00
|
|
|
* Updates templatelinks if it is out of date.
|
2007-01-10 23:32:38 +00:00
|
|
|
*
|
2008-11-30 10:10:15 +00:00
|
|
|
* @param $text String
|
|
|
|
|
* @param $cache Boolean
|
2007-01-10 23:32:38 +00:00
|
|
|
*/
|
|
|
|
|
public function outputWikiText( $text, $cache = true ) {
|
2008-09-25 23:02:35 +00:00
|
|
|
global $wgParser, $wgUser, $wgOut, $wgEnableParserCache, $wgUseFileCache;
|
2007-01-10 23:32:38 +00:00
|
|
|
|
|
|
|
|
$popts = $wgOut->parserOptions();
|
|
|
|
|
$popts->setTidy(true);
|
2007-11-30 16:57:02 +00:00
|
|
|
$popts->enableLimitReport();
|
2007-01-11 00:31:04 +00:00
|
|
|
$parserOutput = $wgParser->parse( $text, $this->mTitle,
|
|
|
|
|
$popts, true, true, $this->getRevIdFetched() );
|
2007-01-10 23:32:38 +00:00
|
|
|
$popts->setTidy(false);
|
2007-11-30 16:57:02 +00:00
|
|
|
$popts->enableLimitReport( false );
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $wgEnableParserCache && $cache && $this && $parserOutput->getCacheTime() != -1 ) {
|
2008-04-09 18:23:34 +00:00
|
|
|
$parserCache = ParserCache::singleton();
|
2007-01-11 00:44:55 +00:00
|
|
|
$parserCache->save( $parserOutput, $this, $wgUser );
|
2007-01-10 23:32:38 +00:00
|
|
|
}
|
2008-09-25 23:02:35 +00:00
|
|
|
// Make sure file cache is not used on uncacheable content.
|
2008-09-26 13:55:42 +00:00
|
|
|
// Output that has magic words in it can still use the parser cache
|
|
|
|
|
// (if enabled), though it will generally expire sooner.
|
|
|
|
|
if( $parserOutput->getCacheTime() == -1 || $parserOutput->containsOldMagic() ) {
|
2008-09-25 23:02:35 +00:00
|
|
|
$wgUseFileCache = false;
|
|
|
|
|
}
|
2007-01-10 23:32:38 +00:00
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $this->isCurrent() && !wfReadOnly() && $this->mTitle->areRestrictionsCascading() ) {
|
2007-01-14 10:55:23 +00:00
|
|
|
// templatelinks table may have become out of sync,
|
|
|
|
|
// especially if using variable-based transclusions.
|
|
|
|
|
// For paranoia, check if things have changed and if
|
|
|
|
|
// so apply updates to the database. This will ensure
|
|
|
|
|
// that cascaded protections apply as soon as the changes
|
|
|
|
|
// are visible.
|
2007-01-10 23:32:38 +00:00
|
|
|
|
|
|
|
|
# Get templates from templatelinks
|
2007-01-11 00:31:04 +00:00
|
|
|
$id = $this->mTitle->getArticleID();
|
|
|
|
|
|
2007-01-11 00:52:50 +00:00
|
|
|
$tlTemplates = array();
|
2007-01-10 23:32:38 +00:00
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2007-01-11 00:31:04 +00:00
|
|
|
$res = $dbr->select( array( 'templatelinks' ),
|
|
|
|
|
array( 'tl_namespace', 'tl_title' ),
|
|
|
|
|
array( 'tl_from' => $id ),
|
2008-07-25 19:36:13 +00:00
|
|
|
__METHOD__ );
|
2007-01-11 00:31:04 +00:00
|
|
|
|
2007-01-11 00:44:55 +00:00
|
|
|
global $wgContLang;
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $res !== false ) {
|
2008-07-27 18:59:46 +00:00
|
|
|
foreach( $res as $row ) {
|
|
|
|
|
$tlTemplates[] = $wgContLang->getNsText( $row->tl_namespace ) . ':' . $row->tl_title ;
|
2007-01-11 00:31:04 +00:00
|
|
|
}
|
2007-01-10 23:32:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Get templates from parser output.
|
|
|
|
|
$poTemplates_allns = $parserOutput->getTemplates();
|
|
|
|
|
|
|
|
|
|
$poTemplates = array ();
|
|
|
|
|
foreach ( $poTemplates_allns as $ns_templates ) {
|
|
|
|
|
$poTemplates = array_merge( $poTemplates, $ns_templates );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Get the diff
|
|
|
|
|
$templates_diff = array_diff( $poTemplates, $tlTemplates );
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( count( $templates_diff ) > 0 ) {
|
2007-01-10 23:32:38 +00:00
|
|
|
# Whee, link updates time.
|
|
|
|
|
$u = new LinksUpdate( $this->mTitle, $parserOutput );
|
|
|
|
|
$u->doUpdate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$wgOut->addParserOutput( $parserOutput );
|
|
|
|
|
}
|
|
|
|
|
|
This is a schema change. It's only a table creation, but the table must be created on Wikimedia servers before this revision goes live. The maintenance script populateCategory.php should be run when convenient. If it's not run, there's only one substantial case where display will be harmed: the page of a category with more than 200 net pages added since the patch goes live will give an erroneously low count. In other cases category pages will just be better-worded, and it will recognize the count in the table is bogus.
* Adds Category and CategoryList classes to represent categories themselves.
* Adds a category table, giving each category a name, ID, and counts of all members, subcats only, and files.
* Adds a maintenance script to populate the category table efficiently. This script is careful to wait for slaves and should be safe to run on a live database. The maintenance script's includes file is called by update.php.
* Until the category table is populated, the patch handles weird category table rows gracefully. It detects whether they're obviously impossible, and if so, it outputs appropriate messages.
2008-03-18 00:17:28 +00:00
|
|
|
/**
|
|
|
|
|
* Update all the appropriate counts in the category table, given that
|
|
|
|
|
* we've added the categories $added and deleted the categories $deleted.
|
|
|
|
|
*
|
|
|
|
|
* @param $added array The names of categories that were added
|
|
|
|
|
* @param $deleted array The names of categories that were deleted
|
|
|
|
|
* @return null
|
|
|
|
|
*/
|
2008-03-19 13:36:33 +00:00
|
|
|
public function updateCategoryCounts( $added, $deleted ) {
|
This is a schema change. It's only a table creation, but the table must be created on Wikimedia servers before this revision goes live. The maintenance script populateCategory.php should be run when convenient. If it's not run, there's only one substantial case where display will be harmed: the page of a category with more than 200 net pages added since the patch goes live will give an erroneously low count. In other cases category pages will just be better-worded, and it will recognize the count in the table is bogus.
* Adds Category and CategoryList classes to represent categories themselves.
* Adds a category table, giving each category a name, ID, and counts of all members, subcats only, and files.
* Adds a maintenance script to populate the category table efficiently. This script is careful to wait for slaves and should be safe to run on a live database. The maintenance script's includes file is called by update.php.
* Until the category table is populated, the patch handles weird category table rows gracefully. It detects whether they're obviously impossible, and if so, it outputs appropriate messages.
2008-03-18 00:17:28 +00:00
|
|
|
$ns = $this->mTitle->getNamespace();
|
2008-03-19 13:36:33 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
This is a schema change. It's only a table creation, but the table must be created on Wikimedia servers before this revision goes live. The maintenance script populateCategory.php should be run when convenient. If it's not run, there's only one substantial case where display will be harmed: the page of a category with more than 200 net pages added since the patch goes live will give an erroneously low count. In other cases category pages will just be better-worded, and it will recognize the count in the table is bogus.
* Adds Category and CategoryList classes to represent categories themselves.
* Adds a category table, giving each category a name, ID, and counts of all members, subcats only, and files.
* Adds a maintenance script to populate the category table efficiently. This script is careful to wait for slaves and should be safe to run on a live database. The maintenance script's includes file is called by update.php.
* Until the category table is populated, the patch handles weird category table rows gracefully. It detects whether they're obviously impossible, and if so, it outputs appropriate messages.
2008-03-18 00:17:28 +00:00
|
|
|
|
|
|
|
|
# First make sure the rows exist. If one of the "deleted" ones didn't
|
|
|
|
|
# exist, we might legitimately not create it, but it's simpler to just
|
|
|
|
|
# create it and then give it a negative value, since the value is bogus
|
|
|
|
|
# anyway.
|
|
|
|
|
#
|
|
|
|
|
# Sometimes I wish we had INSERT ... ON DUPLICATE KEY UPDATE.
|
|
|
|
|
$insertCats = array_merge( $added, $deleted );
|
2008-03-20 17:33:32 +00:00
|
|
|
if( !$insertCats ) {
|
|
|
|
|
# Okay, nothing to do
|
|
|
|
|
return;
|
|
|
|
|
}
|
This is a schema change. It's only a table creation, but the table must be created on Wikimedia servers before this revision goes live. The maintenance script populateCategory.php should be run when convenient. If it's not run, there's only one substantial case where display will be harmed: the page of a category with more than 200 net pages added since the patch goes live will give an erroneously low count. In other cases category pages will just be better-worded, and it will recognize the count in the table is bogus.
* Adds Category and CategoryList classes to represent categories themselves.
* Adds a category table, giving each category a name, ID, and counts of all members, subcats only, and files.
* Adds a maintenance script to populate the category table efficiently. This script is careful to wait for slaves and should be safe to run on a live database. The maintenance script's includes file is called by update.php.
* Until the category table is populated, the patch handles weird category table rows gracefully. It detects whether they're obviously impossible, and if so, it outputs appropriate messages.
2008-03-18 00:17:28 +00:00
|
|
|
$insertRows = array();
|
|
|
|
|
foreach( $insertCats as $cat ) {
|
2008-03-19 11:19:00 +00:00
|
|
|
$insertRows[] = array( 'cat_title' => $cat );
|
This is a schema change. It's only a table creation, but the table must be created on Wikimedia servers before this revision goes live. The maintenance script populateCategory.php should be run when convenient. If it's not run, there's only one substantial case where display will be harmed: the page of a category with more than 200 net pages added since the patch goes live will give an erroneously low count. In other cases category pages will just be better-worded, and it will recognize the count in the table is bogus.
* Adds Category and CategoryList classes to represent categories themselves.
* Adds a category table, giving each category a name, ID, and counts of all members, subcats only, and files.
* Adds a maintenance script to populate the category table efficiently. This script is careful to wait for slaves and should be safe to run on a live database. The maintenance script's includes file is called by update.php.
* Until the category table is populated, the patch handles weird category table rows gracefully. It detects whether they're obviously impossible, and if so, it outputs appropriate messages.
2008-03-18 00:17:28 +00:00
|
|
|
}
|
2008-03-21 02:16:28 +00:00
|
|
|
$dbw->insert( 'category', $insertRows, __METHOD__, 'IGNORE' );
|
This is a schema change. It's only a table creation, but the table must be created on Wikimedia servers before this revision goes live. The maintenance script populateCategory.php should be run when convenient. If it's not run, there's only one substantial case where display will be harmed: the page of a category with more than 200 net pages added since the patch goes live will give an erroneously low count. In other cases category pages will just be better-worded, and it will recognize the count in the table is bogus.
* Adds Category and CategoryList classes to represent categories themselves.
* Adds a category table, giving each category a name, ID, and counts of all members, subcats only, and files.
* Adds a maintenance script to populate the category table efficiently. This script is careful to wait for slaves and should be safe to run on a live database. The maintenance script's includes file is called by update.php.
* Until the category table is populated, the patch handles weird category table rows gracefully. It detects whether they're obviously impossible, and if so, it outputs appropriate messages.
2008-03-18 00:17:28 +00:00
|
|
|
|
|
|
|
|
$addFields = array( 'cat_pages = cat_pages + 1' );
|
|
|
|
|
$removeFields = array( 'cat_pages = cat_pages - 1' );
|
|
|
|
|
if( $ns == NS_CATEGORY ) {
|
2008-03-19 11:19:00 +00:00
|
|
|
$addFields[] = 'cat_subcats = cat_subcats + 1';
|
|
|
|
|
$removeFields[] = 'cat_subcats = cat_subcats - 1';
|
2008-12-01 17:14:30 +00:00
|
|
|
} elseif( $ns == NS_FILE ) {
|
2008-03-19 11:19:00 +00:00
|
|
|
$addFields[] = 'cat_files = cat_files + 1';
|
|
|
|
|
$removeFields[] = 'cat_files = cat_files - 1';
|
This is a schema change. It's only a table creation, but the table must be created on Wikimedia servers before this revision goes live. The maintenance script populateCategory.php should be run when convenient. If it's not run, there's only one substantial case where display will be harmed: the page of a category with more than 200 net pages added since the patch goes live will give an erroneously low count. In other cases category pages will just be better-worded, and it will recognize the count in the table is bogus.
* Adds Category and CategoryList classes to represent categories themselves.
* Adds a category table, giving each category a name, ID, and counts of all members, subcats only, and files.
* Adds a maintenance script to populate the category table efficiently. This script is careful to wait for slaves and should be safe to run on a live database. The maintenance script's includes file is called by update.php.
* Until the category table is populated, the patch handles weird category table rows gracefully. It detects whether they're obviously impossible, and if so, it outputs appropriate messages.
2008-03-18 00:17:28 +00:00
|
|
|
}
|
|
|
|
|
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $added ) {
|
2008-03-19 11:19:00 +00:00
|
|
|
$dbw->update(
|
|
|
|
|
'category',
|
|
|
|
|
$addFields,
|
|
|
|
|
array( 'cat_title' => $added ),
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
|
|
|
|
}
|
2008-11-28 14:29:25 +00:00
|
|
|
if( $deleted ) {
|
2008-03-19 11:19:00 +00:00
|
|
|
$dbw->update(
|
|
|
|
|
'category',
|
|
|
|
|
$removeFields,
|
|
|
|
|
array( 'cat_title' => $deleted ),
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
|
|
|
|
}
|
This is a schema change. It's only a table creation, but the table must be created on Wikimedia servers before this revision goes live. The maintenance script populateCategory.php should be run when convenient. If it's not run, there's only one substantial case where display will be harmed: the page of a category with more than 200 net pages added since the patch goes live will give an erroneously low count. In other cases category pages will just be better-worded, and it will recognize the count in the table is bogus.
* Adds Category and CategoryList classes to represent categories themselves.
* Adds a category table, giving each category a name, ID, and counts of all members, subcats only, and files.
* Adds a maintenance script to populate the category table efficiently. This script is careful to wait for slaves and should be safe to run on a live database. The maintenance script's includes file is called by update.php.
* Until the category table is populated, the patch handles weird category table rows gracefully. It detects whether they're obviously impossible, and if so, it outputs appropriate messages.
2008-03-18 00:17:28 +00:00
|
|
|
}
|
2007-07-22 14:45:12 +00:00
|
|
|
}
|