wiki.techinc.nl/includes/api/ApiFeedWatchlist.php

313 lines
9.4 KiB
PHP
Raw Normal View History

<?php
/**
*
*
* Created on Oct 13, 2006
*
* Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
/**
* This action allows users to get their watchlist items in RSS/Atom formats.
* When executed, it performs a nested call to the API to get the needed data,
* and formats it in a proper format.
*
* @ingroup API
*/
class ApiFeedWatchlist extends ApiBase {
private $watchlistModule = null;
private $linkToSections = false;
/**
* This module uses a custom feed wrapper printer.
2011-09-21 16:36:43 +00:00
*
* @return ApiFormatFeedWrapper
*/
public function getCustomPrinter() {
return new ApiFormatFeedWrapper( $this->getMain() );
}
/**
* Make a nested call to the API to request watchlist items in the last $hours.
* Wrap the result as an RSS/Atom feed.
*/
public function execute() {
$config = $this->getConfig();
$feedClasses = $config->get( 'FeedClasses' );
$params = [];
try {
$params = $this->extractRequestParams();
if ( !$config->get( 'Feed' ) ) {
$this->dieWithError( 'feed-unavailable' );
}
if ( !isset( $feedClasses[$params['feedformat']] ) ) {
$this->dieWithError( 'feed-invalid' );
}
// limit to the number of hours going from now back
$endTime = wfTimestamp( TS_MW, time() - intval( $params['hours'] * 60 * 60 ) );
// Prepare parameters for nested request
$fauxReqArr = [
'action' => 'query',
'meta' => 'siteinfo',
'siprop' => 'general',
'list' => 'watchlist',
'wlprop' => 'title|user|comment|timestamp|ids',
'wldir' => 'older', // reverse order - from newest to oldest
'wlend' => $endTime, // stop at this time
'wllimit' => min( 50, $this->getConfig()->get( 'FeedLimit' ) )
];
if ( $params['wlowner'] !== null ) {
$fauxReqArr['wlowner'] = $params['wlowner'];
}
if ( $params['wltoken'] !== null ) {
$fauxReqArr['wltoken'] = $params['wltoken'];
}
if ( $params['wlexcludeuser'] !== null ) {
$fauxReqArr['wlexcludeuser'] = $params['wlexcludeuser'];
}
if ( $params['wlshow'] !== null ) {
$fauxReqArr['wlshow'] = $params['wlshow'];
}
if ( $params['wltype'] !== null ) {
$fauxReqArr['wltype'] = $params['wltype'];
}
// Support linking directly to sections when possible
// (possible only if section name is present in comment)
if ( $params['linktosections'] ) {
$this->linkToSections = true;
}
// Check for 'allrev' parameter, and if found, show all revisions to each page on wl.
if ( $params['allrev'] ) {
$fauxReqArr['wlallrev'] = '';
}
// Create the request
$fauxReq = new FauxRequest( $fauxReqArr );
// Execute
$module = new ApiMain( $fauxReq );
$module->execute();
$data = $module->getResult()->getResultData( [ 'query', 'watchlist' ] );
$feedItems = [];
API: Overhaul ApiResult, make format=xml not throw, and add json formatversion ApiResult was a mess: some methods could only be used with an array reference instead of manipulating the stored data, methods that had both array-ref and internal-data versions had names that didn't at all correspond, some methods that worked on an array reference were annoyingly non-static, and then the whole mess with setIndexedTagName. ApiFormatXml is also entirely annoying to deal with, as it liked to throw exceptions if certain metadata wasn't provided that no other formatter required. Its legacy also means we have this silly convention of using empty-string rather than boolean true, annoying restrictions on keys (leading to things that should be hashes being arrays of key-value object instead), '*' used as a key all over the place, and so on. So, changes here: * ApiResult is no longer an ApiBase or a ContextSource. * Wherever sensible, ApiResult provides a static method working on an arrayref and a non-static method working on internal data. * Metadata is now always added to ApiResult's internal data structure. Formatters are responsible for stripping it if necessary. "raw mode" is deprecated. * New metadata to replace the '*' key, solve the array() => '[]' vs '{}' question, and so on. * New class for formatting warnings and errors using i18n messages, and support for multiple errors and a more machine-readable format for warnings. For the moment, though, the actual output will not be changing yet (see T47843 for future plans). * New formatversion parameter for format=json and format=php, to select between BC mode and the modern output. * In BC mode, booleans will be converted to empty-string presence style; modules currently returning booleans will need to use ApiResult::META_BC_BOOLS to preserve their current output. Actual changes to the API modules' output (e.g. actually returning booleans for the new formatversion) beyond the use of ApiResult::setContentValue() are left for a future change. Bug: T76728 Bug: T57371 Bug: T33629 Change-Id: I7b37295e8862b188d1f3b0cd07f66ac34629678f
2014-12-03 22:14:22 +00:00
foreach ( (array)$data as $key => $info ) {
if ( ApiResult::isMetadataKey( $key ) ) {
continue;
}
$feedItem = $this->createFeedItem( $info );
if ( $feedItem ) {
$feedItems[] = $feedItem;
}
}
$msg = wfMessage( 'watchlist' )->inContentLanguage()->text();
2011-06-06 15:01:27 +00:00
$feedTitle = $this->getConfig()->get( 'Sitename' ) . ' - ' . $msg .
' [' . $this->getConfig()->get( 'LanguageCode' ) . ']';
$feedUrl = SpecialPage::getTitleFor( 'Watchlist' )->getFullURL();
$feed = new $feedClasses[$params['feedformat']] (
$feedTitle,
htmlspecialchars( $msg ),
$feedUrl
);
ApiFormatFeedWrapper::setResult( $this->getResult(), $feed, $feedItems );
} catch ( Exception $e ) {
// Error results should not be cached
$this->getMain()->setCacheMaxAge( 0 );
// @todo FIXME: Localise brackets
$feedTitle = $this->getConfig()->get( 'Sitename' ) . ' - Error - ' .
wfMessage( 'watchlist' )->inContentLanguage()->text() .
' [' . $this->getConfig()->get( 'LanguageCode' ) . ']';
$feedUrl = SpecialPage::getTitleFor( 'Watchlist' )->getFullURL();
$feedFormat = isset( $params['feedformat'] ) ? $params['feedformat'] : 'rss';
$msg = wfMessage( 'watchlist' )->inContentLanguage()->escaped();
$feed = new $feedClasses[$feedFormat] ( $feedTitle, $msg, $feedUrl );
if ( $e instanceof ApiUsageException ) {
foreach ( $e->getStatusValue()->getErrors() as $error ) {
$msg = ApiMessage::create( $error )
->inLanguage( $this->getLanguage() );
$errorTitle = $this->msg( 'api-feed-error-title', $msg->getApiCode() );
$errorText = $msg->text();
$feedItems[] = new FeedItem( $errorTitle, $errorText, '', '', '' );
}
} else {
if ( $e instanceof UsageException ) {
$errorCode = $e->getCodeString();
} else {
// Something is seriously wrong
$errorCode = 'internal_api_error';
}
$errorTitle = $this->msg( 'api-feed-error-title', $msg->getApiCode() );
$errorText = $e->getMessage();
$feedItems[] = new FeedItem( $errorTitle, $errorText, '', '', '' );
}
ApiFormatFeedWrapper::setResult( $this->getResult(), $feed, $feedItems );
}
}
2011-10-27 00:46:17 +00:00
/**
* @param array $info
2011-10-27 00:46:17 +00:00
* @return FeedItem
*/
private function createFeedItem( $info ) {
if ( !isset( $info['title'] ) ) {
// Probably a revdeled log entry, skip it.
return null;
}
$titleStr = $info['title'];
$title = Title::newFromText( $titleStr );
$curidParam = [];
if ( !$title || $title->isExternal() ) {
// Probably a formerly-valid title that's now conflicting with an
// interwiki prefix or the like.
if ( isset( $info['pageid'] ) ) {
$title = Title::newFromID( $info['pageid'] );
$curidParam = [ 'curid' => $info['pageid'] ];
}
if ( !$title || $title->isExternal() ) {
return null;
}
}
if ( isset( $info['revid'] ) ) {
$titleUrl = $title->getFullURL( [ 'diff' => $info['revid'] ] );
} else {
$titleUrl = $title->getFullURL( $curidParam );
}
Prevent the following strict-standards warnings - i.e. when running with error_logging(E_ALL | E_STRICT); - which seems to disable the yucky "@" operator, as well as maxing out the pedantry of warnings. Nothing major found, just nice to be as explicit and as forward-compatible as possible. * Strict Standards: Undefined index: switch in includes/Parser.php on line 3849 * Strict Standards: Undefined index: ref in includes/Parser.php on line 3818 * Strict Standards: Non-static method OutputPage::setEncodings() should not be called statically in index.php on line 11 * Strict Standards: Only variables should be assigned by reference in includes/Skin.php on line 888 * Strict Standards: Non-static method Title::newFromURL() should not be called statically in includes/SpecialContributions.php on line 178 * Strict Standards: Only variables should be assigned by reference in includes/GlobalFunctions.php on line 2054 * Strict Standards: Undefined index: contributions-summary in languages/Language.php on line 764 * Strict Standards: Undefined index: trackbackhtml in skins/MonoBook.php on line 86 * Strict Standards: Undefined index: blockip in skins/MonoBook.php on line 204 * Strict Standards: Undefined index: tagline in skins/MonoBook.php on line 261 * Strict Standards: Undefined index: uselang in includes/SkinTemplate.php on line 1159 * Strict Standards: Non-static method CoreParserFunctions::plural() cannot be called statically in includes/Parser.php on line 2902 * Strict Standards: Undefined offset: 0 in includes/SkinTemplate.php on line 196 * Strict Standards: Undefined index: USE INDEX in includes/Database.php on line 1015 * Strict Standards: Undefined index: image_tests in includes/Parser.php on line 3488 * Strict Standards: Undefined offset: 0 in includes/Parser.php on line 3507 * Strict Standards: Non-static method ChangesList::newFromUser() should not be called statically in includes/SpecialWatchlist.php on line 361 * Strict Standards: Non-static method RecentChange::newFromCurRow() should not be called statically in includes/SpecialWatchlist.php on line 367 * Strict Standards: is_a(): Deprecated. Please use the instanceof operator in includes/Exception.php on line 168 * Strict Standards: Non-static method LogPage::logName() should not be called statically in includes/SpecialContributions.php on line 325 * Strict Standards: ob_end_flush(): failed to delete and flush buffer. No buffer to delete or flush. in maintenance/commandLine.inc on line 191 * Strict Standards: Undefined index: meatball in languages/Language.php on line 234 * Strict Standards: rmdir(/tmp/mwParser-2108164586-images/thumb): Directory not empty in maintenance/parserTests.inc on line 605 * Cleaning out some new temp files left over by parserTests (there were one or two straggler dirs/files that would persist after the test run ended, due to new tests being added over time) * Strict Standards: Non-static method CoreParserFunctions::special() cannot be called statically in includes/Parser.php on line 2902 * Strict Standards: Declaration of ListUsersPage::preprocessResults() should be compatible with that of QueryPage::preprocessResults() in includes/SpecialListusers.php on line 38 * Strict Standards: Only variables should be passed by reference in includes/SpecialBlockip.php on line 175 * Strict Standards: Skin::include_once(skins/Standard.deps.php) [<a href='function.include-once'>function.include-once</a>]: failed to open stream: No such file or directory in includes/Skin.php on line 121 * Strict Standards: Declaration of ApiMain::getResult() should be compatible with that of ApiBase::getResult() in includes/api/ApiMain.php on line 35 * Strict Standards: is_a(): Deprecated. Please use the instanceof operator in includes/WikiError.php on line 63 * Strict Standards: Non-static method WikiError::isError() should not be called statically in includes/SpecialImport.php on line 64 * Strict Standards: Non-static method ImportStreamSource::newFromInterwiki() should not be called statically in includes/SpecialImport.php on line 58<b * Strict Standards: Only variables should be assigned by reference in includes/SpecialUndelete.php on line 501 * Strict Standards: Non-static method Image::newFromName() should not be called statically in thumb.php on line 56 * Strict Standards: Non-static method CoreParserFunctions::numberoffiles() cannot be called statically in includes/Parser.php on line 2902 * Strict Standards: Non-static method CoreParserFunctions::statisticsFunction() should not be called statically in includes/CoreParserFunctions.php on line 139 * Strict Standards: Non-static method CoreParserFunctions::isRaw() should not be called statically in includes/CoreParserFunctions.php on line 128 * Strict Standards: Non-static method CoreParserFunctions::grammar() cannot be called statically in includes/Parser.php on line 2902 * Strict Standards: Undefined offset: 1 in includes/SpecialMIMEsearch.php on line 130 * Strict Standards: Undefined index: recentchangeslinked in skins/MonoBook.php on line 184 * Strict Standards: Declaration of DumpNotalkFilter::pass() should be compatible with that of DumpFilter::pass() in includes/Export.php on line 612 * Strict Standards: Declaration of DumpNamespaceFilter::pass() should be compatible with that of DumpFilter::pass() in includes/Export.php on line 665 * Strict Standards: Non-static method ImportStreamSource::newFromUpload() should not be called statically in includes/SpecialImport.php on line 46 * Strict Standards: Undefined offset: 5 in includes/Sanitizer.php on line 396 * Strict Standards: Undefined index: wikidbUserName in includes/SpecialUserlogin.php on line 562 * Strict Standards: Only variables should be assigned by reference in includes/api/ApiQueryBase.php on line 95 * Strict Standards: Only variables should be assigned by reference in includes/api/ApiQueryBase.php on line 116 * Strict Standards: Only variables should be assigned by reference in includes/api/ApiQueryWatchlist.php on line 128 * Strict Standards: Undefined property: stdClass::$rc_id in includes/api/ApiQueryBase.php on line 131 * Strict Standards: Undefined property: stdClass::$rc_last_oldid in includes/api/ApiQueryBase.php on line 164 * Strict Standards: Undefined property: stdClass::$rc_moved_to_ns in includes/api/ApiQueryBase.php on line 285 * Strict Standards: Undefined property: stdClass::$rc_patrolled in includes/api/ApiQueryBase.php on line 176 * Strict Standards: Undefined index: comment in includes/api/ApiFeedWatchlist.php on line 85 * Strict Standards: Undefined offset: 0 in includes/Skin.php on line 302 * Strict Standards: Non-static method User::SetupSession() should not be called statically in includes/SpecialUserlogin.php on line 15 ... There are certain to be other things too, so this is not intended to be comprehensive, rather the above just stops most of the notifications I observed.
2006-11-29 05:45:03 +00:00
$comment = isset( $info['comment'] ) ? $info['comment'] : null;
// Create an anchor to section.
// The anchor won't work for sections that have dupes on page
// as there's no way to strip that info from ApiWatchlist (apparently?).
// RegExp in the line below is equal to Linker::formatAutocomments().
if ( $this->linkToSections && $comment !== null &&
preg_match( '!(.*)/\*\s*(.*?)\s*\*/(.*)!', $comment, $matches )
) {
global $wgParser;
$sectionTitle = $wgParser->stripSectionName( $matches[2] );
$sectionTitle = Sanitizer::normalizeSectionNameWhitespace( $sectionTitle );
$titleUrl .= Title::newFromText( '#' . $sectionTitle )->getFragmentForURL();
}
$timestamp = $info['timestamp'];
if ( isset( $info['user'] ) ) {
$user = $info['user'];
$completeText = "$comment ($user)";
} else {
$user = '';
$completeText = (string)$comment;
}
return new FeedItem( $titleStr, $completeText, $titleUrl, $timestamp, $user );
}
private function getWatchlistModule() {
if ( $this->watchlistModule === null ) {
$this->watchlistModule = $this->getMain()->getModuleManager()->getModule( 'query' )
->getModuleManager()->getModule( 'watchlist' );
}
return $this->watchlistModule;
}
public function getAllowedParams( $flags = 0 ) {
$feedFormatNames = array_keys( $this->getConfig()->get( 'FeedClasses' ) );
$ret = [
'feedformat' => [
ApiBase::PARAM_DFLT => 'rss',
ApiBase::PARAM_TYPE => $feedFormatNames
],
'hours' => [
ApiBase::PARAM_DFLT => 24,
ApiBase::PARAM_TYPE => 'integer',
ApiBase::PARAM_MIN => 1,
ApiBase::PARAM_MAX => 72,
],
'linktosections' => false,
];
$copyParams = [
'allrev' => 'allrev',
'owner' => 'wlowner',
'token' => 'wltoken',
'show' => 'wlshow',
'type' => 'wltype',
'excludeuser' => 'wlexcludeuser',
];
if ( $flags ) {
$wlparams = $this->getWatchlistModule()->getAllowedParams( $flags );
foreach ( $copyParams as $from => $to ) {
$p = $wlparams[$from];
if ( !is_array( $p ) ) {
$p = [ ApiBase::PARAM_DFLT => $p ];
}
if ( !isset( $p[ApiBase::PARAM_HELP_MSG] ) ) {
$p[ApiBase::PARAM_HELP_MSG] = "apihelp-query+watchlist-param-$from";
}
if ( isset( $p[ApiBase::PARAM_TYPE] ) && is_array( $p[ApiBase::PARAM_TYPE] ) &&
isset( $p[ApiBase::PARAM_HELP_MSG_PER_VALUE] )
) {
foreach ( $p[ApiBase::PARAM_TYPE] as $v ) {
if ( !isset( $p[ApiBase::PARAM_HELP_MSG_PER_VALUE][$v] ) ) {
$p[ApiBase::PARAM_HELP_MSG_PER_VALUE][$v] = "apihelp-query+watchlist-paramvalue-$from-$v";
}
}
}
$ret[$to] = $p;
}
} else {
foreach ( $copyParams as $from => $to ) {
$ret[$to] = null;
}
}
return $ret;
}
protected function getExamplesMessages() {
return [
'action=feedwatchlist'
=> 'apihelp-feedwatchlist-example-default',
'action=feedwatchlist&allrev=&hours=6'
=> 'apihelp-feedwatchlist-example-all6hrs',
];
}
public function getHelpUrls() {
return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Watchlist_feed';
}
}