From c4ff922e64d8418693d248e23e82eb5ea2c4fbcc Mon Sep 17 00:00:00 2001 From: daniel Date: Thu, 30 Aug 2012 19:17:14 +0200 Subject: [PATCH] Make userWasLastToEdit reusable. Make userWasLastToEdit a static method in the Revision class, so it can be reused by extensions, etc. Change-Id: Ib44423c3544dabab3be7fe6eb675315f2480838e --- includes/EditPage.php | 31 +----- includes/Revision.php | 40 +++++++- .../phpunit/includes/RevisionStorageTest.php | 99 +++++++++++++++++++ 3 files changed, 139 insertions(+), 31 deletions(-) diff --git a/includes/EditPage.php b/includes/EditPage.php index f9bba19040..0c232fb26c 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -1295,7 +1295,7 @@ class EditPage { $this->isConflict = false; wfDebug( __METHOD__ . ": conflict suppressed; new section\n" ); } - } elseif ( $this->section == '' && $this->userWasLastToEdit( $wgUser->getId(), $this->edittime ) ) { + } elseif ( $this->section == '' && Revision::userWasLastToEdit( DB_MASTER, $this->mTitle->getArticleID(), $wgUser->getId(), $this->edittime ) ) { # Suppress edit conflict with self, except for section edits where merging is required. wfDebug( __METHOD__ . ": Suppressing edit conflict, same user.\n" ); $this->isConflict = false; @@ -1489,35 +1489,6 @@ class EditPage { } } - /** - * Check if no edits were made by other users since - * the time a user started editing the page. Limit to - * 50 revisions for the sake of performance. - * - * @param $id int - * @param $edittime string - * - * @return bool - */ - protected function userWasLastToEdit( $id, $edittime ) { - if ( !$id ) return false; - $dbw = wfGetDB( DB_MASTER ); - $res = $dbw->select( 'revision', - 'rev_user', - array( - 'rev_page' => $this->mTitle->getArticleID(), - 'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $edittime ) ) - ), - __METHOD__, - array( 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 50 ) ); - foreach ( $res as $row ) { - if ( $row->rev_user != $id ) { - return false; - } - } - return true; - } - /** * @private * @todo document diff --git a/includes/Revision.php b/includes/Revision.php index 9da031e3a5..20cc8f5862 100644 --- a/includes/Revision.php +++ b/includes/Revision.php @@ -1290,4 +1290,42 @@ class Revision implements IDBAccessObject { } return 0; } -} + + /** + * Check if no edits were made by other users since + * the time a user started editing the page. Limit to + * 50 revisions for the sake of performance. + * + * @since 1.20 + * + * @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. + * @param int $pageId the ID of the page in question + * @param int $userId the ID of the user in question + * @param string $since look at edits since this time + * + * @return bool True if the given user was the only one to edit since the given timestamp + */ + public static function userWasLastToEdit( $db, $pageId, $userId, $since ) { + if ( !$userId ) return false; + + if ( is_int( $db ) ) { + $db = wfGetDB( $db ); + } + + $res = $db->select( 'revision', + 'rev_user', + array( + 'rev_page' => $pageId, + 'rev_timestamp > ' . $db->addQuotes( $db->timestamp( $since ) ) + ), + __METHOD__, + array( 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 50 ) ); + foreach ( $res as $row ) { + if ( $row->rev_user != $userId ) { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/tests/phpunit/includes/RevisionStorageTest.php b/tests/phpunit/includes/RevisionStorageTest.php index 6d82d0c99b..8a7facece4 100644 --- a/tests/phpunit/includes/RevisionStorageTest.php +++ b/tests/phpunit/includes/RevisionStorageTest.php @@ -5,6 +5,9 @@ * * @group Database * ^--- important, causes temporary tables to be used instead of the real database + * + * @group medium + * ^--- important, causes tests not to fail with timeout */ class RevisionStorageTest extends MediaWikiTestCase { @@ -306,4 +309,100 @@ class RevisionStorageTest extends MediaWikiTestCase { $this->assertEquals( $orig->getTextId(), $rev->getTextId(), 'new null revision shold have the same text id as the original revision' ); $this->assertEquals( 'some testing text', $rev->getText() ); } + + public function dataUserWasLastToEdit() { + return array( + array( #0 + 3, true, # actually the last edit + ), + array( #1 + 2, true, # not the current edit, but still by this user + ), + array( #2 + 1, false, # edit by another user + ), + array( #3 + 0, false, # first edit, by this user, but another user edited in the mean time + ), + ); + } + + /** + * @dataProvider dataUserWasLastToEdit + */ + public function testUserWasLastToEdit( $sinceIdx, $expectedLast ) { + $userA = \User::newFromName( "RevisionStorageTest_userA" ); + $userB = \User::newFromName( "RevisionStorageTest_userB" ); + + if ( $userA->getId() === 0 ) { + $userA = \User::createNew( $userA->getName() ); + } + + if ( $userB->getId() === 0 ) { + $userB = \User::createNew( $userB->getName() ); + } + + $dbw = wfGetDB( DB_MASTER ); + $revisions = array(); + + // create revisions ----------------------------- + $page = WikiPage::factory( Title::newFromText( 'RevisionStorageTest_testUserWasLastToEdit' ) ); + + # zero + $revisions[0] = new Revision( array( + 'page' => $page->getId(), + 'timestamp' => '20120101000000', + 'user' => $userA->getId(), + 'text' => 'zero', + 'summary' => 'edit zero' + ) ); + $revisions[0]->insertOn( $dbw ); + + # one + $revisions[1] = new Revision( array( + 'page' => $page->getId(), + 'timestamp' => '20120101000100', + 'user' => $userA->getId(), + 'text' => 'one', + 'summary' => 'edit one' + ) ); + $revisions[1]->insertOn( $dbw ); + + # two + $revisions[2] = new Revision( array( + 'page' => $page->getId(), + 'timestamp' => '20120101000200', + 'user' => $userB->getId(), + 'text' => 'two', + 'summary' => 'edit two' + ) ); + $revisions[2]->insertOn( $dbw ); + + # three + $revisions[3] = new Revision( array( + 'page' => $page->getId(), + 'timestamp' => '20120101000300', + 'user' => $userA->getId(), + 'text' => 'three', + 'summary' => 'edit three' + ) ); + $revisions[3]->insertOn( $dbw ); + + # four + $revisions[4] = new Revision( array( + 'page' => $page->getId(), + 'timestamp' => '20120101000200', + 'user' => $userA->getId(), + 'text' => 'zero', + 'summary' => 'edit four' + ) ); + $revisions[4]->insertOn( $dbw ); + + // test it --------------------------------- + $since = $revisions[ $sinceIdx ]->getTimestamp(); + + $wasLast = Revision::userWasLastToEdit( $dbw, $page->getId(), $userA->getId(), $since ); + + $this->assertEquals( $expectedLast, $wasLast ); + } } -- 2.20.1