Merge "Detect signature using Title class"

This commit is contained in:
jenkins-bot 2014-10-23 21:25:37 +00:00 committed by Gerrit Code Review
commit c5559da8cb
2 changed files with 130 additions and 66 deletions

View file

@ -669,74 +669,74 @@ abstract class EchoDiscussionParser {
static function getUserFromLine( $line, $timestampPos ) {
global $wgContLang;
// Later entries have a higher precedence
// @todo FIXME: handle optional whitespace in links
$languages = array( $wgContLang );
if ( $wgContLang->getCode() !== 'en' ) {
$languages[] = Language::factory( 'en' );
// lifted from Parser::pstPass2
$tc = '[' . Title::legalChars() . ']';
$nc = '[ _0-9A-Za-z\x80-\xff-]'; // Namespaces can use non-ascii
// [[ns:page]] with optional fragment(#foo) and/or pipe(|bar)
$regex = "/\[\[($nc+:$tc+)(?:#.*?)?(?:\\|.*?)?]]/";
$potentialContext = substr( $line, 0, $timestampPos );
// only look at the 300 chars preceding the timestamp
$startCheckAt = max( 0, $timestampPos - 300 );
$context = substr( $potentialContext, -$startCheckAt );
if ( !preg_match_all( $regex, $context, $matches, PREG_SET_ORDER ) ) {
return false;
}
$possiblePrefixes = array();
foreach ( $languages as $language ) {
$nsNames = $language->getNamespaces();
$possiblePrefixes[] = '[[' . $nsNames[NS_USER] . ':';
$possiblePrefixes[] = '[[' . $nsNames[NS_USER_TALK] . ':';
$nsAliases = $language->getNamespaceAliases();
foreach ( $nsAliases as $text => $id ) {
if ( $id == NS_USER || $id == NS_USER_TALK ) {
$possiblePrefixes[] = '[[' . $text . ':';
// prefer the last match in the line
$winningUser = $winner = false;
foreach ( array_reverse( $matches ) as $match ) {
$title = Title::newFromText( $match[1] );
if ( !$title ) {
continue;
}
if ( $title->getNamespace() === NS_USER ) {
if ( $winningUser === false || $winningUser === $title->getText() ) {
// registered user winner!!
$winningUser = $title->getText();
$winner = $match;
}
break;
}
// Only check Special:Contributions and NS_USER_TALK if NS_USER_TALK
// has not yet triggered.
if ( $winningUser === false ) {
if ( $title->isSpecial( 'Contributions' ) ) {
// anon user winner!!
$parts = explode( '/', $title->getText(), 2 );
$winningUser = end( $parts );
$winner = $match;
break;
}
if ( $title->getNamespace() === NS_USER_TALK ) {
// registered user winner!
// but keep looking for a matching NS_USER link to the same user so
// we return the correct starting position. often the signature is:
// NS_USER (NS_USER_TALK) <timestamp>
// Wiki's have complete control over their signatures via Mediawiki:Signature,
// so it's also possible there is no matching NS_USER link.
$winningUser = $title->getText();
$winner = $match;
continue;
}
}
}
// @todo FIXME: Check aliases too
$possiblePrefixes[] = '[[' . SpecialPage::getTitleFor( 'Contributions' )->getPrefixedText() . '/';
foreach ( $possiblePrefixes as $prefix ) {
if ( strpos( $prefix, '_' ) !== false ) {
$possiblePrefixes[] = str_replace( '_', ' ', $prefix );
}
}
$winningUser = false;
$winningPos = false;
// Look for the leftmost link to the rightmost user
foreach ( $possiblePrefixes as $prefix ) {
$output = self::getLinkFromLine( $line, $prefix );
if ( $output === false ) {
continue;
} else {
list( $pos, $user ) = $output;
}
// Couldn't be a signature
if ( ( $timestampPos - $pos ) > 255 ) {
continue;
}
if (
$winningPos === false ||
( $pos > $winningPos && $user !== $winningUser ) ||
(
$pos < $winningPos &&
$user === $winningUser
)
) {
$winningPos = $pos;
$winningUser = ucfirst( trim( $user ) );
}
}
if ( $winningUser === false ) {
// print "E\tNo winning user\n";
if ( !$winningUser ) {
return false;
}
return array( $winningPos, $winningUser );
$pos = strrpos( $potentialContext, $winner[0] );
if ( !$pos ) {
// shouldn't be possible, $winner[0] is the string match from preg_match_all above,
// but just in case.
wfDebugLog( 'Echo', __METHOD__ . 'Did not find user "' . $match[0] . '" in wikitext: ' . $line );
return false;
}
return array( $pos, $winningUser );
}
/**

View file

@ -83,17 +83,66 @@ TEXT
$ts = self::getExemplarTimestamp();
return array(
// Basic
array( "I like this. [[User:Werdna]] ([[User talk:Werdna|talk]]) $ts", 'Werdna' ),
array(
"I like this. [[User:Werdna]] ([[User talk:Werdna|talk]]) $ts",
array(
13,
'Werdna'
),
),
// Confounding
array( "[[User:Jorm]] is a meanie. --[[User:Werdna|Andrew]] $ts", "Werdna" ),
array(
"[[User:Jorm]] is a meanie. --[[User:Werdna|Andrew]] $ts",
array(
29,
"Werdna"
),
),
// Talk page link only
array( "[[User:Swalling|Steve]] is the best person I have ever met. --[[User talk:Werdna|Andrew]] $ts", 'Werdna' ),
array(
"[[User:Swalling|Steve]] is the best person I have ever met. --[[User talk:Werdna|Andrew]] $ts",
array(
62,
'Werdna'
),
),
// Anonymous user
array( "I am anonymous because I like my IP address. --[[Special:Contributions/127.0.0.1]] $ts", '127.0.0.1' ),
array(
"I am anonymous because I like my IP address. --[[Special:Contributions/127.0.0.1]] $ts",
array(
47,
'127.0.0.1'
),
),
// No signature
array( "Well, I do think that [[User:Newyorkbrad]] is pretty cool, but what do I know?", false ),
array(
"Well, \nI do think that [[User:Newyorkbrad]] is pretty cool, but what do I know?",
false
),
// Hash symbols in usernames
array( "What do you think? [[User talk:We buried our secrets in the garden#top|wbositg]] $ts", 'We buried our secrets in the garden' ),
array(
"What do you think? [[User talk:We buried our secrets in the garden#top|wbositg]] $ts",
array(
19,
'We buried our secrets in the garden'
),
),
// Title that gets normalized different than it is provided in the wikitext
array(
"Beep boop [[User:I_Heart_Spaces]] ([[User_talk:I_Heart_Spaces]]) $ts",
array(
10,
'I Heart Spaces'
),
),
// Accepts ] in the pipe
array(
"Shake n Bake --[[User:Werdna|wer]dna]] $ts",
array(
15,
'Werdna',
),
),
);
}
@ -423,7 +472,9 @@ TEXT
return array(
array(
'Must detect first sub heading when inserting in the middle of two sub headings',
// expected header content
'Sub Heading 1',
// test content format
"
== Heading ==
$comment
@ -435,12 +486,15 @@ $comment
== Sub Heading 2 ==
$comment
",
// user signing new comment
$name
),
array(
'Must detect second sub heading when inserting in the end of two sub headings',
// expected header content
'Sub Heading 2',
// test content format
"
== Heading ==
$comment
@ -452,12 +506,15 @@ $comment
$comment
%s
",
// user signing new comment
$name
),
array(
'Commenting in multiple sub-headings must result in no section link',
// expected header content
'',
// test content format
"
== Heading ==
$comment
@ -471,29 +528,36 @@ $comment
%s
",
// user signing new comment
$name
),
array(
'Must accept headings without a space between the = and the section name',
// expected header content
'Heading',
// test content format
"
==Heading==
$comment
%s
",
// user signing new comment
$name
),
array(
'Must not accept invalid headings split with a return',
// expected header content
'',
// test content format
"
==Some
Heading==
$comment
%s
",
// user signing new comment
$name
),
);
@ -502,7 +566,7 @@ $comment
/**
* @dataProvider provider_detectSectionTitleAndText
*/
public function testdetectSectionTitleAndText( $message, $expect, $format, $name ) {
public function testDetectSectionTitleAndText( $message, $expect, $format, $name ) {
// str_replace because we want to replace multiple instances of '%s' with the same valueA
$before = str_replace( '%s', '', $format );
$after = str_replace( '%s', self::signedMessage( $name ), $format );