r91627 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r91626‎ | r91627 | r91628 >
Date:00:49, 7 July 2011
Author:aigerim
Status:deferred (Comments)
Tags:
Comment:
Initial import of GSoC project.
Modified paths:
  • /trunk/extensions/ExtensionManagement (added) (history)
  • /trunk/extensions/ExtensionManagement/ExtensionManagement.alias.php (added) (history)
  • /trunk/extensions/ExtensionManagement/ExtensionManagement.i18n.php (added) (history)
  • /trunk/extensions/ExtensionManagement/ExtensionManagement.php (added) (history)
  • /trunk/extensions/ExtensionManagement/ExtensionManagement_body.php (added) (history)
  • /trunk/extensions/ExtensionManagement/api (added) (history)
  • /trunk/extensions/ExtensionManagement/extensionmanagement.sql (added) (history)
  • /trunk/extensions/ExtensionManagement/includes (added) (history)
  • /trunk/extensions/ExtensionManagement/includes/EMSubversion.php (added) (history)
  • /trunk/extensions/ExtensionManagement/specials (added) (history)
  • /trunk/extensions/ExtensionManagement/specials/SpecialExtensionManagement.php (added) (history)

Diff [purge]

Index: trunk/extensions/ExtensionManagement/ExtensionManagement.php
@@ -0,0 +1,77 @@
 2+<?php
 3+
 4+/**
 5+ * Initialization file for the ExtensionManagement extension.
 6+ * Extension documentation: http://www.mediawiki.org/wiki/Extension:ExtensionManagement
 7+ *
 8+ * @file extensionManagement.php
 9+ * @ingroup ExtensionManagement
 10+ */
 11+
 12+// Alert the user that this is not a valid entry point to MediaWiki if they try to access the special pages file directly.
 13+if (!defined('MEDIAWIKI')) {
 14+ echo <<<EOT
 15+To install this extension, put the following line in LocalSettings.php:
 16+require_once( "\$IP/extensions/ExtensionManagement/ExtensionManagement.php" );
 17+EOT;
 18+ exit( 1 );
 19+}
 20+
 21+$wgExtensionCredits['specialpage'][] = array(
 22+ 'path' => __FILE__,
 23+ 'name' => 'ExtensionManagement',
 24+ 'author' => array('aigerim'),
 25+ 'url' => 'http://www.mediawiki.org/wiki/Extension:ExtensionManagement',
 26+ 'description' => 'Extension for displaying installed extension information.',
 27+ 'descriptionmsg' => 'extensionmanagement-desc',
 28+);
 29+
 30+$dir = dirname(__FILE__) . '/';
 31+
 32+// Register the internalization and aliasing files
 33+$wgExtensionMessagesFiles['ExtensionManagement'] = $dir . 'ExtensionManagement.i18n.php';
 34+$wgExtensionAliasesFiles['ExtensionManagement'] = $dir . 'ExtensionManagement.alias.php';
 35+
 36+// Load classes
 37+$wgAutoloadClasses['ExtensionManagement'] = $dir . 'ExtensionManagement.php';
 38+$wgAutoloadClasses['ExtensionManagementPage'] = $dir . 'ExtensionManagement_body.php';
 39+$wgAutoloadClasses['EMSubversion'] = $dir . 'includes/EMSubversion.php';
 40+
 41+// Special pages
 42+$wgSpecialPages['ExtensionManagement'] = 'SpecialExtensionManagement';
 43+$wgAutoloadClasses['SpecialExtensionManagement'] = $dir . 'specials/SpecialExtensionManagement.php';
 44+//$wgSpecialPageGroups['ExtensionManagement'] = 'other';
 45+
 46+// API modules
 47+
 48+// Hook registration
 49+$wgHooks['LoadExtensionSchemaUpdates'][] = 'efExtensionMgmtSchemaUpdate';
 50+
 51+/**
 52+ * LoadExtensionSchemaUpdates hook
 53+ *
 54+ */
 55+function efExtensionMgmtSchemaUpdate( $updater = null ) {
 56+ if ( $updater === null ) {
 57+ global $wgExtNewTables;
 58+ $wgExtNewTables[] = array(
 59+ 'extensionmanagement', dirname( __FILE__ ) . '/extensionmanagement.sql'
 60+ );
 61+ $wgExtNewTables[] = array(
 62+ 'extensionmanagement_versions', dirname( __FILE__ ) . '/extensionmanagement.sql'
 63+ );
 64+ $wgExtNewTables[] = array(
 65+ 'extensionmanagement_mwreleases', dirname( __FILE__ ) . '/extensionmanagement.sql'
 66+ );
 67+ } else {
 68+ $updater->addExtensionUpdate( array( 'addTable', 'extensionmanagement',
 69+ dirname( __FILE__ ) . '/extensionmanagement.sql', true ) );
 70+ $updater->addExtensionUpdate( array( 'addTable', 'extensionmanagement_versions',
 71+ dirname( __FILE__ ) . '/extensionmanagement.sql', true ) );
 72+ $updater->addExtensionUpdate( array( 'addTable', 'extensionmanagement_mwreleases',
 73+ dirname( __FILE__ ) . '/extensionmanagement.sql', true ) );
 74+ }
 75+ return true;
 76+}
 77+
 78+?>
Index: trunk/extensions/ExtensionManagement/specials/SpecialExtensionManagement.php
@@ -0,0 +1,213 @@
 2+<?php
 3+
 4+/**
 5+ * A special page that displays installed extensions.
 6+ * Based on Special:Version.
 7+ *
 8+ * @ingroup ExtensionManagement
 9+ * @ingroup SpecialPage
 10+ */
 11+
 12+class SpecialExtensionManagement extends SpecialPage {
 13+
 14+ private $firstExtOpened = true;
 15+
 16+ static $viewvcUrls = array(
 17+ 'svn+ssh://svn.wikimedia.org/svnroot/mediawiki' => 'http://svn.wikimedia.org/viewvc/mediawiki',
 18+ 'http://svn.wikimedia.org/svnroot/mediawiki' => 'http://svn.wikimedia.org/viewvc/mediawiki',
 19+ # Doesn't work at the time of writing but maybe some day:
 20+ 'https://svn.wikimedia.org/viewvc/mediawiki' => 'http://svn.wikimedia.org/viewvc/mediawiki',
 21+ );
 22+
 23+ function __construct() {
 24+ parent::__construct( 'ExtensionManagement' );
 25+ }
 26+
 27+
 28+ function execute( $par ) {
 29+ global $wgOut, $wgMessageCache, $wgContLang;
 30+ $wgMessageCache->loadAllMessages();
 31+
 32+ $this->setHeaders();
 33+ $this->outputHeader();
 34+
 35+ $wgOut->addHTML( Xml::openElement( 'div',
 36+ array( 'dir' => $wgContLang->getDir() ) ) );
 37+ $wgOut->addWikiMsgArray( 'extensionmanagement-page-explanation', '' );
 38+
 39+ $text =
 40+ $this->displayExtensions();
 41+
 42+ $wgOut->addWikiText( $text );
 43+ $wgOut->addHTML( '</div>' );
 44+ }
 45+
 46+
 47+ function displayExtensions() {
 48+ global $wgOut, $wgExtensionCredits;
 49+
 50+ $extensionAmount = 0;
 51+
 52+ $extensionTypes = array(
 53+ 'specialpage' => wfMsg( 'version-specialpages' ),
 54+ 'parserhook' => wfMsg( 'version-parserhooks' ),
 55+ 'variable' => wfMsg( 'version-variables' ),
 56+ 'media' => wfMsg( 'version-mediahandlers' ),
 57+ 'other' => wfMsg( 'version-other' ),
 58+ );
 59+
 60+ $out = Xml::element( 'h2', array( 'id' => 'mw-version-ext' ), wfMsg( 'version-extensions' ) ) .
 61+ Xml::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-ext' ) );
 62+
 63+ foreach ( $extensionTypes as $type => $text ) {
 64+ if ( isset ( $wgExtensionCredits[$type] ) && count ( $wgExtensionCredits[$type] ) ) {
 65+ $out .= $this->openExtType( $text, 'credits-' . $type );
 66+
 67+ usort( $wgExtensionCredits[$type], array( $this, 'compare' ) );
 68+
 69+ foreach ( $wgExtensionCredits[$type] as $extension ) {
 70+ $out .= $this->formatCredits( $extension );
 71+ }
 72+ }
 73+ }
 74+ //$wgOut->addWikiText( $out );
 75+ $out .= Xml::closeElement( 'table' );
 76+ return $out;
 77+ }
 78+
 79+ private function openExtType( $text, $name = null ) {
 80+ $out = '';
 81+ $opt = array( 'colspan' => 2 );
 82+
 83+ if( !$this->firstExtOpened ) {
 84+ // Insert a spacing line
 85+ $out .= '<tr class="sv-space">' . Xml::element( 'td', $opt ) . "</tr>\n";
 86+ }
 87+ $this->firstExtOpened = false;
 88+
 89+ if( $name )
 90+ $opt['id'] = "sv-$name";
 91+
 92+ $out .= "<tr>" . Xml::element( 'th', $opt, $text ) . "</tr>\n";
 93+ return $out;
 94+ }
 95+
 96+ /** Callback to sort extensions by type */
 97+ function compare( $a, $b ) {
 98+ global $wgLang;
 99+ if( $a['name'] === $b['name'] ) {
 100+ return 0;
 101+ } else {
 102+ return $wgLang->lc( $a['name'] ) > $wgLang->lc( $b['name'] )
 103+ ? 1
 104+ : -1;
 105+ }
 106+ }
 107+ function formatCredits( $extension ) {
 108+ $out = '';
 109+ $name = isset( $extension['name'] ) ? $extension['name'] : '[no name]';
 110+
 111+ if ( isset( $extension['path'] ) ) {
 112+ $svnInfo = SpecialVersion::getSvnInfo( dirname($extension['path']) );
 113+ $directoryRev = isset( $svnInfo['directory-rev'] ) ? $svnInfo['directory-rev'] : null;
 114+ $checkoutRev = isset( $svnInfo['checkout-rev'] ) ? $svnInfo['checkout-rev'] : null;
 115+ $viewvcUrl = isset( $svnInfo['viewvc-url'] ) ? $svnInfo['viewvc-url'] : null;
 116+ } else {
 117+ $directoryRev = null;
 118+ $checkoutRev = null;
 119+ $viewvcUrl = null;
 120+ }
 121+
 122+ # Make main link (or just the name if there is no URL)
 123+ if ( isset( $extension['url'] ) ) {
 124+ $mainLink = "[{$extension['url']} $name]";
 125+ } else {
 126+ $mainLink = $name;
 127+ }
 128+ # Version
 129+ if ( isset( $extension['version'] ) ) {
 130+ $versionText = '<span class="mw-version-ext-version"><em>' .
 131+ wfMsg( 'version-version', $extension['version'] ) .
 132+ '</em></span> | ';
 133+ } else {
 134+ $versionText = '';
 135+ }
 136+ /*
 137+ if ( $checkoutRev ) {
 138+ $svnText = wfMsg( 'version-svn-revision', $directoryRev, $checkoutRev );
 139+ $svnText = isset( $viewvcUrl ) ? "[$viewvcUrl $svnText]" : $svnText;
 140+ } else {
 141+ $svnText = false;
 142+ }*/
 143+
 144+ # Make description text
 145+ $description = isset ( $extension['description'] ) ? $extension['description'] : '';
 146+ if( isset ( $extension['descriptionmsg'] ) ) {
 147+ # Look for a localized description
 148+ $descriptionMsg = $extension['descriptionmsg'];
 149+ if( is_array( $descriptionMsg ) ) {
 150+ $descriptionMsgKey = $descriptionMsg[0]; // Get the message key
 151+ array_shift( $descriptionMsg ); // Shift out the message key to get the parameters only
 152+ array_map( "htmlspecialchars", $descriptionMsg ); // For sanity
 153+ $msg = wfMsg( $descriptionMsgKey, $descriptionMsg );
 154+ } else {
 155+ $msg = wfMsg( $descriptionMsg );
 156+ }
 157+ if ( !wfEmptyMsg( $descriptionMsg, $msg ) && $msg != '' ) {
 158+ $description = $msg;
 159+ }
 160+ }
 161+ $author = isset ( $extension['author'] ) ? $extension['author'] : array();
 162+ $extDescAuthor = "<td>$description <br />". $versionText . $this->listToText( (array)$author, false ) . "</td>
 163+ </tr>\n";
 164+
 165+ $extNameVer = "<tr>
 166+ <td><em>$mainLink</em></td>";
 167+
 168+ return $extNameVer.$extDescAuthor;
 169+ }
 170+ /**
 171+ * @param array $list
 172+ * @param bool $sort
 173+ * @return string
 174+ */
 175+ function listToText( $list, $sort = true ) {
 176+ $cnt = count( $list );
 177+
 178+ if ( $cnt == 1 ) {
 179+ // Enforce always returning a string
 180+ return (string)self::arrayToString( $list[0] );
 181+ } elseif ( $cnt == 0 ) {
 182+ return '';
 183+ } else {
 184+ global $wgLang;
 185+ if ( $sort ) {
 186+ sort( $list );
 187+ }
 188+ return $wgLang->listToText( array_map( array( __CLASS__, 'arrayToString' ), $list ) );
 189+ }
 190+ }
 191+
 192+ /**
 193+ * @param mixed $list Will convert an array to string if given and return
 194+ * the paramater unaltered otherwise
 195+ * @return mixed
 196+ */
 197+ static function arrayToString( $list ) {
 198+ if( is_array( $list ) && count( $list ) == 1 )
 199+ $list = $list[0];
 200+ if( is_object( $list ) ) {
 201+ $class = get_class( $list );
 202+ return "($class)";
 203+ } elseif ( !is_array( $list ) ) {
 204+ return $list;
 205+ } else {
 206+ if( is_object( $list[0] ) )
 207+ $class = get_class( $list[0] );
 208+ else
 209+ $class = $list[0];
 210+ return "($class, {$list[1]})";
 211+ }
 212+ }
 213+}
 214+?>
Index: trunk/extensions/ExtensionManagement/includes/EMSubversion.php
Index: trunk/extensions/ExtensionManagement/ExtensionManagement.alias.php
@@ -0,0 +1,12 @@
 2+<?php
 3+/**
 4+ * Special page aliases for the ExtensionManagement extension.
 5+ *
 6+ * @file ExtensionManagement.i18n.php
 7+ */
 8+
 9+$specialPageAliases = array();
 10+
 11+$specialPageAliases['en'] = array(
 12+ 'ExtensionManagement' => array( 'ExtensionManagement' ),
 13+);
Index: trunk/extensions/ExtensionManagement/extensionmanagement.sql
@@ -0,0 +1,41 @@
 2+-- MySQL database schema for the Extension Management extension.
 3+
 4+CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/extensionmanagement (
 5+ ext_id INT(8) unsigned NOT NULL auto_increment PRIMARY KEY,
 6+ ext_name VARCHAR(255) NOT NULL,
 7+ ext_url VARCHAR(255) NULL,
 8+ -- Latest stable release
 9+ ext_current INT(8) unsigned NOT NULL,
 10+ -- Info of the latest stable release
 11+ current_desc BLOB NOT NULL,
 12+ current_authors BLOB NOT NULL
 13+) /*$wgDBTableOptions*/;
 14+
 15+CREATE UNIQUE INDEX unit_name ON /*$wgDBprefix*/extensionmanagement (ext_name);
 16+
 17+-- Specific versions of extensions
 18+CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/extensionmanagement_versions (
 19+ version_id INT(8) unsigned NOT NULL auto_increment PRIMARY KEY,
 20+
 21+ version_ext_id INT(8) unsigned NOT NULL,
 22+ FOREIGN KEY (version_ext_id) REFERENCES /*$wgDBprefix*/extensionmanagement (ext_id),
 23+
 24+ version_status TINYINT unsigned NOT NULL,
 25+ version_release_date CHAR(14) binary NOT NULL default '',
 26+ version_directory VARCHAR(255) NOT NULL,
 27+ version_entrypoint VARCHAR(255) NOT NULL,
 28+ version_desc BLOB NOT NULL,
 29+ version_authors BLOB NOT NULL
 30+) /*$wgDBTableOptions*/;
 31+
 32+CREATE TABLE IF NOT EXISTS /*_*/extensionmanagement_mwreleases (
 33+ mwr_id int(10) unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
 34+ mwr_name varchar(255) NOT NULL,
 35+ mwr_number varchar(32) NOT NULL,
 36+ mwr_reldate varbinary(32) DEFAULT NULL,
 37+ mwr_eoldate varbinary(32) DEFAULT NULL,
 38+ mwr_branch varchar(32) NOT NULL,
 39+ mwr_tag varchar(32) NOT NULL,
 40+ mwr_announcement varchar(255) DEFAULT NULL,
 41+ mwr_supported int(1) NOT NULL
 42+) /*$wgDBTableOptions*/;
Index: trunk/extensions/ExtensionManagement/ExtensionManagement_body.php
Index: trunk/extensions/ExtensionManagement/ExtensionManagement.i18n.php
@@ -0,0 +1,17 @@
 2+<?php
 3+$aliases = array();
 4+$messages = array();
 5+
 6+$aliases['en'] = array(
 7+ 'ExtensionManagement' => array( 'ExtensionManagement' ),
 8+);
 9+
 10+$messages['en'] = array(
 11+ 'extensionmanagement' => 'Extension Management',
 12+ 'extensionmanagement-desc' => 'TBA',
 13+
 14+ //Special:ExtensionManagement
 15+ 'extensionmanagement-page-explanation' => 'This page shows all extensions installed on this wiki.
 16+For more info about this wiki installation, see [[Special:Version|{{int:version}}]].',
 17+);
 18+?>

Follow-up revisions

RevisionCommit summaryAuthorDate
r91628Followup r91627...reedy04:37, 7 July 2011

Comments

#Comment by 😂 (talk | contribs)   15:02, 11 July 2011

This is the review of your proposed schema:

  • I see you used my old mwreleases schema for tracking MediaWiki core releases. Good, because I liked it :)
  • For all the tables: we could probably drop the (8) and (10) for our id columns. They're unsigned anyway.
  • Also, adding some more comments about what the columns do will help answer questions too.
  • Looking at 'extensionmanagement', there's a couple of things:
    • We try to name all columns in a table with the same prefix, so it would be good to rename current_desc and current_authors to begin with "ext_"
    • Is current_desc supposed to be a short one or two sentence summary of the extension? If so then that seems fine.
    • current_authors is a BLOB. How were you planning on storing the information here? Presumably we'd be wanting to store user_ids of the Mediawiki.org users who are maintaining an extension. If that's the case, I would suggest moving this to its own table called extension_authors or similar. This would let you have columns like (ext_id,user_id) which is good form in database design and allows you to do queries like "Name all of the extensions user 123 helps maintain." Still having a column for the primary maintainer/owner in this table does sound like a good idea though
  • Couple of notes on 'extensionmanagement_versions':
    • We don't use foreign keys in Mysql in MediaWiki. Enforce this logic in your code.
    • What is version_status tracking?
    • version_release_date should be varbinary(32) like I did in mwreleases.
    • is version_directory the directory name in SVN?
    • version_entrypoint -- I'm pretty sure this is for tracking what entry point we would put in LocalSettings for enabling an extension. Since 1.17, we've tried very hard to enforce the extensions/FooBar/FooBar.php naming convention, so I'm not sure this is really necessary to track.

This is a great first draft though, thanks for getting it into SVN!

Status & tagging log