mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Echo
synced 2024-11-28 01:30:15 +00:00
Merge "Detect signature using Title class"
This commit is contained in:
commit
c5559da8cb
|
@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in a new issue