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 |
1 | 44 | + 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 |
1 | 639 | + 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 |
1 | 37 | + 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 |
1 | 71 | + native |