diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0b10f70 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Composer dependencies +/vendor/ +/composer.lock + +# IDE files +.vscode/ +.idea/ + +# Temporary files +*.tmp +*.log + +# OS files +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..f76e141 --- /dev/null +++ b/composer.json @@ -0,0 +1,5 @@ +{ + "require-dev": { + "phpunit/phpunit": "^9.0" + } +} diff --git a/i18n/de.json b/i18n/de.json index fa773f4..5e55db4 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -3,5 +3,5 @@ "authors": [ "MyWikis LLC" ] }, "crawlerprotection-accessdenied-title": "Zugriff verweigert", - "crawlerprotection-accessdenied-text": "Anmeldung erforderlich, um diese Aktion auzuführen oder Spezialseite anzusehen." + "crawlerprotection-accessdenied-text": "Anmeldung erforderlich, um diese Aktion auzuführen oder Spezialseite anzusehen. Bitte [[Special:UserLogin|melden Sie sich an]], um fortzufahren." } diff --git a/i18n/en.json b/i18n/en.json index 6ca93dc..59d0a89 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -3,5 +3,5 @@ "authors": [ "MyWikis LLC" ] }, "crawlerprotection-accessdenied-title": "Access denied", - "crawlerprotection-accessdenied-text": "You must be logged in to perform this action or view this special page." + "crawlerprotection-accessdenied-text": "You must be logged in to perform this action or view this special page. Please [[Special:UserLogin|log in]] to continue." } diff --git a/includes/Hooks.php b/includes/Hooks.php index 436d7e0..304767c 100644 --- a/includes/Hooks.php +++ b/includes/Hooks.php @@ -113,14 +113,17 @@ public function onSpecialPageBeforeExecute( $special, $subPage ) { * @return void */ protected function denyAccess( OutputPage $output ): void { + $output->clearHTML(); $output->setStatusCode( 403 ); - $output->addWikiTextAsInterface( wfMessage( 'crawlerprotection-accessdenied-text' )->plain() ); - + if ( version_compare( MW_VERSION, '1.41', '<' ) ) { $output->setPageTitle( wfMessage( 'crawlerprotection-accessdenied-title' ) ); } else { // @phan-suppress-next-line PhanUndeclaredMethod Exists in 1.41+ $output->setPageTitleMsg( wfMessage( 'crawlerprotection-accessdenied-title' ) ); } + + $output->addWikiTextAsInterface( wfMessage( 'crawlerprotection-accessdenied-text' )->plain() ); + $output->returnToMain(); } } diff --git a/tests/phpunit/unit/HooksTest.php b/tests/phpunit/unit/HooksTest.php index eec20b8..47742c1 100644 --- a/tests/phpunit/unit/HooksTest.php +++ b/tests/phpunit/unit/HooksTest.php @@ -133,4 +133,21 @@ public function testNonRevisionTypeAlwaysAllowed() { $result = $runner->onMediaWikiPerformAction( $output, $article, $title, $user, $request, $wiki ); $this->assertTrue( $result ); } + + /** + * @covers ::denyAccess + */ + public function testDenyAccessSetsCorrectStatusAndContent() { + $output = $this->createMock( self::$outputPageClassName ); + $output->expects( $this->once() )->method( 'clearHTML' ); + $output->expects( $this->once() )->method( 'setStatusCode' )->with( 403 ); + $output->expects( $this->once() )->method( 'addWikiTextAsInterface' ); + $output->expects( $this->once() )->method( 'returnToMain' ); + + $hooks = new Hooks(); + $reflection = new \ReflectionClass( $hooks ); + $method = $reflection->getMethod( 'denyAccess' ); + $method->setAccessible( true ); + $method->invoke( $hooks, $output ); + } }