diff --git a/PubSubHubbubSubscriber.php b/PubSubHubbubSubscriber.php index 093afa1..c0ffdb6 100644 --- a/PubSubHubbubSubscriber.php +++ b/PubSubHubbubSubscriber.php @@ -53,8 +53,10 @@ $wgAutoloadClasses['PubSubHubbubSubscriber\\Subscription'] = $dir . 'src/Subscription.php'; $wgAutoloadClasses['PubSubHubbubSubscriber\\SubscriptionHandler'] = $dir . 'src/SubscriptionHandler.php'; $wgAutoloadClasses['PubSubHubbubSubscriber\\SubscriberClient'] = $dir . 'src/SubscriberClient.php'; +$wgAutoloadClasses['PubSubHubbubSubscriber\\ImportCallbacks'] = $dir . 'src/ImportCallbacks.php'; $wgAPIModules['pushcallback'] = 'PubSubHubbubSubscriber\\ApiSubscription'; $wgHooks['LoadExtensionSchemaUpdates'][] = 'PubSubHubbubSubscriber\\HookHandler::onLoadExtensionSchemaUpdates'; $wgHooks['UnitTestsList'][] = 'PubSubHubbubSubscriber\\HookHandler::onUnitTestsList'; + diff --git a/src/HookHandler.php b/src/HookHandler.php index 52ef0ef..88fdd42 100644 --- a/src/HookHandler.php +++ b/src/HookHandler.php @@ -3,6 +3,7 @@ namespace PubSubHubbubSubscriber; use DatabaseUpdater; +use WikiImporter; class HookHandler { @@ -37,5 +38,4 @@ public static function onUnitTestsList( &$files ) { $files = array_merge( $files, glob( __DIR__ . '/../tests/phpunit/*Test.php' ) ); return true; } - } diff --git a/src/ImportCallbacks.php b/src/ImportCallbacks.php new file mode 100644 index 0000000..2fba721 --- /dev/null +++ b/src/ImportCallbacks.php @@ -0,0 +1,91 @@ +previousPageOutCallback = $previousPageOutCallback; + } + + /** + * @param WikiRevision $revision + */ + public function deletionPage( WikiRevision $revision ) { + if ( $revision->getAction() != 'delete' ){ + return; + } + $username = $revision->getUser(); + if ( !empty( $username ) ) { + $user = User::newFromName( $username ); + } + else { + $user = null; + } + $error = array(); + $title = $revision->getTitle(); + $wikipage = new WikiPage( $title ); + $wikipage->doDeleteArticle( $revision->getComment(), false, 0, true, $error, $user ); + } + + /** + * @param Title $title + * @param $origTitle + * @param $revCount + * @param $sucCount + * @param $pageInfo + * @return bool + */ + function callOriginalPageOutCallback( Title $title, $origTitle, $revCount, $sucCount, $pageInfo ) { + if ( is_callable( $this->previousPageOutCallback) ) { + call_user_func_array( $this->previousPageOutCallback, func_get_args() ); + } + return true; + } + + /** + * @param Title $title + * @param $origTitle + * @param $revCount + * @param $sucCount + * @param $pageInfo + */ + public function createRedirect( Title $title, $origTitle, $revCount, $sucCount, $pageInfo ) { + if ( !array_key_exists( 'redirect', $pageInfo ) || $pageInfo['redirect'] == "" || $sucCount < 1 ) { + $this->callOriginalPageOutCallback( $title, $origTitle, $revCount, $sucCount, $pageInfo ); + return; + } + + $wikipage = new WikiPage( $title ); + $redirectTitle = Title::newFromText( $pageInfo['redirect'] ); + if ( $redirectTitle->exists() ){ + $this->callOriginalPageOutCallback( $title, $origTitle, $revCount, $sucCount, $pageInfo ); + return; + } + + $dbw = wfGetDB( DB_MASTER ); + $pageId = $wikipage->getId(); + $currentRevision = $wikipage->getRevision(); + $contentRevision = $currentRevision->getPrevious(); + $currentRevisionID = $currentRevision->getId(); + $contentRevisionID = $contentRevision->getId(); + + $dbw->delete( 'revision', array( 'rev_id' => $currentRevisionID ) ); + $dbw->update( 'page', array( 'page_latest' => $contentRevisionID ), array( 'page_id' => $pageId ) ); + $title->moveTo( $redirectTitle, false ); + + $this->callOriginalPageOutCallback( $title, $origTitle, $revCount, $sucCount, $pageInfo ); + } +} diff --git a/src/SubscriptionHandler.php b/src/SubscriptionHandler.php index c93ad72..a062a06 100644 --- a/src/SubscriptionHandler.php +++ b/src/SubscriptionHandler.php @@ -30,8 +30,11 @@ public function handlePush( $topic, $hmacSignature, $file = "php://input" ) { // Still need to return success according to specification. return true; } - + $callbacks = new ImportCallbacks(); $importer = new WikiImporter( $source->value ); + $importer->setLogItemCallback( array( &$callbacks, 'deletionPage' ) ); + $callbacks->setPreviousPageOutCallback( $importer->setPageOutCallback( + array( &$callbacks, 'createRedirect' ) ) ); $importer->doImport(); return true; } else { diff --git a/tests/phpunit/ImportCallbacksTest.php b/tests/phpunit/ImportCallbacksTest.php new file mode 100644 index 0000000..90cb846 --- /dev/null +++ b/tests/phpunit/ImportCallbacksTest.php @@ -0,0 +1,292 @@ + + */ +class ImportCallbacksTest extends MediaWikiLangTestCase { + /** + * @var ImportCallbacks $mImportCallbacks; + */ + private $mImportCallbacks; + + protected function setUp() { + parent::setUp(); + $this->mImportCallbacks = new ImportCallbacks(); + $this->addDBData(); + } + + protected function tearDown() { + parent::tearDown(); + } + + /** + * @dataProvider getDeletionRevision + */ + public function testDeletionPage( WikiRevision $revision ) { + $wikiPage = new WikiPage( $revision->getTitle() ); + $this->mImportCallbacks->deletionPage( $revision ); + $this->assertFalse( $wikiPage->exists() ); + } + + /** + * @dataProvider getNoDeletionRevision + */ + public function testDeletionPageNoDelete( WikiRevision $revision ) { + $wikiPage = new WikiPage( $revision->getTitle() ); + $this->mImportCallbacks->deletionPage( $revision ); + $this->assertTrue( $wikiPage->exists() ); + } + + /** + * @dataProvider getNoRedirectData + * + * @param Title $title + * @param $origTitle + * @param $revCount + * @param $sucCount + * @param $pageInfo + */ + public function testCreateRedirectNoRedirect( Title $title, $origTitle, $revCount, $sucCount, $pageInfo ) { + $this->mImportCallbacks->createRedirect( $title, $origTitle, $revCount, $sucCount, $pageInfo ); + + $originalTitle = Title::newFromText( 'TestPage' ); + $originalPage = WikiPage::factory( $originalTitle ); + $redirectTitle = Title::newFromText( 'Redirect TestPage' ); + $redirectPage = WikiPage::factory( $redirectTitle ); + + $this->assertFalse( $redirectPage->exists() ); + + $text = $originalPage->getContent()->getNativeData(); + $this->assertEquals( "TestPage content", $text ); + } + + /** + * @dataProvider getRedirectExistsData + * + * @param Title $title + * @param $origTitle + * @param $revCount + * @param $sucCount + * @param $pageInfo + */ + public function testCreateRedirectExists( Title $title, $origTitle, $revCount, $sucCount, $pageInfo ) { + $this->insertWikipage( 'Existing Page', 'Existing Page content', 'Existing Page comment' ); + $this->mImportCallbacks->createRedirect( $title, $origTitle, $revCount, $sucCount, $pageInfo ); + + $originalTitle = Title::newFromText( 'TestPage' ); + $originalPage = WikiPage::factory( $originalTitle ); + $redirectTitle = Title::newFromText( 'Existing Page' ); + $redirectPage = WikiPage::factory( $redirectTitle ); + + $text = $redirectPage->getContent()->getNativeData(); + $this->assertEquals( "Existing Page content", $text ); + + $text =$originalPage->getContent()->getNativeData(); + $this->assertEquals( "TestPage content", $text ); + } + + /** + * @dataProvider getRedirectSuccessful + * + * @param Title $title + * @param $origTitle + * @param $revCount + * @param $sucCount + * @param $pageInfo + */ + public function testCreateRedirectSuccessful( Title $title, $origTitle, $revCount, $sucCount, $pageInfo ) { + $originalTitle = Title::newFromText( 'TestPage' ); + $originalPage = WikiPage::factory( $originalTitle ); + $content = new WikitextContent( '#REDIRECT [[Redirect TestPage]]' ); + $originalPage->doEditContent( $content, '' ); + + $this->mImportCallbacks->createRedirect( $title, $origTitle, $revCount, $sucCount, $pageInfo ); + + $redirectTitle = Title::newFromText( 'Redirect TestPage' ); + $redirectPage = WikiPage::factory( $redirectTitle ); + + $this->assertTrue( $redirectPage->exists() ); + + $text = $redirectPage->getContent()->getNativeData(); + $this->assertEquals( "TestPage content", $text ); + + $text =$originalPage->getContent()->getNativeData(); + $this->assertEquals( "#REDIRECT [[Redirect TestPage]]", $text ); + } + + /** + * @dataProvider getRedirectSuccessful + * + * @param Title $title + * @param $origTitle + * @param $revCount + * @param $sucCount + * @param $pageInfo + */ + public function testCallOriginalPageOutCallbackNull( Title $title, $origTitle, $revCount, $sucCount, $pageInfo ) { + $success = $this->mImportCallbacks->callOriginalPageOutCallback( $title, $origTitle, $revCount, $sucCount, + $pageInfo ); + $this->assertTrue( $success ); + } + + /** + * @dataProvider getRedirectSuccessful + * + * @param Title $title + * @param $origTitle + * @param $revCount + * @param $sucCount + * @param $pageInfo + */ + public function testCallOriginalPageOutCallback( Title $title, $origTitle, $revCount, $sucCount, $pageInfo ) { + $mock = $this->getMock( 'OriginalCallbackClass', array( 'callback' ) ); + $mock->expects( $this->once() ) + ->method( 'callback' ); + $previousPageOutCallback = array( &$mock, 'callback' ); + $this->mImportCallbacks->setPreviousPageOutCallback( $previousPageOutCallback ); + $success = $this->mImportCallbacks->callOriginalPageOutCallback( $title, $origTitle, $revCount, $sucCount, + $pageInfo ); + $this->assertTrue( $success ); + + } + + public function addDBData() { + $this->insertUser( 'TestUser' ); + $this->insertWikipage( 'TestPage', 'TestPage content', 'TestPage comment' ); + } + + /** + * @param string $userName + */ + private function insertUser( $userName ) { + $user = User::newFromName( $userName ); + $user->addToDatabase(); + } + + /** + * @param string $titleName + * @param string $contentText + * @param string $comment + */ + private function insertWikipage( $titleName, $contentText, $comment ) { + $page = WikiPage::factory( Title::newFromText( $titleName ) ); + + if ( !$page->exists() ) { + $pageId = $page->insertOn( $this->db ); + } else { + $pageId = $page->getId(); + } + + $user = User::newFromName( 'TestUser' ); + $revision = new Revision( array( + 'title' => $page->getTitle(), + 'page' => $pageId, + 'content_model' => $page->getTitle()->getContentModel(), + 'content_format' => $this->getFormat( $page->getTitle() ), + 'text' => $contentText, + 'comment' => $comment, + 'user' => $user->getId(), + 'user_text' => $user->getName(), + 'timestamp' => wfTimestamp( TS_ISO_8601 ), + 'minor_edit' => false, + ) ); + $revision->insertOn( $this->db ); + $changed = $page->updateIfNewerOn( $this->db, $revision ); + + if ( $changed !== false ) { + $page->doEditUpdates( $revision, $user ); + } + } + + /** + * @param Title $title + * @return string + */ + private function getFormat( Title $title ) { + return ContentHandler::getForTitle( $title )->getDefaultFormat(); + } + + public function getDeletionRevision() { + $data = array(); + + $revision = $this->getBaseRevision(); + $revision->setType( 'delete' ); + $revision->setAction( 'delete' ); + $revision->setUserName( 'TestUser' ); + array_push( $data, array( $revision ) ); + + $revision = $this->getBaseRevision(); + $revision->setType( 'delete' ); + $revision->setAction( 'delete' ); + array_push( $data, array( $revision ) ); + + return $data; + } + + public function getNoDeletionRevision() { + $revision = $this->getBaseRevision(); + $revision->setType( 'move' ); + $revision->setAction( 'move' ); + $revision->setUserName( 'TestUser' ); + return array( array( $revision ) ); + } + + private function getBaseRevision() { + $revision = new WikiRevision; + + $revision->setID( 1 ); + $revision->setTimestamp( wfTimestampNow() ); + $revision->setParams( 'a:0:{}' ); + $revision->setTitle( Title::newFromText( 'TestPage' ) ); + $revision->setNoUpdates( true ); + + return $revision; + } + + public function getNoRedirectData() { + $title = Title::newFromText( 'TestPage' ); + $origTitle = $title; + $revCount = 1; + return array( + array( $title, $origTitle, $revCount, 1, array() ), + array( $title, $origTitle, $revCount, 1, array( 'redirect' => "" ) ), + array( $title, $origTitle, $revCount, 0, array( 'redirect' => "Redirect TestPage" ) ) + ); + } + + public function getRedirectExistsData() { + $title = Title::newFromText( 'TestPage' ); + $origTitle = $title; + return array( + array( $title, $origTitle, 1, 1, array( 'redirect' => "Existing Page" ) ) + ); + } + + public function getRedirectSuccessful() { + $title = Title::newFromText( 'TestPage' ); + $origTitle = $title; + return array( + array( $title, $origTitle, 1, 1, array( 'redirect' => "Redirect TestPage" ) ) + ); + } +} + \ No newline at end of file diff --git a/tests/phpunit/SubscriptionHandlerTest.php b/tests/phpunit/SubscriptionHandlerTest.php index 61727e7..594cf64 100644 --- a/tests/phpunit/SubscriptionHandlerTest.php +++ b/tests/phpunit/SubscriptionHandlerTest.php @@ -2,7 +2,6 @@ namespace PubSubHubbubSubscriber; -use Language; use MediaWikiLangTestCase; use Revision; use Title; @@ -27,7 +26,6 @@ class SubscriptionHandlerTest extends MediaWikiLangTestCase { protected function setUp() { parent::setUp(); $this->tablesUsed[] = 'push_subscriptions'; - $this->mHandler = new SubscriptionHandler(); }