mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Echo
synced 2024-09-24 02:39:33 +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 ) {
|
static function getUserFromLine( $line, $timestampPos ) {
|
||||||
global $wgContLang;
|
global $wgContLang;
|
||||||
|
|
||||||
// Later entries have a higher precedence
|
// lifted from Parser::pstPass2
|
||||||
// @todo FIXME: handle optional whitespace in links
|
$tc = '[' . Title::legalChars() . ']';
|
||||||
$languages = array( $wgContLang );
|
$nc = '[ _0-9A-Za-z\x80-\xff-]'; // Namespaces can use non-ascii
|
||||||
if ( $wgContLang->getCode() !== 'en' ) {
|
|
||||||
$languages[] = Language::factory( 'en' );
|
// [[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();
|
// prefer the last match in the line
|
||||||
|
$winningUser = $winner = false;
|
||||||
foreach ( $languages as $language ) {
|
foreach ( array_reverse( $matches ) as $match ) {
|
||||||
$nsNames = $language->getNamespaces();
|
$title = Title::newFromText( $match[1] );
|
||||||
$possiblePrefixes[] = '[[' . $nsNames[NS_USER] . ':';
|
if ( !$title ) {
|
||||||
$possiblePrefixes[] = '[[' . $nsNames[NS_USER_TALK] . ':';
|
continue;
|
||||||
|
}
|
||||||
$nsAliases = $language->getNamespaceAliases();
|
if ( $title->getNamespace() === NS_USER ) {
|
||||||
foreach ( $nsAliases as $text => $id ) {
|
if ( $winningUser === false || $winningUser === $title->getText() ) {
|
||||||
if ( $id == NS_USER || $id == NS_USER_TALK ) {
|
// registered user winner!!
|
||||||
$possiblePrefixes[] = '[[' . $text . ':';
|
$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
|
if ( !$winningUser ) {
|
||||||
$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";
|
|
||||||
return false;
|
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();
|
$ts = self::getExemplarTimestamp();
|
||||||
return array(
|
return array(
|
||||||
// Basic
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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(
|
return array(
|
||||||
array(
|
array(
|
||||||
'Must detect first sub heading when inserting in the middle of two sub headings',
|
'Must detect first sub heading when inserting in the middle of two sub headings',
|
||||||
|
// expected header content
|
||||||
'Sub Heading 1',
|
'Sub Heading 1',
|
||||||
|
// test content format
|
||||||
"
|
"
|
||||||
== Heading ==
|
== Heading ==
|
||||||
$comment
|
$comment
|
||||||
|
@ -435,12 +486,15 @@ $comment
|
||||||
== Sub Heading 2 ==
|
== Sub Heading 2 ==
|
||||||
$comment
|
$comment
|
||||||
",
|
",
|
||||||
|
// user signing new comment
|
||||||
$name
|
$name
|
||||||
),
|
),
|
||||||
|
|
||||||
array(
|
array(
|
||||||
'Must detect second sub heading when inserting in the end of two sub headings',
|
'Must detect second sub heading when inserting in the end of two sub headings',
|
||||||
|
// expected header content
|
||||||
'Sub Heading 2',
|
'Sub Heading 2',
|
||||||
|
// test content format
|
||||||
"
|
"
|
||||||
== Heading ==
|
== Heading ==
|
||||||
$comment
|
$comment
|
||||||
|
@ -452,12 +506,15 @@ $comment
|
||||||
$comment
|
$comment
|
||||||
%s
|
%s
|
||||||
",
|
",
|
||||||
|
// user signing new comment
|
||||||
$name
|
$name
|
||||||
),
|
),
|
||||||
|
|
||||||
array(
|
array(
|
||||||
'Commenting in multiple sub-headings must result in no section link',
|
'Commenting in multiple sub-headings must result in no section link',
|
||||||
|
// expected header content
|
||||||
'',
|
'',
|
||||||
|
// test content format
|
||||||
"
|
"
|
||||||
== Heading ==
|
== Heading ==
|
||||||
$comment
|
$comment
|
||||||
|
@ -471,29 +528,36 @@ $comment
|
||||||
%s
|
%s
|
||||||
|
|
||||||
",
|
",
|
||||||
|
// user signing new comment
|
||||||
$name
|
$name
|
||||||
),
|
),
|
||||||
|
|
||||||
array(
|
array(
|
||||||
'Must accept headings without a space between the = and the section name',
|
'Must accept headings without a space between the = and the section name',
|
||||||
|
// expected header content
|
||||||
'Heading',
|
'Heading',
|
||||||
|
// test content format
|
||||||
"
|
"
|
||||||
==Heading==
|
==Heading==
|
||||||
$comment
|
$comment
|
||||||
%s
|
%s
|
||||||
",
|
",
|
||||||
|
// user signing new comment
|
||||||
$name
|
$name
|
||||||
),
|
),
|
||||||
|
|
||||||
array(
|
array(
|
||||||
'Must not accept invalid headings split with a return',
|
'Must not accept invalid headings split with a return',
|
||||||
|
// expected header content
|
||||||
'',
|
'',
|
||||||
|
// test content format
|
||||||
"
|
"
|
||||||
==Some
|
==Some
|
||||||
Heading==
|
Heading==
|
||||||
$comment
|
$comment
|
||||||
%s
|
%s
|
||||||
",
|
",
|
||||||
|
// user signing new comment
|
||||||
$name
|
$name
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -502,7 +566,7 @@ $comment
|
||||||
/**
|
/**
|
||||||
* @dataProvider provider_detectSectionTitleAndText
|
* @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
|
// str_replace because we want to replace multiple instances of '%s' with the same valueA
|
||||||
$before = str_replace( '%s', '', $format );
|
$before = str_replace( '%s', '', $format );
|
||||||
$after = str_replace( '%s', self::signedMessage( $name ), $format );
|
$after = str_replace( '%s', self::signedMessage( $name ), $format );
|
||||||
|
|
Loading…
Reference in a new issue