Add support for enabling and displaying global interwikis

This effectively merges Extension:ShoutWikiInterwikiMagic into Interwiki
to add support for global interwikis, allowing sysadmins to set
$wgInterwikiCentralDB to a central wiki database from which to pull global
interwikis, which will be used alongside any locally-defined prefixes.

It also separates out the display of global, local, and language
interwikis into their own sections, improving the display even for
local-only projects.

Bug: 68241
Change-Id: I54c072c65f10dd0ad5f815c2649e7ce9ed1e7b58
This commit is contained in:
isarra 2014-07-19 17:40:44 +00:00
parent 6e13591eb7
commit ca46fc0350
4 changed files with 168 additions and 23 deletions

46
Interwiki.php Normal file → Executable file
View file

@ -10,6 +10,8 @@
* @version 3.0 * @version 3.0
* @author Stephanie Amanda Stevens <phroziac@gmail.com> * @author Stephanie Amanda Stevens <phroziac@gmail.com>
* @author Robin Pepermans (SPQRobin) <robinp.1273@gmail.com> * @author Robin Pepermans (SPQRobin) <robinp.1273@gmail.com>
* @author Jack Phoenix <jack@shoutwiki.com>
* @author Calimonius the Estrange <isarra@shoutwiki.com>
* @copyright Copyright © 2005-2007 Stephanie Amanda Stevens * @copyright Copyright © 2005-2007 Stephanie Amanda Stevens
* @copyright Copyright © 2007-2011 Robin Pepermans (SPQRobin) * @copyright Copyright © 2007-2011 Robin Pepermans (SPQRobin)
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
@ -26,6 +28,9 @@ if ( !defined( 'MEDIAWIKI' ) ) {
// the addition of a log for interwiki link changes. // the addition of a log for interwiki link changes.
$wgInterwikiViewOnly = false; $wgInterwikiViewOnly = false;
// Name of a database where global interwikis will be stored.
$wgInterwikiCentralDB = null;
// Extension credits for Special:Version // Extension credits for Special:Version
$wgExtensionCredits['specialpage'][] = array( $wgExtensionCredits['specialpage'][] = array(
'path' => __FILE__, 'path' => __FILE__,
@ -38,9 +43,11 @@ $wgExtensionCredits['specialpage'][] = array(
'Platonides', 'Platonides',
'Raimond Spekking', 'Raimond Spekking',
'Sam Reed', 'Sam Reed',
'Jack Phoenix',
'Calimonius the Estrange',
'...' '...'
), ),
'version' => '2.3 20140327', 'version' => '3.0 20140719',
'url' => 'https://www.mediawiki.org/wiki/Extension:Interwiki', 'url' => 'https://www.mediawiki.org/wiki/Extension:Interwiki',
'descriptionmsg' => 'interwiki-desc', 'descriptionmsg' => 'interwiki-desc',
); );
@ -66,6 +73,9 @@ $wgAutoloadClasses['InterwikiLogFormatter'] = $dir . 'Interwiki_body.php';
$wgSpecialPages['Interwiki'] = 'SpecialInterwiki'; $wgSpecialPages['Interwiki'] = 'SpecialInterwiki';
$wgSpecialPageGroups['Interwiki'] = 'wiki'; $wgSpecialPageGroups['Interwiki'] = 'wiki';
$wgHooks['InterwikiLoadPrefix'][] = 'wfGlobalInterwikis';
function setupInterwikiExtension() { function setupInterwikiExtension() {
global $wgInterwikiViewOnly; global $wgInterwikiViewOnly;
@ -77,9 +87,41 @@ function setupInterwikiExtension() {
// Set up the new log type - interwiki actions are logged to this new log // Set up the new log type - interwiki actions are logged to this new log
$wgLogTypes[] = 'interwiki'; $wgLogTypes[] = 'interwiki';
# interwiki, iw_add, iw_delete, iw_edit // interwiki, iw_add, iw_delete, iw_edit
$wgLogActionsHandlers['interwiki/*'] = 'InterwikiLogFormatter'; $wgLogActionsHandlers['interwiki/*'] = 'InterwikiLogFormatter';
} }
return true; return true;
} }
function wfGlobalInterwikis( $prefix, &$iwData ) {
global $wgInterwikiCentralDB;
// docs/hooks.txt says: Return true without providing an interwiki to continue interwiki search.
if ( $wgInterwikiCentralDB === null || $wgInterwikiCentralDB === wfWikiId() ) {
// No global set or this is global, nothing to add
return true;
}
if ( !Language::fetchLanguageName( $prefix ) ) {
// Check if prefix exists locally and skip
foreach ( Interwiki::getAllPrefixes( null ) as $id => $localPrefixInfo ) {
if ( $prefix === $localPrefixInfo['iw_prefix'] ) {
return true;
}
}
$dbr = wfGetDB( DB_SLAVE, array(), $wgInterwikiCentralDB );
$res = $dbr->selectRow(
'interwiki',
'*',
array( 'iw_prefix' => $prefix ),
__METHOD__
);
if ( !$res ) {
return true;
}
// Excplicitly make this an array since it's expected to be one
$iwData = (array)$res;
// At this point, we can safely return false because we know that we have something
return false;
}
return true;
}

View file

@ -212,7 +212,7 @@ class SpecialInterwiki extends SpecialPage {
} }
function doSubmit() { function doSubmit() {
global $wgContLang, $wgMemc; global $wgMemc, $wgContLang;
$request = $this->getRequest(); $request = $this->getRequest();
$prefix = $request->getVal( 'wpInterwikiPrefix' ); $prefix = $request->getVal( 'wpInterwikiPrefix' );
@ -295,47 +295,130 @@ class SpecialInterwiki extends SpecialPage {
} }
function showList() { function showList() {
global $wgInterwikiCentralDB;
$canModify = $this->canModify(); $canModify = $this->canModify();
// Page intro content
$this->getOutput()->addWikiMsg( 'interwiki_intro' ); $this->getOutput()->addWikiMsg( 'interwiki_intro' );
// Make collapsible. // Make collapsible.
$this->getOutput()->addHTML( $this->getOutput()->addHTML(
Html::openElement( Html::openElement(
'div', array( 'div', array(
'class' => 'mw-collapsible mw-collapsed', 'class' => 'mw-collapsible mw-collapsed mw-interwiki-legend',
'data-collapsetext' => $this->msg( 'interwiki-legend-hide' )->escaped(), 'data-collapsetext' => $this->msg( 'interwiki-legend-hide' )->escaped(),
'data-expandtext' => $this->msg('interwiki-legend-show' )->escaped() 'data-expandtext' => $this->msg('interwiki-legend-show' )->escaped()
) ) ); ) ) );
$this->getOutput()->addWikiMsg( 'interwiki_legend' ); $this->getOutput()->addWikiMsg( 'interwiki_legend' );
$this->getOutput()->addHTML( Html::closeElement( 'div' ) ); // end collapsible. $this->getOutput()->addHTML( Html::closeElement( 'div' ) ); // end collapsible.
$this->getOutput()->addHTML( '<div style="clear:both"></div>' );
if ( $canModify ) { // Build lists
$this->getOutput()->addWikiMsg( 'interwiki_intro_footer' );
$addtext = $this->msg( 'interwiki_addtext' )->escaped();
$addlink = Linker::linkKnown( $this->getPageTitle( 'add' ), $addtext );
$this->getOutput()->addHTML( '<p class="mw-interwiki-addlink">' . $addlink . '</p>' );
}
if ( !method_exists( 'Interwiki', 'getAllPrefixes' ) ) { if ( !method_exists( 'Interwiki', 'getAllPrefixes' ) ) {
// version 2.0 is not backwards compatible (but still display nice error) // version 2.0 is not backwards compatible (but will still display a nice error)
$this->error( 'interwiki_error' ); $this->error( 'interwiki_error' );
return; return;
} }
$iwPrefixes = Interwiki::getAllPrefixes( null ); $iwPrefixes = Interwiki::getAllPrefixes( null );
$iwGlobalPrefixes = array();
if ( !is_array( $iwPrefixes ) || count( $iwPrefixes ) === 0 ) { if ( $wgInterwikiCentralDB !== null && $wgInterwikiCentralDB !== wfWikiId() ) {
// If the interwiki table is empty, display an error message // Fetch list from global table
$this->error( 'interwiki_error' ); $dbrCentralDB = wfGetDB( DB_SLAVE, array(), $wgInterwikiCentralDB );
return; $res = $dbrCentralDB->select( 'interwiki', '*', false, __METHOD__ );
$retval = array();
foreach ( $res as $row ) {
$row = (array)$row;
if ( !Language::fetchLanguageName( $row['iw_prefix'] ) ) {
$retval[] = $row;
}
}
$iwGlobalPrefixes = $retval;
} }
// Split out language links
$iwLocalPrefixes = array();
$iwLanguagePrefixes = array();
foreach ( $iwPrefixes as $iwPrefix ) {
if ( Language::fetchLanguageName( $iwPrefix['iw_prefix'] ) ) {
$iwLanguagePrefixes[] = $iwPrefix;
} else {
$iwLocalPrefixes[] = $iwPrefix;
}
}
// Add general description and 'add' link
if ( $canModify ) {
$this->getOutput()->addWikiMsg( 'interwiki_intro_footer' );
if ( count( $iwGlobalPrefixes ) !== 0 ) {
$addtext = $this->msg( 'interwiki-addtext-local' )->escaped();
} else {
$addtext = $this->msg( 'interwiki_addtext' )->escaped();
}
$addlink = Linker::linkKnown( $this->getPageTitle( 'add' ), $addtext );
$this->getOutput()->addHTML( '<p class="mw-interwiki-addlink">' . $addlink . '</p>' );
}
if ( !is_array( $iwPrefixes ) || count( $iwPrefixes ) === 0 ) {
if ( !is_array( $iwGlobalPrefixes ) || count( $iwGlobalPrefixes ) === 0 ) {
// If the interwiki table(s) are empty, display an error message
$this->error( 'interwiki_error' );
return;
}
}
// Add the global table
if ( count( $iwGlobalPrefixes ) !== 0 ) {
$this->getOutput()->addHTML(
'<h2 id="interwikitable-global">' .
$this->msg( 'interwiki-global-links' )->parse() .
'</h2>'
);
$this->getOutput()->addWikiMsg( 'interwiki-global-description' );
// $canModify is false here because this is just a display of remote data
$this->makeTable( false, $iwGlobalPrefixes );
}
// Add the local table
if ( count( $iwLocalPrefixes ) !== 0 ) {
if ( count( $iwGlobalPrefixes ) !== 0 ) {
$this->getOutput()->addHTML(
'<h2 id="interwikitable-local">' .
$this->msg( 'interwiki-local-links' )->parse() .
'</h2>'
);
$this->getOutput()->addWikiMsg( 'interwiki-local-description' );
} else {
$this->getOutput()->addHTML(
'<h2 id="interwikitable-local">' .
$this->msg( 'interwiki-links' )->parse() .
'</h2>'
);
$this->getOutput()->addWikiMsg( 'interwiki-description' );
}
$this->makeTable( $canModify, $iwLocalPrefixes );
}
// Add the language table
if ( count( $iwLanguagePrefixes ) !== 0 ) {
$this->getOutput()->addHTML(
'<h2 id="interwikitable-language">' .
$this->msg( 'interwiki-language-links' )->parse() .
'</h2>'
);
$this->getOutput()->addWikiMsg( 'interwiki-language-description' );
$this->makeTable( $canModify, $iwLanguagePrefixes );
}
}
function makeTable( $canModify, $iwPrefixes ) {
// Output the existing Interwiki prefixes table header // Output the existing Interwiki prefixes table header
$out = ''; $out = '';
$out .= Html::openElement( $out .= Html::openElement(
'table', 'table',
array( 'class' => 'mw-interwikitable wikitable sortable body' ) array( 'class' => 'mw-interwikitable wikitable sortable body' )
) . "\n"; ) . "\n";
$out .= Html::openElement( 'tr', array( 'id' => 'interwikitable-header' ) ) . $out .= Html::openElement( 'tr', array( 'class' => 'interwikitable-header' ) ) .
Html::element( 'th', null, $this->msg( 'interwiki_prefix' )->text() ) . Html::element( 'th', null, $this->msg( 'interwiki_prefix' )->text() ) .
Html::element( 'th', null, $this->msg( 'interwiki_url' )->text() ) . Html::element( 'th', null, $this->msg( 'interwiki_url' )->text() ) .
Html::element( 'th', null, $this->msg( 'interwiki_local' )->text() ) . Html::element( 'th', null, $this->msg( 'interwiki_local' )->text() ) .

View file

@ -3,7 +3,8 @@
"authors": [ "authors": [
"Stephanie Amanda Stevens", "Stephanie Amanda Stevens",
"SPQRobin", "SPQRobin",
"Purodha" "Purodha",
"Isarra"
] ]
}, },
"interwiki": "View and edit interwiki data", "interwiki": "View and edit interwiki data",
@ -38,7 +39,8 @@
"interwiki_deleting": "You are deleting prefix \"$1\".", "interwiki_deleting": "You are deleting prefix \"$1\".",
"interwiki_deleted": "Prefix \"$1\" was successfully removed from the interwiki table.", "interwiki_deleted": "Prefix \"$1\" was successfully removed from the interwiki table.",
"interwiki_delfailed": "Prefix \"$1\" could not be removed from the interwiki table.", "interwiki_delfailed": "Prefix \"$1\" could not be removed from the interwiki table.",
"interwiki_addtext": "Add an interwiki prefix", "interwiki_addtext": "Add an interwiki or language prefix",
"interwiki-addtext-local": "Add a local interwiki or language prefix",
"interwiki_addintro": "You are adding a new interwiki prefix.\nRemember that it cannot contain spaces ( ), colons (:), ampersands (&), or equal signs (=).", "interwiki_addintro": "You are adding a new interwiki prefix.\nRemember that it cannot contain spaces ( ), colons (:), ampersands (&), or equal signs (=).",
"interwiki_addbutton": "Add", "interwiki_addbutton": "Add",
"interwiki_added": "Prefix \"$1\" was successfully added to the interwiki table.", "interwiki_added": "Prefix \"$1\" was successfully added to the interwiki table.",
@ -58,5 +60,13 @@
"log-description-interwiki": "This is a log of changes to the [[Special:Interwiki|interwiki table]].", "log-description-interwiki": "This is a log of changes to the [[Special:Interwiki|interwiki table]].",
"logentry-interwiki-interwiki": "", "logentry-interwiki-interwiki": "",
"right-interwiki": "Edit interwiki data", "right-interwiki": "Edit interwiki data",
"action-interwiki": "change this interwiki entry" "action-interwiki": "change this interwiki entry",
"interwiki-global-links": "Global interwiki prefixes",
"interwiki-global-description": "These prefixes are inherited from a global configuration, and can only be edited on the source wiki.",
"interwiki-local-links": "Local interwiki prefixes",
"interwiki-local-description": "These prefixes exist locally. Any duplicates with the global configuration will override the global definiton.",
"interwiki-links": "Interwiki prefixes",
"interwiki-description": "",
"interwiki-language-links": "Interlanguage prefixes",
"interwiki-language-description": "These prefixes match defined language codes, and will be used to create the 'in other languages' listing when added to a page."
} }

View file

@ -12,7 +12,8 @@
"SPQRobin", "SPQRobin",
"Shirayuki", "Shirayuki",
"Siebrand", "Siebrand",
"Umherirrender" "Umherirrender",
"Isarra"
] ]
}, },
"interwiki": "{{doc-special|Interwiki}}", "interwiki": "{{doc-special|Interwiki}}",
@ -48,6 +49,7 @@
"interwiki_deleted": "Used as success message. Parameters:\n* $1 - interwiki prefix", "interwiki_deleted": "Used as success message. Parameters:\n* $1 - interwiki prefix",
"interwiki_delfailed": "Error message when removing an interwiki table entry fails. Parameters:\n* $1 is an interwiki prefix.", "interwiki_delfailed": "Error message when removing an interwiki table entry fails. Parameters:\n* $1 is an interwiki prefix.",
"interwiki_addtext": "Link description to open form to add an interwiki prefix.", "interwiki_addtext": "Link description to open form to add an interwiki prefix.",
"interwiki-addtext-local": "Link description for wikis with global interwikis to open form to add a local interwiki prefix.",
"interwiki_addintro": "Form information when adding an interwiki prefix.", "interwiki_addintro": "Form information when adding an interwiki prefix.",
"interwiki_addbutton": "This message is the text of the button to submit the interwiki prefix you are adding.\n\n{{Identical|Add}}", "interwiki_addbutton": "This message is the text of the button to submit the interwiki prefix you are adding.\n\n{{Identical|Add}}",
"interwiki_added": "Success message after adding an interwiki prefix. Parameters:\n* $1 is the added interwiki prefix.", "interwiki_added": "Success message after adding an interwiki prefix. Parameters:\n* $1 is the added interwiki prefix.",
@ -67,5 +69,13 @@
"log-description-interwiki": "Part of the interwiki extension. Summary shown on [[Special:Log/interwiki]].", "log-description-interwiki": "Part of the interwiki extension. Summary shown on [[Special:Log/interwiki]].",
"logentry-interwiki-interwiki": "{{notranslate}}", "logentry-interwiki-interwiki": "{{notranslate}}",
"right-interwiki": "{{doc-right|interwiki}}", "right-interwiki": "{{doc-right|interwiki}}",
"action-interwiki": "{{doc-action|interwiki}}" "action-interwiki": "{{doc-action|interwiki}}",
"interwiki-global-links": "Used on [[Special:Interwiki]] as header text for global interwiki prefix table",
"interwiki-global-description": "Appears under the interwiki-global-links header on [[Special:Interwiki]]; explains the distinction between global and local tables",
"interwiki-local-links": "Used on [[Special:Interwiki]] as header text for local interwiki prefix table if a global table is also present",
"interwiki-local-description": "Appears under the interwiki-local-links header on [[Special:Interwiki]]Used on [[Special:Interwiki]]; explains what the local table does",
"interwiki-links": "Used on [[Special:Interwiki]] as header text for interwiki prefix table if no global table is present",
"interwiki-description": "{{notranslate}}\nAppears under the interwiki-links header on [[Special:Interwiki]]",
"interwiki-language-links": "Used on [[Special:Interwiki]] as header text for interwiki language prefix table",
"interwiki-language-description": "Appears under the interwiki-language-links header on [[Special:Interwiki]]; explains what interlanguage links do"
} }