(bug 56849) Deprecate dangerous edittime-based content update functions

Existing edit conflict logic relies on second-resolution timestamps,
which can fail in many exciting ways.  This patch provides new support
functions which take an explicit revision ID instead of a timestamp.

No functionality is changed.  Hopefully.

TODO:
* Make use of this code by replacing all edittime and starttime logic
with an explicit baseRevId.

Change-Id: I83cdd4adaaa67f81e933654228eccdc9fcdf9009
This commit is contained in:
Adam Roses Wight 2014-05-18 14:26:17 -07:00 committed by IAlex
parent 262a7e2d58
commit 2521f8b5b9
3 changed files with 56 additions and 2 deletions

View file

@ -1731,6 +1731,7 @@ class Revision implements IDBAccessObject {
* 50 revisions for the sake of performance.
*
* @since 1.20
* @deprecated since 1.24
*
* @param DatabaseBase|int $db The Database to perform the check on. May be given as a
* Database object or a database identifier usable with wfGetDB.

View file

@ -1387,6 +1387,8 @@ class WikiPage implements Page, IDBAccessObject {
* If the given revision is newer than the currently set page_latest,
* update the page record. Otherwise, do nothing.
*
* @deprecated since 1.24, use updateRevisionOn instead
*
* @param DatabaseBase $dbw
* @param Revision $revision
* @return bool
@ -1528,11 +1530,45 @@ class WikiPage implements Page, IDBAccessObject {
* @return Content New complete article content, or null if error.
*
* @since 1.21
* @deprecated since 1.24, use replaceSectionAtRev instead
*/
public function replaceSectionContent( $section, Content $sectionContent, $sectionTitle = '',
$edittime = null ) {
wfProfileIn( __METHOD__ );
$baseRevId = null;
if ( $edittime && $section !== 'new' ) {
$dbw = wfGetDB( DB_MASTER );
$rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime );
if ( !$rev ) {
wfDebug( __METHOD__ . " given bad revision time for page " .
$this->getId() . "; edittime: $edittime)\n" );
wfProfileOut( __METHOD__ );
return null;
}
$baseRevId = $rev->getId();
}
wfProfileOut( __METHOD__ );
return $this->replaceSectionAtRev( $section, $sectionContent, $sectionTitle, $baseRevId );
}
/**
* @param string|null|bool $section Null/false, a section number (0, 1, 2, T1, T2, ...) or "new".
* @param Content $sectionContent New content of the section.
* @param string $sectionTitle New section's subject, only if $section is "new".
* @param string $baseRevId integer|null
*
* @throws MWException
* @return Content New complete article content, or null if error.
*
* @since 1.24
*/
public function replaceSectionAtRev( $section, Content $sectionContent,
$sectionTitle = '', $baseRevId = null
) {
wfProfileIn( __METHOD__ );
if ( strval( $section ) == '' ) {
// Whole-page edit; let the whole text through
$newContent = $sectionContent;
@ -1544,11 +1580,12 @@ class WikiPage implements Page, IDBAccessObject {
}
// Bug 30711: always use current version when adding a new section
if ( is_null( $edittime ) || $section == 'new' ) {
if ( is_null( $baseRevId ) || $section == 'new' ) {
$oldContent = $this->getContent();
} else {
// TODO: try DB_READ first
$dbw = wfGetDB( DB_MASTER );
$rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime );
$rev = Revision::loadFromId( $dbw, $baseRevId );
if ( !$rev ) {
wfDebug( "WikiPage::replaceSection asked for bogus section (page: " .

View file

@ -817,6 +817,22 @@ more stuff
$this->assertEquals( $expected, is_null( $c ) ? null : trim( $c->getNativeData() ) );
}
/**
* @dataProvider dataReplaceSection
* @covers WikiPage::replaceSectionAtRev
*/
public function testReplaceSectionAtRev( $title, $model, $text, $section,
$with, $sectionTitle, $expected
) {
$page = $this->createPage( $title, $text, $model );
$baseRevId = $page->getLatest();
$content = ContentHandler::makeContent( $with, $page->getTitle(), $page->getContentModel() );
$c = $page->replaceSectionAtRev( $section, $content, $sectionTitle, $baseRevId );
$this->assertEquals( $expected, is_null( $c ) ? null : trim( $c->getNativeData() ) );
}
/* @todo FIXME: fix this!
public function testGetUndoText() {
$this->checkHasDiff3();