r60172 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r60171‎ | r60172 | r60173 >
Date:20:01, 17 December 2009
Author:maxsem
Status:deferred (Comments)
Tags:
Comment:
Added GNSM extension, posted by Amgine as bug 20818 attachment. Not ready for production yet.
Modified paths:
  • /trunk/extensions/GNSM (added) (history)
  • /trunk/extensions/GNSM/SpecialGNSM.alias.php (added) (history)
  • /trunk/extensions/GNSM/SpecialGNSM.i18n.php (added) (history)
  • /trunk/extensions/GNSM/SpecialGNSM.php (added) (history)
  • /trunk/extensions/GNSM/SpecialGNSM_body.php (added) (history)

Diff [purge]

Index: trunk/extensions/GNSM/SpecialGNSM.alias.php
@@ -0,0 +1,42 @@
 2+<?php
 3+/**
 4+ * Aliases for Special:Editcount
 5+ *
 6+ * @addtogroup Extensions
 7+ */
 8+
 9+/**
 10+ * Deutsch
 11+ * @author Amgine
 12+ **/
 13+$aliases['de'] = array(
 14+ 'GNSM' => array( 'SpezialGNSM' )
 15+);
 16+
 17+/** English
 18+ * @author Amgine
 19+ **/
 20+$aliases['en'] = array(
 21+ 'GNSM' => array( 'Google News SiteMap', 'SpecialGNSM' ),
 22+);
 23+
 24+/** Fran�ais
 25+ * @author Amgine
 26+ **/
 27+$aliases['fr'] = array(
 28+ 'GNSM' => array( 'GNSMSp�cial' ),
 29+);
 30+
 31+/** Nederlands
 32+ * @author Amgine
 33+ **/
 34+$aliases['nl'] = array(
 35+ 'GNSM' => array( 'GNSMSpeciaal' )
 36+);
 37+
 38+/** Norsk (bokm�l)
 39+ * @author Amgine
 40+ **/
 41+$aliases['no'] = array(
 42+ 'GNSM' => array( 'SpesialGNSM' ),
 43+);
\ No newline at end of file
Property changes on: trunk/extensions/GNSM/SpecialGNSM.alias.php
___________________________________________________________________
Name: svn:eol-style
144 + native
Index: trunk/extensions/GNSM/SpecialGNSM_body.php
@@ -0,0 +1,637 @@
 2+<?php
 3+if (!defined('MEDIAWIKI')) die();
 4+
 5+/**
 6+ * Class GNSM creates Atom/RSS feeds for Wikinews
 7+ **
 8+ * Simple feed using Atom/RSS coupled to DynamicPageList category searching.
 9+ *
 10+ * To use: http://wiki.url/Special:GNSM/[paramter=value][...]
 11+ *
 12+ * Implemented parameters are marked with an @
 13+ **
 14+ * Parameters
 15+ * * category = string ; default = Published
 16+ * * notcategory = string ; default = null
 17+ * * namespace = string ; default = null
 18+ * * count = integer ; default = $wgDPLmaxResultCount = 50
 19+ * * order = string ; default = descending
 20+ * * ordermethod = string ; default = categoryadd
 21+ * * redirects = string ; default = exclude
 22+ * * stablepages = string ; default = null
 23+ * * qualitypages = string ; default = null
 24+ * * feed = string ; default = atom
 25+ * usenamespace = bool ; default = false
 26+ * usecurid = bool ; default = false
 27+ * suppresserrors = bool ; default = false
 28+ **/
 29+
 30+class GNSM extends IncludableSpecialPage {
 31+
 32+
 33+ /**
 34+ * FIXME: Some of this might need a config eventually
 35+ * @var string
 36+ **/
 37+ var $Title = '';
 38+ var $Description = '';
 39+ var $Url = '';
 40+ var $Date = '';
 41+ var $Author = '';
 42+ var $pubDate = '';
 43+ var $keywords = '';
 44+ var $lastMod = '';
 45+ var $priority = '';
 46+
 47+ /**
 48+ * Script default values - correctly spelt, naming standard.
 49+ **/
 50+ var $wgDPlminCategories = 1; // Minimum number of categories to look for
 51+ var $wgDPlmaxCategories = 6; // Maximum number of categories to look for
 52+ var $wgDPLminResultCount = 1; // Minimum number of results to allow
 53+ var $wgDPLmaxResultCount = 50; // Maximum number of results to allow
 54+ var $wgDPLallowUnlimitedResults = true; // Allow unlimited results
 55+ var $wgDPLallowUnlimitedCategories = false; // Allow unlimited categories
 56+
 57+
 58+ /**
 59+ * @var array Parameters array
 60+ **/
 61+ var $params = array();
 62+ var $categories = array();
 63+ var $notCategories = array();
 64+
 65+ /**
 66+ * Constructor
 67+ **/
 68+ public function __construct() {
 69+ parent::__construct( 'GNSM' );
 70+ }
 71+
 72+ /**
 73+ * main()
 74+ **/
 75+ public function execute( $par ) {
 76+ global $wgUser;
 77+ global $wgLang;
 78+ global $wgContLang;
 79+ global $wgRequest, $wgOut;
 80+ global $wgSitename, $wgServer, $wgScriptPath;
 81+// global $wfTimeStamp;
 82+ wfLoadExtensionMessages( 'GNSM' );
 83+ global $wgFeedClasses, $wgLocaltimezone;
 84+
 85+ // Not sure how clean $wgLocaltimezone is
 86+ // In fact, it's default setting is null...
 87+ if ( null == $wgLocaltimezone )
 88+ $wgLocaltimezone = date_default_timezone_get();
 89+ date_default_timezone_set( $wgLocaltimezone );
 90+ //$url = __FILE__;
 91+
 92+ $this->dpl_parm( $par );
 93+
 94+
 95+ $wgFeedClasses[] = array( 'sitemap' => 'SitemapFeed' );
 96+
 97+ if ( 'sitemap' == $this->params['feed'] ){
 98+ $feed = new SitemapFeed(
 99+ $wgServer.$wgScriptPath,
 100+ date( DATE_ATOM )
 101+ );
 102+ }else{
 103+ // FIXME: These should be configurable at some point
 104+ $feed = new $wgFeedClasses[ $this->params['feed'] ](
 105+ $wgSitename,
 106+ $wgSitename . ' ' . $this->params['feed'] . ' feed',
 107+ $wgServer.$wgScriptPath,
 108+ date( DATE_ATOM ),
 109+ $wgSitename
 110+ );
 111+ }
 112+
 113+ $feed->outHeader();
 114+
 115+ // main routine to output items
 116+ if ( isset( $this->param['error'] ) ){
 117+ echo $this->param['error'];
 118+ }else{
 119+ $dbr =& wfGetDB( DB_SLAVE );
 120+ $sql = $this->dpl_buildSQL();
 121+ //Debug line
 122+ //echo "\n<p>$sql</p>\n";
 123+ $res = $dbr->query ( $sql );
 124+
 125+ // FIXME: figure out how to fail with no results gracefully
 126+ if ( $dbr->numRows( $res ) == 0 ){
 127+ if ( false == $this->params['suppressErrors'] )
 128+ return htmlspecialchars( wfMsg( 'gnsm_noresults' ) );
 129+ else
 130+ return '';
 131+ }
 132+
 133+ while ($row = $dbr->fetchObject( $res ) ) {
 134+ $title = Title::makeTitle( $row->page_namespace, $row->page_title);
 135+
 136+ if ( $title ){
 137+ print $this->params['nameSpace'];
 138+
 139+ $titleText = ( true == $this->params['nameSpace'] ) ? $title->getPrefixedText() : $title->getText();
 140+
 141+ if ( 'sitemap' == $this->params['feed'] ){
 142+
 143+ $this->pubDate = isset( $row->cl_timestamp ) ? $row->cl_timestamp : date( DATE_ATOM );
 144+ $feedArticle = new Article( $title );
 145+
 146+ $feedItem = new feedSMItem(
 147+ trim( $title->getFullURL() ),
 148+ wfTimeStamp( TS_ISO_8601, $this->pubDate ),
 149+ $this->getKeywords( $title ),
 150+ wfTimeStamp( TS_ISO_8601, $feedArticle->getTouched() ),
 151+ $feed->getPriority( $this->priority )
 152+ );
 153+
 154+ }elseif ( ('atom' == $this->params['feed'] ) || ( 'rss' == $this->params['feed'] ) ){
 155+
 156+ $this->Date = isset( $row->cl_timestamp ) ? $row->cl_timestamp : date( DATE_ATOM );
 157+ if ( isset( $row->comment ) ){
 158+ $comments = htmlspecialchars( $row->comment );
 159+ }else{
 160+ $talkpage = $title->getTalkPage();
 161+ $comments = $talkpage->getFullURL();
 162+ }
 163+ $titleText = (true === $this->params['nameSpace'] ) ? $title->getPrefixedText() : $title->getText();
 164+ $feedItem = new FeedItem(
 165+ $titleText,
 166+ $this->feedItemDesc( $row ),
 167+ $title->getFullURL(),
 168+ $this->Date,
 169+ $this->feedItemAuthor( $row ),
 170+ $comments);
 171+ }
 172+ $feed->outItem( $feedItem );
 173+ }
 174+ }
 175+ }
 176+ $feed->outFooter();
 177+ }
 178+
 179+ /**
 180+ * Build sql
 181+ **/
 182+ public function dpl_buildSQL(){
 183+
 184+ $sqlSelectFrom = 'SELECT page_namespace, page_title, page_id, c1.cl_timestamp FROM ' . $this->params['dbr']->tableName( 'page' );
 185+
 186+ if ( $this->params['nameSpace'] ){
 187+ $sqlWhere = ' WHERE page_namespace=' . $this->params['iNameSpace'] . ' ';
 188+ }else{
 189+ $sqlWhere = ' WHERE 1=1 ';
 190+ }
 191+
 192+ // If flagged revisions is in use, check which options selected.
 193+ // FIXME: double check the default options in function::dpl_parm; what should it default to?
 194+ if( function_exists('efLoadFlaggedRevs') ) {
 195+ $flaggedPages = $this->params['dbr']->tableName( 'flaggedpages' );
 196+ $filterSet = array( 'only', 'exclude' );
 197+ # Either involves the same JOIN here...
 198+ if( in_array( $this->params['stable'], $filterSet ) || in_array( $this->params['quality'], $filterSet ) ) {
 199+ $sqlSelectFrom .= " LEFT JOIN $flaggedPages ON page_id = fp_page_id";
 200+ }
 201+ switch( $this->params['stable'] ){
 202+ case 'only':
 203+ $sqlWhere .= ' AND fp_stable IS NOT NULL ';
 204+ break;
 205+ case 'exclude':
 206+ $sqlWhere .= ' AND fp_stable IS NULL ';
 207+ break;
 208+ }
 209+ switch( $this->params['quality'] ){
 210+ case 'only':
 211+ $sqlWhere .= ' AND fp_quality >= 1';
 212+ break;
 213+ case 'exclude':
 214+ $sqlWhere .= ' AND fp_quality = 0';
 215+ break;
 216+ }
 217+ }
 218+
 219+ switch ( $this->params['redirects'] )
 220+ {
 221+ case 'only':
 222+ $sqlWhere .= ' AND page_is_redirect = 1 ';
 223+ break;
 224+ case 'exclude':
 225+ $sqlWhere .= ' AND page_is_redirect = 0 ';
 226+ break;
 227+ }
 228+
 229+ $currentTableNumber = 0;
 230+
 231+ for ( $i = 0; $i < $this->params['catCount']; $i++ ){
 232+
 233+ $sqlSelectFrom .= ' INNER JOIN ' . $this->params['dbr']->tableName( 'categorylinks' );
 234+ $sqlSelectFrom .= ' AS c' . ( $currentTableNumber + 1 ) . ' ON page_id = c';
 235+ $sqlSelectFrom .= ( $currentTableNumber + 1 ) . '.cl_from AND c' . ( $currentTableNumber + 1 );
 236+
 237+ $sqlSelectFrom .= '.cl_to=' . $this->params['dbr']->addQuotes( $this->categories[$i]->getDBkey() );
 238+
 239+ $currentTableNumber++;
 240+ }
 241+
 242+ for ( $i = 0; $i < $this->params['notCatCount']; $i++ ){
 243+ //echo "notCategory parameter $i<br />\n";
 244+ $sqlSelectFrom .= ' LEFT OUTER JOIN ' . $this->params['dbr']->tableName( 'categorylinks' );
 245+ $sqlSelectFrom .= ' AS c' . ( $currentTableNumber + 1 ) . ' ON page_id = c' . ( $currentTableNumber + 1 );
 246+ $sqlSelectFrom .= '.cl_from AND c' . ( $currentTableNumber + 1 );
 247+ $sqlSelectFrom .= '.cl_to=' . $this->params['dbr']->addQuotes( $this->notCategories[$i]->getDBkey() );
 248+
 249+ $sqlWhere .= ' AND c' . ( $currentTableNumber + 1 ) . '.cl_to IS NULL';
 250+
 251+ $currentTableNumber++;
 252+ }
 253+
 254+ if ('lastedit' == $this->params['orderMethod'] )
 255+ $sqlWhere .= ' ORDER BY page_touched ';
 256+ else
 257+ $sqlWhere .= ' ORDER BY c1.cl_timestamp ';
 258+
 259+ if ( 'descending' == $this->params['order'] )
 260+ $sqlWhere .= 'DESC';
 261+ else
 262+ $sqlWhere .= 'ASC';
 263+
 264+ // FIXME: Note: this is not a boolean type check - will also trap count = 0 which may
 265+ // accidentally give unlimited returns
 266+ if ( 0 < $this->params['count'] ){
 267+ $sqlWhere .= ' LIMIT ' . $this->params['count'];
 268+ }
 269+
 270+ //debug line
 271+ //echo "<p>$sqlSelectFrom$sqlWhere;</p>\n";
 272+
 273+ return $sqlSelectFrom . $sqlWhere;
 274+ }
 275+
 276+ /**
 277+ * Parse parameters
 278+ **
 279+ * FIXME this includes a lot of DynamicPageList cruft in need of thinning.
 280+ **/
 281+ public function dpl_parm( $par ){
 282+ global $wgContLang;
 283+
 284+ $params = array();
 285+ // FIXME: note: if ( false === $count ) then no count has ever been set
 286+ // however, there's still no guarantee $count <> zero || NULL
 287+ $this->params['count'] = $this->wgDPLmaxResultCount;
 288+
 289+ $this->params['orderMethod'] = 'categoryadd';
 290+ $this->params['order'] = 'descending';
 291+ $this->params['redirects'] = 'exclude';
 292+ $this->params['stable'] = $quality = 'only';
 293+
 294+ $this->params['nameSpace'] = false;
 295+ $this->params['iNameSpace'] = 0;
 296+
 297+ $this->params['useNameSpace'] = false;
 298+ $this->params['useCurId'] = false;
 299+
 300+ $this->params['suppressErrors'] = false;
 301+
 302+ $this->params['feed'] = 'atom';
 303+
 304+ $params = explode( '&', $par );
 305+
 306+ $parser = new Parser;
 307+ $poptions = new ParserOptions;
 308+
 309+ foreach ( $params AS $paramString ){
 310+ $param = explode( '=', $paramString );
 311+
 312+ if ( count( $param ) < 2 ) continue;
 313+
 314+ // not sure this is necessary, or even would work
 315+ $param[0] = trim( $param[0] );
 316+ $param[1] = trim( $param[1] );
 317+
 318+ switch ( $param[0] ){
 319+ case 'category':
 320+ $title = Title::newFromText( $parser->transformMsg( $param[1], $poptions ) );
 321+
 322+ if ( is_object( $title ) ){
 323+ $this->categories[] = $title;
 324+ }else{
 325+ echo "Explode on category.\n";
 326+ continue;
 327+ }
 328+ break;
 329+ case 'notcategory':
 330+ //echo "Got notcategory $param[1]\n";
 331+ $title = Title::newFromText( $parser->transformMsg( $param[1], $poptions ) );
 332+ if ( is_object( $title ) )
 333+ $this->notCategories[] = $title;
 334+ else{
 335+ echo 'Explode on notCategory.';
 336+ continue;
 337+ }
 338+ break;
 339+ case 'namespace':
 340+ if ( $param[1] == intval( $param[1] ) ){
 341+ $this->params['iNameSpace'] = intval( $param[1] );
 342+ if ( 0 <= $this->params['iNameSpace'] ){
 343+ $this->params['nameSpace'] = true;
 344+ }else{
 345+ $this->params['nameSpace'] = false;
 346+ }
 347+ }else{
 348+ $ns = $wgContLang->getNsIndex( $param[1] );
 349+ if ( null !== $ns ){
 350+ $this->params['iNameSpace'] = $ns;
 351+ $this->params['nameSpace'] = true;
 352+ }
 353+ }
 354+ break;
 355+ case 'count':
 356+ if ( ( $this->wgDPLminResultCount < $param[1] ) && ( $param[1] < $this->wgDPLmaxResultCount ) ){
 357+ $this->params['count'] = intval( $param[1] );
 358+ }
 359+ break;
 360+ case 'order';
 361+ switch ( $param[1] ){
 362+ case 'ascending':
 363+ $this->params['order'] = 'ascending';
 364+ break;
 365+ case 'descending':
 366+ default:
 367+ $this->params['order'] = 'descending';
 368+ break;
 369+ }
 370+ break;
 371+ case 'ordermethod';
 372+ switch ( $param[1] ){
 373+ case 'lastedit':
 374+ $this->params['orderMethod'] = 'lastedit';
 375+ break;
 376+ case 'categoryadd':
 377+ default:
 378+ $this->params['orderMethod'] = 'categoryadd';
 379+ break;
 380+ }
 381+ break;
 382+ case 'redirects';
 383+ switch ( $param[1] ){
 384+ case 'include':
 385+ $this->params['redirects'] = 'include';
 386+ break;
 387+ case 'only':
 388+ $this->params['redirects'] = 'only';
 389+ break;
 390+ case 'exclude':
 391+ default:
 392+ $this->params['redirects'] = 'exclude';
 393+ break;
 394+ }
 395+ break;
 396+ case 'stablepages':
 397+ switch ( $param[1] ){
 398+ case 'include':
 399+ $this->params['stable'] = 'include';
 400+ break;
 401+ case 'exclude':
 402+ $this->params['stable'] = 'exclude';
 403+ break;
 404+ case 'only':
 405+ default:
 406+ $this->params['stable'] = 'only';
 407+ break;
 408+ }
 409+ break;
 410+ case 'qualitypages':
 411+ switch ( $param[1] ){
 412+ case 'include':
 413+ $this->params['quality'] = 'include';
 414+ break;
 415+ case 'only':
 416+ $this->params['quality'] = 'only';
 417+ break;
 418+ case 'exclude':
 419+ default:
 420+ $this->params['quality'] = 'exclude';
 421+ break;
 422+ }
 423+ break;
 424+ case 'suppresserrors':
 425+ // note: if previously set to true, remains true. malformed does not reset to false.
 426+ if ( 'true' == $param[1] ) $this->params['suppressErrors'] = true;
 427+ break;
 428+ case 'usenamespace':
 429+ // note: if previously set to false, remains false. Malformed does not reset to true.
 430+ if ( 'false' == $param[1] ) $this->params['useNameSpace'] = false;
 431+ break;
 432+ case 'usecurid':
 433+ // note: if previously set to true, remains true. Malformed does not reset to false.
 434+ if ( 'true' == $param[1] ) $this->params['useCurId'] = true;
 435+ break;
 436+ case 'feed':
 437+ $param[1] = strtolower( $param[1] );
 438+ switch( $param[1] ){
 439+ case 'rss':
 440+ $this->params['feed'] = 'rss';
 441+ break;
 442+ case 'sitemap':
 443+ $this->params['feed'] = 'sitemap';
 444+ break;
 445+ default:
 446+ $this->params['feed'] = 'atom';
 447+ break;
 448+ }
 449+ break;
 450+ default:
 451+
 452+ }
 453+ }
 454+
 455+ $this->params['catCount'] = count( $this->categories );
 456+ $this->params['notCatCount'] = count( $this->notCategories );
 457+ $totalCatCount = $this->params['catCount'] + $this->params['notCatCount'];
 458+
 459+ if (( $this->params['catCount'] < 1 && false == $this->params['nameSpace'] ) || ( $totalCatCount < $this->wgDPLminCategories )){
 460+ //echo "Boom on catCount\n";
 461+ $parser = new Parser;
 462+ $poptions = new ParserOptions;
 463+ $feed = Title::newFromText( $parser->transformMsg( 'Published', $poptions ) );
 464+ if ( is_object( $feed ) ){
 465+ $this->categories[] = $feed;
 466+ $this->params['catCount'] = count( $this->categories );
 467+ }else{
 468+ echo "\$feed is not an object.\n";
 469+ continue;
 470+ }
 471+ }
 472+
 473+ if ( ( $totalCatCount > $this->wgDPlmaxCategories ) && ( !$this->wgDPLallowUnlimitedCategories ) ){
 474+ $this->params['error'] = htmlspecialchars( wfMsg( 'intersection_toomanycats' ) ); // "!!too many categories!!";
 475+ }
 476+
 477+ //disallow showing date if the query doesn't have an inclusion category parameter
 478+ if ( $this->params['count'] < 1 )
 479+ $this->params['addFirstCategoryDate'] = false;
 480+
 481+ $this->params['dbr'] =& wfGetDB( DB_SLAVE );
 482+ return;
 483+ }
 484+
 485+ function feedItemAuthor( $row ) {
 486+ return isset( $row->user_text ) ? $row->user_text : 'Wikinews';
 487+ }
 488+
 489+ function feedItemDesc( $row ) {
 490+ return isset( $row->comment ) ? htmlspecialchars( $row->comment ) : '';
 491+ }
 492+
 493+ function getKeywords ( $title ){
 494+ $cats = $title->getParentCategories();
 495+ $str = '';
 496+ foreach ( $cats as $key => $val ){
 497+ $str .= ', ' . str_replace( '_', ' ', trim( substr( $key, strpos( $key, ':' ) + 1 ) ) );
 498+ }
 499+ $str = substr( $str, 2 );
 500+ return $str;
 501+ }
 502+
 503+}
 504+
 505+/**
 506+ * feedSMItem Class
 507+ **
 508+ * Base class for basic SiteMap support, for building url containers.
 509+ **/
 510+class feedSMItem{
 511+ /**
 512+ * Var string
 513+ **/
 514+ var $url = '';
 515+ var $pubDate = '';
 516+ var $keywords = '';
 517+ var $lastMod = '';
 518+ var $priority = '';
 519+
 520+ function __construct( $url, $pubDate, $keywords = '', $lastMod = '', $priority = ''){
 521+ $this->url = $url;
 522+ $this->pubDate = $pubDate;
 523+ $this->keywords = $keywords;
 524+ $this->lastMod = $lastMod;
 525+ $this->priority = $priority;
 526+ }
 527+
 528+ public function xmlEncode( $string ){
 529+ $string = str_replace( "\r\n", "\n", $string );
 530+ $string = preg_replace( '/[\x00-\x08\x0b\x0c\x0e-\x1f]/', '', $string );
 531+ return htmlspecialchars( $string );
 532+ }
 533+
 534+ public function getUrl(){
 535+ return $this->url;
 536+ }
 537+
 538+ public function getPriority(){
 539+ return $this->priority;
 540+ }
 541+
 542+ public function getLastMod(){
 543+ return $this->lastMod;
 544+ }
 545+
 546+ public function getKeywords (){
 547+ return $this->xmlEncode( $this->keywords );
 548+ }
 549+
 550+ public function getPubDate(){
 551+ return $this->pubDate;
 552+ }
 553+
 554+ function formatTime( $ts ) {
 555+ // need to use RFC 822 time format at least for rss2.0
 556+ return gmdate( 'Y-m-d\TH:i:s', wfTimestamp( TS_UNIX, $ts ) );
 557+ }
 558+
 559+ /**
 560+ * Setup and send HTTP headers. Don't send any content;
 561+ * content might end up being cached and re-sent with
 562+ * these same headers later.
 563+ *
 564+ * This should be called from the outHeader() method,
 565+ * but can also be called separately.
 566+ *
 567+ * @public
 568+ **/
 569+ function httpHeaders() {
 570+ global $wgOut;
 571+ # We take over from $wgOut, excepting its cache header info
 572+ $wgOut->disable();
 573+ $mimetype = $this->contentType();
 574+ header( "Content-type: $mimetype; charset=UTF-8" );
 575+ $wgOut->sendCacheControl();
 576+
 577+ }
 578+
 579+ function outXmlHeader(){
 580+ global $wgStylePath, $wgStyleVersion;
 581+
 582+ $this->httpHeaders();
 583+ echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
 584+ }
 585+
 586+ /**
 587+ * Return an internet media type to be sent in the headers.
 588+ *
 589+ * @return string
 590+ * @private
 591+ **/
 592+ function contentType() {
 593+ global $wgRequest;
 594+ $ctype = $wgRequest->getVal('ctype','application/xml');
 595+ $allowedctypes = array('application/xml','text/xml','application/rss+xml','application/atom+xml');
 596+ return (in_array($ctype, $allowedctypes) ? $ctype : 'application/xml');
 597+ }
 598+
 599+}
 600+
 601+class SitemapFeed extends feedSMItem{
 602+ /**
 603+ * Output feed headers
 604+ **/
 605+ function outHeader(){
 606+ $this->outXmlHeader();
 607+ ?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">
 608+<?php
 609+ }
 610+ /**
 611+ * Output a SiteMap 0.9 item
 612+ * @param feedSMItem item to be output
 613+ **/
 614+ function outItem( $item ) {
 615+ ?>
 616+ <url>
 617+ <loc><?php print $item->getUrl() ?></loc>
 618+ <news:news>
 619+ <news:publication_date><?php print $item->getPubDate() ?></news:publication_date>
 620+ <?php if( $item->getKeywords() ){
 621+ echo '<news:keywords>' . $item->getKeywords() . "</news:keywords>\n";
 622+ }
 623+?> </news:news>
 624+<?php if( $item->getLastMod() ){ ?> <lastmod><?php print $item->getLastMod(); ?></lastmod>
 625+<?php }?>
 626+<?php if( $item->getPriority() ){ ?> <priority><? print $item->getPriority(); ?></priority><?php }?>
 627+ </url>
 628+<?php
 629+ }
 630+
 631+ /**
 632+ * Output SiteMap 0.9 footer
 633+ **/
 634+ function outFooter(){
 635+ echo '</urlset>';
 636+ }
 637+
 638+}?>
\ No newline at end of file
Property changes on: trunk/extensions/GNSM/SpecialGNSM_body.php
___________________________________________________________________
Name: svn:eol-style
1639 + native
Index: trunk/extensions/GNSM/SpecialGNSM.i18n.php
@@ -0,0 +1,35 @@
 2+<?php
 3+/**
 4+ * Internationalisation file for extension special page GNSM
 5+ * New version of DynamicPageList extension for use by Wikinews projects
 6+ *
 7+ * @addtogroup Extensions
 8+ **/
 9+
 10+$messages= array();
 11+
 12+/** English
 13+ * @author Amgine
 14+ **/
 15+
 16+$messages['en'] = array(
 17+ 'gnsm' => 'Google News SiteMap',
 18+ 'gnsm-desc' => 'Outputs an Atom/RSS feed as a Google News Sitemap.',
 19+ 'gnsm_toomanycats' => 'Error: Too many categories!',
 20+ 'gnsm_toofewcats' => 'Error: Too few categories!',
 21+ 'gnsm_noresults' => 'Error: No results!',
 22+ 'gnsm_noincludecats' => 'Error: You need to include at least one category, or specify a namespace!',
 23+);
 24+
 25+/** Fran�ais
 26+ * @author Amgine
 27+ **/
 28+
 29+$messages['fr'] = array(
 30+ 'gnsm' => 'Google nouvelles SiteMap',
 31+ 'gnsm-desc' => 'Cre un Atom ou RSS feed comme un plan Sitemap pour Google.',
 32+ 'gnsm_toomanycats' => 'Erreur: Trop de nombreuses cat�gories!',
 33+ 'gnsm_toofewcats' => 'Erreur: Trop peu de cat�gories!',
 34+ 'gnsm_noresults' => 'Erreur: Pas de r�sultats!',
 35+ 'gnsm_noincludecats' => 'Error : Vous devez inclure au moins une cat�gorie, ou sp�cifier un nom d�espace !'
 36+);
\ No newline at end of file
Property changes on: trunk/extensions/GNSM/SpecialGNSM.i18n.php
___________________________________________________________________
Name: svn:eol-style
137 + native
Index: trunk/extensions/GNSM/SpecialGNSM.php
@@ -0,0 +1,69 @@
 2+<?php
 3+if (!defined('MEDIAWIKI')) {
 4+ echo <<<EOT
 5+To install GNSM extension, an extension special page, put the following line in LocalSettings.php:
 6+require_once( dirname(__FILE__) . '/extensions/GNSM/SpecialGNSM.php' );
 7+EOT;
 8+ exit( 1 );
 9+}
 10+
 11+/**
 12+ * Outputs feed xml
 13+ **
 14+ * A Special Page extension to produce:
 15+ * Google News sitemap output - http://www.google.com/support/news_pub/bin/answer.py?hl=en&answer=74288
 16+ * - http://www.sitemaps.org/protocol.php
 17+ * RSS feed output - 2.0 http://www.rssboard.org/rss-specification
 18+ * - 0.92 http://www.rssboard.org/rss-0-9-2
 19+ * Atom feed output - 2005 http://tools.ietf.org/html/rfc4287
 20+ **
 21+ * This page can be accessed from Special:GNSM[/][|category=Catname]
 22+ * [|notcategory=OtherCatName][|namespace=0][|notnamespace=User]
 23+ * [|feed=sitemap][|count=10][|mode=ul][|ordermethod=lastedit]
 24+ * [|order=ascending] as well as being included like
 25+ * {{Special:GNSM/[options][...]}}
 26+ **
 27+ * This program is free software; you can redistribute it and/or modify it
 28+ * under the terms of the GNU General Public License as published by the Free
 29+ * Software Foundation; either version 2 of the License, or (at your option)
 30+ * any later version.
 31+ *
 32+ * This program is distributed in the hope that it will be useful, but WITHOUT
 33+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 34+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 35+ * more details.
 36+ *
 37+ * You should have received a copy of the GNU General Public License along with
 38+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 39+ * Place - Suite 330, Boston, MA 02111-1307, USA.
 40+ * http://www.gnu.org/copyleft/gpl.html
 41+ **
 42+ * Contributors
 43+ * This script is based on Extension:DynamicPageList (Wikimedia), originally
 44+ * developed by:
 45+ * wikt:en:User:Amgine http://en.wiktionary.org/wiki/User:Amgine
 46+ * n:en:User:IlyaHaykinson http://en.wikinews.org/wiki/User:IlyaHaykinson
 47+ **
 48+ * FIXME requests
 49+ * use=Mediawiki:GNSM_Feedname Parameter to allow on-site control of feed
 50+ **
 51+ * @addtogroup Extensions
 52+ *
 53+ * @author Amgine <amgine.saewyc@gmail.com>
 54+ * @copyright Copyright � 2009, Amgine
 55+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
 56+ */
 57+$wgExtensionCredits['specialpage'][] = array(
 58+ 'path' => __FILE__,
 59+ 'name' => 'GNSM',
 60+ 'author' => 'Amgine',
 61+ 'description' => 'Outputs xml based on defined criteria',
 62+ 'descriptionmsg' => 'gnsm-desc',
 63+ 'url' => 'http://www.mediawiki.org/wiki/Extension:GNSM',
 64+);
 65+
 66+$dir = dirname(__FILE__) . '/';
 67+$wgExtensionMessagesFiles['GNSM'] = $dir . 'SpecialGNSM.i18n.php';
 68+$wgExtensionAliasesFiles['GNSM'] = $dir . 'SpecialGNSM.alias.php';
 69+$wgAutoloadClasses['GNSM'] = $dir . 'SpecialGNSM_body.php';
 70+$wgSpecialPages['GNSM'] = 'GNSM';
\ No newline at end of file
Property changes on: trunk/extensions/GNSM/SpecialGNSM.php
___________________________________________________________________
Name: svn:eol-style
171 + native

Follow-up revisions

RevisionCommit summaryAuthorDate
r60253Fix for bug 20818: To make google happy, set a dummy parameter (dpl_id) which...tstarling07:22, 21 December 2009

Comments

#Comment by Raymond (talk | contribs)   20:08, 17 December 2009

i18n and alias files have encoding errors (not UTF-8)

#Comment by MaxSem (talk | contribs)   20:15, 17 December 2009

Fixed in r60174

#Comment by 😂 (talk | contribs)   15:07, 21 December 2009
  1. Newlines at ends of files to avoid warnings on diff
  2. Use spaces/tabs consistently for indentation (see Manual:Coding_conventions#Whitespace_etc)
  3. If you're not using globals, don't declare them
  4. Remove commented debugging code

Basically, code cleanup.

#Comment by Tim Starling (talk | contribs)   07:31, 12 January 2010

Renamed to GoogleNewsSitemap in r60963 and r60965.

Status & tagging log