From: petarpetkovic Date: Thu, 9 Nov 2017 11:13:16 +0000 (+0100) Subject: Add new core tags X-Git-Tag: 1.31.0-rc.0~1346^2 X-Git-Url: http://git.cyclocoop.org/?a=commitdiff_plain;h=62713be990a1cde6962e583165ba4480d9bab098;p=lhc%2Fweb%2Fwiklou.git Add new core tags Add tags to types of edits that get automatic edit summaries: - Making a page a redirect - Changing redirect target - Changing an existing redirect into a non-redirect - Blanking of the page - Removing nearly all (more than 90%) content - Rolling back an edit Bug: T167656 Bug: T73236 Change-Id: Ie7f637fcec5ee659c1086e28e8ba21f470c45160 --- diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 3cd7ef181a..b623a343e8 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -6961,6 +6961,29 @@ $wgAllowCategorizedRecentChanges = false; */ $wgUseTagFilter = true; +/** + * List of core tags to enable. Available tags are: + * - 'mw-contentmodelchange': Edit changes content model of a page + * - 'mw-new-redirect': Edit makes new redirect page (new page or by changing content page) + * - 'mw-removed-redirect': Edit changes an existing redirect into a non-redirect + * - 'mw-changed-redirect-target': Edit changes redirect target + * - 'mw-blank': Edit completely blanks the page + * - 'mw-replace': Edit removes more than 90% of the content + * - 'mw-rollback': Edit is a rollback, made through the rollback link or rollback API + * + * @var array + * @since 1.31 + */ +$wgSoftwareTags = [ + 'mw-contentmodelchange' => true, + 'mw-new-redirect' => true, + 'mw-removed-redirect' => true, + 'mw-changed-redirect-target' => true, + 'mw-blank' => true, + 'mw-replace' => true, + 'mw-rollback' => true +]; + /** * If set to an integer, pages that are watched by this many users or more * will not require the unwatchedpages permission to view the number of diff --git a/includes/changetags/ChangeTags.php b/includes/changetags/ChangeTags.php index fa981247c2..b4a8ca8028 100644 --- a/includes/changetags/ChangeTags.php +++ b/includes/changetags/ChangeTags.php @@ -32,10 +32,44 @@ class ChangeTags { */ const MAX_DELETE_USES = 5000; + private static $definedSoftwareTags = [ + 'mw-contentmodelchange', + 'mw-new-redirect', + 'mw-removed-redirect', + 'mw-changed-redirect-target', + 'mw-blank', + 'mw-replace', + 'mw-rollback' + ]; + /** - * @var string[] + * Loads defined core tags, checks for invalid types (if not array), + * and filters for supported and enabled (if $all is false) tags only. + * + * @param bool $all If true, return all valid defined tags. Otherwise, return only enabled ones. + * @return array Array of all defined/enabled tags. */ - private static $coreTags = [ 'mw-contentmodelchange' ]; + public static function getSoftwareTags( $all = false ) { + global $wgSoftwareTags; + $softwareTags = []; + + if ( !is_array( $wgSoftwareTags ) ) { + wfWarn( 'wgSoftwareTags should be associative array of enabled tags. + Please refer to documentation for the list of tags you can enable' ); + return $softwareTags; + } + + $availableSoftwareTags = !$all ? + array_keys( array_filter( $wgSoftwareTags ) ) : + array_keys( $wgSoftwareTags ); + + $softwareTags = array_intersect( + $availableSoftwareTags, + self::$definedSoftwareTags + ); + + return $softwareTags; + } /** * Creates HTML for the given tags @@ -1210,7 +1244,7 @@ class ChangeTags { */ public static function listSoftwareActivatedTags() { // core active tags - $tags = self::$coreTags; + $tags = self::getSoftwareTags(); if ( !Hooks::isRegistered( 'ChangeTagsListActive' ) ) { return $tags; } @@ -1301,7 +1335,7 @@ class ChangeTags { */ public static function listSoftwareDefinedTags() { // core defined tags - $tags = self::$coreTags; + $tags = self::getSoftwareTags( true ); if ( !Hooks::isRegistered( 'ListDefinedTags' ) ) { return $tags; } diff --git a/includes/content/ContentHandler.php b/includes/content/ContentHandler.php index 0509e29215..a7b97a5425 100644 --- a/includes/content/ContentHandler.php +++ b/includes/content/ContentHandler.php @@ -754,82 +754,190 @@ abstract class ContentHandler { return false; } + /** + * Return type of change if one exists for the given edit. + * + * @since 1.31 + * + * @param Content|null $oldContent The previous text of the page. + * @param Content|null $newContent The submitted text of the page. + * @param int $flags Bit mask: a bit mask of flags submitted for the edit. + * + * @return string|null String key representing type of change, or null. + */ + private function getChangeType( + Content $oldContent = null, + Content $newContent = null, + $flags = 0 + ) { + $oldTarget = $oldContent !== null ? $oldContent->getRedirectTarget() : null; + $newTarget = $newContent !== null ? $newContent->getRedirectTarget() : null; + + // We check for the type of change in the given edit, and return string key accordingly + + // Blanking of a page + if ( $oldContent && $oldContent->getSize() > 0 && + $newContent && $newContent->getSize() === 0 + ) { + return 'blank'; + } + + // Redirects + if ( $newTarget ) { + if ( !$oldTarget ) { + // New redirect page (by creating new page or by changing content page) + return 'new-redirect'; + } elseif ( !$newTarget->equals( $oldTarget ) || + $oldTarget->getFragment() !== $newTarget->getFragment() + ) { + // Redirect target changed + return 'changed-redirect-target'; + } + } elseif ( $oldTarget ) { + // Changing an existing redirect into a non-redirect + return 'removed-redirect'; + } + + // New page created + if ( $flags & EDIT_NEW && $newContent && $newContent->getSize() > 0 ) { + return 'newpage'; + } + + // New blank page + if ( $flags & EDIT_NEW && $newContent && $newContent->getSize() === 0 ) { + return 'newblank'; + } + + // Removing more than 90% of the page + if ( $oldContent && $newContent && $oldContent->getSize() > 10 * $newContent->getSize() ) { + return 'replace'; + } + + // Content model changed + if ( $oldContent && $newContent && $oldContent->getModel() !== $newContent->getModel() ) { + return 'contentmodelchange'; + } + + return null; + } + /** * Return an applicable auto-summary if one exists for the given edit. * * @since 1.21 * - * @param Content $oldContent The previous text of the page. - * @param Content $newContent The submitted text of the page. + * @param Content|null $oldContent The previous text of the page. + * @param Content|null $newContent The submitted text of the page. * @param int $flags Bit mask: a bit mask of flags submitted for the edit. * * @return string An appropriate auto-summary, or an empty string. */ - public function getAutosummary( Content $oldContent = null, Content $newContent = null, - $flags ) { - // Decide what kind of auto-summary is needed. - - // Redirect auto-summaries - - /** - * @var $ot Title - * @var $rt Title - */ + public function getAutosummary( + Content $oldContent = null, + Content $newContent = null, + $flags = 0 + ) { + $changeType = $this->getChangeType( $oldContent, $newContent, $flags ); - $ot = !is_null( $oldContent ) ? $oldContent->getRedirectTarget() : null; - $rt = !is_null( $newContent ) ? $newContent->getRedirectTarget() : null; + // There's no applicable auto-summary for our case, so our auto-summary is empty. + if ( !$changeType ) { + return ''; + } - if ( is_object( $rt ) ) { - if ( !is_object( $ot ) - || !$rt->equals( $ot ) - || $ot->getFragment() != $rt->getFragment() - ) { + // Decide what kind of auto-summary is needed. + switch ( $changeType ) { + case 'new-redirect': + $newTarget = $newContent->getRedirectTarget(); $truncatedtext = $newContent->getTextForSummary( 250 - strlen( wfMessage( 'autoredircomment' )->inContentLanguage()->text() ) - - strlen( $rt->getFullText() ) ); + - strlen( $newTarget->getFullText() ) + ); - return wfMessage( 'autoredircomment', $rt->getFullText() ) + return wfMessage( 'autoredircomment', $newTarget->getFullText() ) ->rawParams( $truncatedtext )->inContentLanguage()->text(); - } - } + case 'changed-redirect-target': + $oldTarget = $oldContent->getRedirectTarget(); + $newTarget = $newContent->getRedirectTarget(); - // New page auto-summaries - if ( $flags & EDIT_NEW && $newContent->getSize() > 0 ) { - // If they're making a new article, give its text, truncated, in - // the summary. + $truncatedtext = $newContent->getTextForSummary( + 250 + - strlen( wfMessage( 'autosumm-changed-redirect-target' ) + ->inContentLanguage()->text() ) + - strlen( $oldTarget->getFullText() ) + - strlen( $newTarget->getFullText() ) + ); + + return wfMessage( 'autosumm-changed-redirect-target', + $oldTarget->getFullText(), + $newTarget->getFullText() ) + ->rawParams( $truncatedtext )->inContentLanguage()->text(); + case 'removed-redirect': + $oldTarget = $oldContent->getRedirectTarget(); + $truncatedtext = $newContent->getTextForSummary( + 250 + - strlen( wfMessage( 'autosumm-removed-redirect' ) + ->inContentLanguage()->text() ) + - strlen( $oldTarget->getFullText() ) ); - $truncatedtext = $newContent->getTextForSummary( - 200 - strlen( wfMessage( 'autosumm-new' )->inContentLanguage()->text() ) ); + return wfMessage( 'autosumm-removed-redirect', $oldTarget->getFullText() ) + ->rawParams( $truncatedtext )->inContentLanguage()->text(); + case 'newpage': + // If they're making a new article, give its text, truncated, in the summary. + $truncatedtext = $newContent->getTextForSummary( + 200 - strlen( wfMessage( 'autosumm-new' )->inContentLanguage()->text() ) ); - return wfMessage( 'autosumm-new' )->rawParams( $truncatedtext ) - ->inContentLanguage()->text(); + return wfMessage( 'autosumm-new' )->rawParams( $truncatedtext ) + ->inContentLanguage()->text(); + case 'blank': + return wfMessage( 'autosumm-blank' )->inContentLanguage()->text(); + case 'replace': + $truncatedtext = $newContent->getTextForSummary( + 200 - strlen( wfMessage( 'autosumm-replace' )->inContentLanguage()->text() ) ); + + return wfMessage( 'autosumm-replace' )->rawParams( $truncatedtext ) + ->inContentLanguage()->text(); + case 'newblank': + return wfMessage( 'autosumm-newblank' )->inContentLanguage()->text(); + default: + return ''; } + } - // Blanking auto-summaries - if ( !empty( $oldContent ) && $oldContent->getSize() > 0 && $newContent->getSize() == 0 ) { - return wfMessage( 'autosumm-blank' )->inContentLanguage()->text(); - } elseif ( !empty( $oldContent ) - && $oldContent->getSize() > 10 * $newContent->getSize() - && $newContent->getSize() < 500 - ) { - // Removing more than 90% of the article - - $truncatedtext = $newContent->getTextForSummary( - 200 - strlen( wfMessage( 'autosumm-replace' )->inContentLanguage()->text() ) ); + /** + * Return an applicable tag if one exists for the given edit or return null. + * + * @since 1.31 + * + * @param Content|null $oldContent The previous text of the page. + * @param Content|null $newContent The submitted text of the page. + * @param int $flags Bit mask: a bit mask of flags submitted for the edit. + * + * @return string|null An appropriate tag, or null. + */ + public function getChangeTag( + Content $oldContent = null, + Content $newContent = null, + $flags = 0 + ) { + $changeType = $this->getChangeType( $oldContent, $newContent, $flags ); - return wfMessage( 'autosumm-replace' )->rawParams( $truncatedtext ) - ->inContentLanguage()->text(); + // There's no applicable tag for this change. + if ( !$changeType ) { + return null; } - // New blank article auto-summary - if ( $flags & EDIT_NEW && $newContent->isEmpty() ) { - return wfMessage( 'autosumm-newblank' )->inContentLanguage()->text(); + // Core tags use the same keys as ones returned from $this->getChangeType() + // but prefixed with pseudo namespace 'mw-', so we add the prefix before checking + // if this type of change should be tagged + $tag = 'mw-' . $changeType; + + // Not all change types are tagged, so we check against the list of defined tags. + if ( in_array( $tag, ChangeTags::getSoftwareTags() ) ) { + return $tag; } - // If we reach this point, there's no applicable auto-summary for our - // case, so our auto-summary is empty. - return ''; + return null; } /** diff --git a/includes/page/WikiPage.php b/includes/page/WikiPage.php index 8b349288fe..9df3d8caca 100644 --- a/includes/page/WikiPage.php +++ b/includes/page/WikiPage.php @@ -1617,13 +1617,15 @@ class WikiPage implements Page, IDBAccessObject { $old_revision = $this->getRevision(); // current revision $old_content = $this->getContent( Revision::RAW ); // current revision's content - if ( $old_content && $old_content->getModel() !== $content->getModel() ) { - $tags[] = 'mw-contentmodelchange'; + $handler = $content->getContentHandler(); + $tag = $handler->getChangeTag( $old_content, $content, $flags ); + // If there is no applicable tag, null is returned, so we need to check + if ( $tag ) { + $tags[] = $tag; } - // Provide autosummaries if one is not provided and autosummaries are enabled + // Provide autosummaries if summary is not provided and autosummaries are enabled if ( $wgUseAutomaticEditSummaries && ( $flags & EDIT_AUTOSUMMARY ) && $summary == '' ) { - $handler = $content->getContentHandler(); $summary = $handler->getAutosummary( $old_content, $content, $flags ); } @@ -3211,6 +3213,10 @@ class WikiPage implements Page, IDBAccessObject { $targetContent = $target->getContent(); $changingContentModel = $targetContent->getModel() !== $current->getContentModel(); + if ( in_array( 'mw-rollback', ChangeTags::getSoftwareTags() ) ) { + $tags[] = 'mw-rollback'; + } + // Actually store the edit $status = $this->doEditContent( $targetContent, @@ -3287,7 +3293,8 @@ class WikiPage implements Page, IDBAccessObject { 'summary' => $summary, 'current' => $current, 'target' => $target, - 'newid' => $revId + 'newid' => $revId, + 'tags' => $tags ]; return []; diff --git a/languages/i18n/en.json b/languages/i18n/en.json index 52ac44703c..3eb5a885f9 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -3641,6 +3641,8 @@ "autosumm-blank": "Blanked the page", "autosumm-replace": "Replaced content with \"$1\"", "autoredircomment": "Redirected page to [[$1]]", + "autosumm-removed-redirect": "Removed redirect to [[$1]]", + "autosumm-changed-redirect-target": "Changed redirect target from [[$1]] to [[$2]]", "autosumm-new": "Created page with \"$1\"", "autosumm-newblank": "Created blank page", "autoblock_whitelist": "", @@ -3866,6 +3868,18 @@ "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag|Tags}}]]: $2)", "tag-mw-contentmodelchange": "content model change", "tag-mw-contentmodelchange-description": "Edits that [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel change the content model] of a page", + "tag-mw-new-redirect": "New redirect", + "tag-mw-new-redirect-description": "Edits that create a new redirect or change a page to a redirect", + "tag-mw-removed-redirect": "Removed redirect", + "tag-mw-removed-redirect-description": "Edits that change an existing redirect to a non-redirect", + "tag-mw-changed-redirect-target": "Redirect target changed", + "tag-mw-changed-redirect-target-description": "Edits that change the target of a redirect", + "tag-mw-blank": "Blanking", + "tag-mw-blank-description": "Edits that blank a page", + "tag-mw-replace": "Replaced", + "tag-mw-replace-description": "Edits that remove more than 90% of the content of a page", + "tag-mw-rollback": "Rollback", + "tag-mw-rollback-description": "Edits that roll back previous edits using the rollback link", "tags-title": "Tags", "tags-intro": "This page lists the tags that the software may mark an edit with, and their meaning.", "tags-tag": "Tag name", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index e5d4984441..9f365ee3f6 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -3835,6 +3835,8 @@ "autosumm-blank": "The auto summary when blanking the whole page. This is not the same as deleting the page.", "autosumm-replace": "The auto summary when a user removes a lot of characters in the page.\n\nParameters:\n* $1 - truncated text", "autoredircomment": "The auto summary when making a redirect. Parameters:\n* $1 - the page where it redirects to\n* $2 - (Optional) the first X number of characters of the redirect ($2 is usually only used when end users customize the message)\n{{Identical|Redirect}}", + "autosumm-removed-redirect": "The auto summary when making a redirect. Parameters:\n* $1 - the page where it redirects to\n* $2 - (Optional) the first X number of characters of the redirect ($2 is usually only used when end users customize the message)\n{{Identical|Redirect}}", + "autosumm-changed-redirect-target": "The auto summary when making a redirect. Parameters:\n* $1 - the page where it redirects to\n* $2 - (Optional) the first X number of characters of the redirect ($2 is usually only used when end users customize the message)\n{{Identical|Redirect}}", "autosumm-new": "The auto summary when creating a new page. $1 are the first X number of characters of the new page.", "autosumm-newblank": "The automatic edit summary when creating a blank page. This is not the same as blanking a page.", "autoblock_whitelist": "{{notranslate}}", @@ -4060,6 +4062,18 @@ "tag-list-wrapper": "Wrapper for the list of tags shown on recent changes, watchlists, history pages and diffs.\n\nParameters:\n* $1 - number of distinct tags for given edit\n* $2 - comma-separated list of tags for given edit", "tag-mw-contentmodelchange": "Change tag for edits that change the content model of a page", "tag-mw-contentmodelchange-description": "Description for \"content model change\" change tag", + "tag-mw-new-redirect": "Change tag for edits that make the page a redirect (either redirect creation or editing an existing page)", + "tag-mw-new-redirect-description": "Description for \"New redirect\" change tag", + "tag-mw-removed-redirect": "Change tag for edits that change an existing redirect into a non-redirect", + "tag-mw-removed-redirect-description": "Description for \"Removed redirect\" change tag", + "tag-mw-changed-redirect-target": "Change tag for edits that change the target of a redirect", + "tag-mw-changed-redirect-target-description": "Description for \"Redirect target changed\" change tag", + "tag-mw-blank": "Change tag for edits that blank a page with existing content", + "tag-mw-blank-description": "Description for \"blank\" change tag", + "tag-mw-replace": "Change tag for edits removing more than 90% of the content of a page", + "tag-mw-replace-description": "Description for \"replace\" change tag", + "tag-mw-rollback": "Change tag for rolling back an edit", + "tag-mw-rollback-description": "Description for \"rollback\" change tag", "tags-title": "The title of [[Special:Tags]].\n{{Identical|Tag}}", "tags-intro": "Explanation on top of [[Special:Tags]]. For more information on tags see [[mw:Manual:Tags|MediaWiki]].", "tags-tag": "Caption of a column in [[Special:Tags]]. For more information on tags see [[mw:Manual:Tags|MediaWiki]].", diff --git a/tests/phpunit/includes/changetags/ChangeTagsTest.php b/tests/phpunit/includes/changetags/ChangeTagsTest.php index 723d685627..63e0ec2268 100644 --- a/tests/phpunit/includes/changetags/ChangeTagsTest.php +++ b/tests/phpunit/includes/changetags/ChangeTagsTest.php @@ -5,7 +5,7 @@ */ class ChangeTagsTest extends MediaWikiTestCase { - // TODO only modifyDisplayQuery is tested, nothing else is + // TODO only modifyDisplayQuery and getSoftwareTags are tested, nothing else is /** @dataProvider provideModifyDisplayQuery */ public function testModifyDisplayQuery( $origQuery, $filter_tag, $useTags, $modifiedQuery ) { @@ -244,4 +244,66 @@ class ChangeTagsTest extends MediaWikiTestCase { ]; } + public static function dataGetSoftwareTags() { + return [ + [ + [ + 'mw-contentModelChange' => true, + 'mw-redirect' => true, + 'mw-rollback' => true, + 'mw-blank' => true, + 'mw-replace' => true + ], + [ + 'mw-rollback', + 'mw-replace', + 'mw-blank' + ] + ], + + [ + [ + 'mw-contentmodelchanged' => true, + 'mw-replace' => true, + 'mw-new-redirects' => true, + 'mw-changed-redirect-target' => true, + 'mw-rolback' => true, + 'mw-blanking' => false + ], + [ + 'mw-replace', + 'mw-changed-redirect-target' + ] + ], + + [ + [ + null, + false, + 'Lorem ipsum', + 'mw-translation' + ], + [] + ], + + [ + [], + [] + ] + ]; + } + + /** + * @dataProvider dataGetSoftwareTags + * @covers ChangeTags::getSoftwareTags + */ + public function testGetSoftwareTags( $softwareTags, $expected ) { + $this->setMwGlobals( 'wgSoftwareTags', $softwareTags ); + + $actual = ChangeTags::getSoftwareTags(); + // Order of tags in arrays is not important + sort( $expected ); + sort( $actual ); + $this->assertEquals( $expected, $actual ); + } } diff --git a/tests/phpunit/includes/content/ContentHandlerTest.php b/tests/phpunit/includes/content/ContentHandlerTest.php index 2422e792cf..1bd2eb04af 100644 --- a/tests/phpunit/includes/content/ContentHandlerTest.php +++ b/tests/phpunit/includes/content/ContentHandlerTest.php @@ -342,15 +342,32 @@ class ContentHandlerTest extends MediaWikiTestCase { $content = new DummyContentHandlerForTesting( CONTENT_MODEL_WIKITEXT ); $title = Title::newFromText( 'Help:Test' ); // Create a new content object with no content - $newContent = ContentHandler::makeContent( '', $title, null, null, CONTENT_MODEL_WIKITEXT ); + $newContent = ContentHandler::makeContent( '', $title, CONTENT_MODEL_WIKITEXT, null ); // first check, if we become a blank page created summary with the right bitmask $autoSummary = $content->getAutosummary( null, $newContent, 97 ); - $this->assertEquals( $autoSummary, 'Created blank page' ); + $this->assertEquals( $autoSummary, + wfMessage( 'autosumm-newblank' )->inContentLanguage()->text() ); // now check, what we become with another bitmask $autoSummary = $content->getAutosummary( null, $newContent, 92 ); $this->assertEquals( $autoSummary, '' ); } + /** + * Test software tag that is added when content model of the page changes + * @covers ContentHandler::getChangeTag + */ + public function testGetChangeTag() { + $this->setMwGlobals( 'wgSoftwareTags', [ 'mw-contentmodelchange' => true ] ); + $wikitextContentHandler = new DummyContentHandlerForTesting( CONTENT_MODEL_WIKITEXT ); + // Create old content object with javascript content model + $oldContent = ContentHandler::makeContent( '', null, CONTENT_MODEL_JAVASCRIPT, null ); + // Create new content object with wikitext content model + $newContent = ContentHandler::makeContent( '', null, CONTENT_MODEL_WIKITEXT, null ); + // Get the tag for this edit + $tag = $wikitextContentHandler->getChangeTag( $oldContent, $newContent, EDIT_UPDATE ); + $this->assertSame( $tag, 'mw-contentmodelchange' ); + } + /* public function testSupportsSections() { $this->markTestIncomplete( "not yet implemented" ); diff --git a/tests/phpunit/includes/content/WikitextContentHandlerTest.php b/tests/phpunit/includes/content/WikitextContentHandlerTest.php index 290b11ab00..77cfb92bbc 100644 --- a/tests/phpunit/includes/content/WikitextContentHandlerTest.php +++ b/tests/phpunit/includes/content/WikitextContentHandlerTest.php @@ -185,6 +185,13 @@ class WikitextContentHandlerTest extends MediaWikiLangTestCase { '/^Created page .*Hello/' ], + [ + null, + '', + EDIT_NEW, + '/^Created blank page$/' + ], + [ 'Hello there, world!', '', @@ -227,6 +234,104 @@ class WikitextContentHandlerTest extends MediaWikiLangTestCase { ); } + public static function dataGetChangeTag() { + return [ + [ + null, + '#REDIRECT [[Foo]]', + 0, + 'mw-new-redirect' + ], + + [ + 'Lorem ipsum dolor', + '#REDIRECT [[Foo]]', + 0, + 'mw-new-redirect' + ], + + [ + '#REDIRECT [[Foo]]', + 'Lorem ipsum dolor', + 0, + 'mw-removed-redirect' + ], + + [ + '#REDIRECT [[Foo]]', + '#REDIRECT [[Bar]]', + 0, + 'mw-changed-redirect-target' + ], + + [ + null, + 'Lorem ipsum dolor', + EDIT_NEW, + null // mw-newpage is not defined as a tag + ], + + [ + null, + '', + EDIT_NEW, + null // mw-newblank is not defined as a tag + ], + + [ + 'Lorem ipsum dolor', + '', + 0, + 'mw-blank' + ], + + [ + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy + eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam + voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet + clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.', + 'Ipsum', + 0, + 'mw-replace' + ], + + [ + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy + eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam + voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet + clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.', + 'Duis purus odio, rhoncus et finibus dapibus, facilisis ac urna. Pellentesque + arcu, tristique nec tempus nec, suscipit vel arcu. Sed non dolor nec ligula + congue tempor. Quisque pellentesque finibus orci a molestie. Nam maximus, purus + euismod finibus mollis, dui ante malesuada felis, dignissim rutrum diam sapien.', + 0, + null + ], + ]; + } + + /** + * @dataProvider dataGetChangeTag + * @covers WikitextContentHandler::getChangeTag + */ + public function testGetChangeTag( $old, $new, $flags, $expected ) { + $this->setMwGlobals( 'wgSoftwareTags', [ + 'mw-new-redirect' => true, + 'mw-removed-redirect' => true, + 'mw-changed-redirect-target' => true, + 'mw-newpage' => true, + 'mw-newblank' => true, + 'mw-blank' => true, + 'mw-replace' => true, + ] ); + $oldContent = is_null( $old ) ? null : new WikitextContent( $old ); + $newContent = is_null( $new ) ? null : new WikitextContent( $new ); + + $tag = $this->handler->getChangeTag( $oldContent, $newContent, $flags ); + + $this->assertSame( $expected, $tag ); + } + /** * @todo Text case requires database, should be done by a test class in the Database group */ diff --git a/tests/phpunit/includes/page/WikiPageTest.php b/tests/phpunit/includes/page/WikiPageTest.php index 386f142dbb..d36f8b50f1 100644 --- a/tests/phpunit/includes/page/WikiPageTest.php +++ b/tests/phpunit/includes/page/WikiPageTest.php @@ -993,6 +993,60 @@ more stuff $this->assertEquals( "one", $page->getContent()->getNativeData() ); } + /** + * Tests tagging for edits that do rollback action + * @covers WikiPage::doRollback + */ + public function testDoRollbackTagging() { + if ( !in_array( 'mw-rollback', ChangeTags::getSoftwareTags() ) ) { + $this->markTestSkipped( 'Rollback tag deactivated, skipped the test.' ); + } + + $admin = new User(); + $admin->setName( 'Administrator' ); + $admin->addToDatabase(); + + $text = 'First line'; + $page = $this->newPage( 'WikiPageTest_testDoRollbackTagging' ); + $page->doEditContent( + ContentHandler::makeContent( $text, $page->getTitle(), CONTENT_MODEL_WIKITEXT ), + 'Added first line', + EDIT_NEW, + false, + $admin + ); + + $secondUser = new User(); + $secondUser->setName( '92.65.217.32' ); + $text .= '\n\nSecond line'; + $page = new WikiPage( $page->getTitle() ); + $page->doEditContent( + ContentHandler::makeContent( $text, $page->getTitle(), CONTENT_MODEL_WIKITEXT ), + 'Adding second line', + 0, + false, + $secondUser + ); + + // Now, try the rollback + $admin->addGroup( 'sysop' ); // Make the test user a sysop + $token = $admin->getEditToken( 'rollback' ); + $errors = $page->doRollback( + $secondUser->getName(), + 'testing rollback', + $token, + false, + $resultDetails, + $admin + ); + + // If doRollback completed without errors + if ( $errors === [] ) { + $tags = $resultDetails[ 'tags' ]; + $this->assertContains( 'mw-rollback', $tags ); + } + } + public static function provideGetAutoDeleteReason() { return [ [