21use Wikimedia\Timestamp\TimestampFormat as TS;
33 private $watchlistModule =
null;
35 private $linkToSections =
false;
44 parent::__construct( $main, $action );
45 $this->parserFactory = $parserFactory;
64 '@phan-var array<string,class-string<ChannelFeed>> $feedClasses';
74 if ( !isset( $feedClasses[$params[
'feedformat']] ) ) {
79 $endTime =
wfTimestamp( TS::MW, time() - (
int)$params[
'hours'] * 60 * 60 );
85 'siprop' =>
'general',
86 'list' =>
'watchlist',
87 'wlprop' =>
'title|user|comment|timestamp|ids|loginfo',
93 if ( $params[
'wlowner'] !==
null ) {
94 $fauxReqArr[
'wlowner'] = $params[
'wlowner'];
96 if ( $params[
'wltoken'] !==
null ) {
97 $fauxReqArr[
'wltoken'] = $params[
'wltoken'];
99 if ( $params[
'wlexcludeuser'] !==
null ) {
100 $fauxReqArr[
'wlexcludeuser'] = $params[
'wlexcludeuser'];
102 if ( $params[
'wlshow'] !==
null ) {
103 $fauxReqArr[
'wlshow'] = ParamValidator::implodeMultiValue( $params[
'wlshow'] );
105 if ( $params[
'wltype'] !==
null ) {
106 $fauxReqArr[
'wltype'] = ParamValidator::implodeMultiValue( $params[
'wltype'] );
111 if ( $params[
'linktosections'] ) {
112 $this->linkToSections =
true;
116 if ( $params[
'allrev'] ) {
117 $fauxReqArr[
'wlallrev'] =
'';
122 $module =
new ApiMain( $fauxReq );
125 $data = $module->getResult()->getResultData( [
'query',
'watchlist' ] );
126 foreach ( (array)$data as $key => $info ) {
130 $feedItem = $this->createFeedItem( $info );
132 $feedItems[] = $feedItem;
136 $msg = $this->
msg(
'watchlist' )->inContentLanguage()->text();
142 $feed =
new $feedClasses[$params[
'feedformat']] (
144 htmlspecialchars( $msg ),
149 }
catch ( Exception $e ) {
151 $this->
getMain()->setCacheMaxAge( 0 );
155 $this->
msg(
'watchlist' )->inContentLanguage()->text() .
159 $feedFormat = $params[
'feedformat'] ??
'rss';
160 $msg = $this->
msg(
'watchlist' )->inContentLanguage()->escaped();
161 $feed =
new $feedClasses[$feedFormat]( $feedTitle, $msg, $feedUrl );
164 foreach ( $e->getStatusValue()->getMessages() as $msg ) {
168 $errorTitle = $this->
msg(
'api-feed-error-title', $msg->getApiCode() )->text();
169 $errorText = $msg->text();
170 $feedItems[] =
new FeedItem( $errorTitle, $errorText,
'',
'',
'' );
174 $errorCode =
'internal_api_error';
175 $errorTitle = $this->
msg(
'api-feed-error-title', $errorCode )->text();
176 $errorText = $e->getMessage();
177 $feedItems[] =
new FeedItem( $errorTitle, $errorText,
'',
'',
'' );
188 private function createFeedItem( $info ) {
189 if ( !isset( $info[
'title'] ) ) {
194 $titleStr = $info[
'title'];
195 $title = Title::newFromText( $titleStr );
197 if ( !$title || $title->isExternal() ) {
200 if ( isset( $info[
'pageid'] ) ) {
201 $title = Title::newFromID( $info[
'pageid'] );
202 $curidParam = [
'curid' => $info[
'pageid'] ];
204 if ( !$title || $title->isExternal() ) {
208 if ( isset( $info[
'revid'] ) ) {
209 if ( $info[
'revid'] === 0 && isset( $info[
'logid'] ) ) {
211 $titleUrl = $logTitle->getFullURL( [
'logid' => $info[
'logid'] ] );
213 $titleUrl = $title->getFullURL( [
'diff' => $info[
'revid'] ] );
216 $titleUrl = $title->getFullURL( $curidParam );
218 $comment = $info[
'comment'] ??
null;
224 if ( $this->linkToSections && $comment !==
null &&
225 preg_match(
'!(.*)/\*\s*(.*?)\s*\*/(.*)!', $comment,
$matches )
227 $titleUrl .= $this->parserFactory->getMainInstance()->guessSectionNameFromWikiText(
$matches[ 2 ] );
230 $timestamp = $info[
'timestamp'];
232 if ( isset( $info[
'user'] ) ) {
233 $user = $info[
'user'];
234 $completeText =
"$comment ($user)";
237 $completeText = (string)$comment;
240 return new FeedItem( $titleStr, $completeText, $titleUrl, $timestamp, $user );
244 private function getWatchlistModule() {
245 $this->watchlistModule ??= $this->
getMain()->getModuleManager()->getModule(
'query' )
246 ->getModuleManager()->getModule(
'watchlist' );
248 return $this->watchlistModule;
256 ParamValidator::PARAM_DEFAULT =>
'rss',
257 ParamValidator::PARAM_TYPE => $feedFormatNames
260 ParamValidator::PARAM_DEFAULT => 24,
261 ParamValidator::PARAM_TYPE =>
'integer',
262 IntegerDef::PARAM_MIN => 1,
263 IntegerDef::PARAM_MAX => 72,
265 'linktosections' =>
false,
269 'allrev' =>
'allrev',
270 'owner' =>
'wlowner',
271 'token' =>
'wltoken',
274 'excludeuser' =>
'wlexcludeuser',
277 $wlparams = $this->getWatchlistModule()->getAllowedParams( $flags );
278 foreach ( $copyParams as $from => $to ) {
279 $p = $wlparams[$from];
280 if ( !is_array( $p ) ) {
281 $p = [ ParamValidator::PARAM_DEFAULT => $p ];
286 if ( isset( $p[ParamValidator::PARAM_TYPE] ) && is_array( $p[ParamValidator::PARAM_TYPE] ) &&
289 foreach ( $p[ParamValidator::PARAM_TYPE] as $v ) {
304 'action=feedwatchlist'
305 =>
'apihelp-feedwatchlist-example-default',
306 'action=feedwatchlist&allrev=&hours=6'
307 =>
'apihelp-feedwatchlist-example-all6hrs',
313 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Watchlist_feed';
318class_alias( ApiFeedWatchlist::class,
'ApiFeedWatchlist' );
wfTimestamp( $outputtype=TS::UNIX, $ts=0)
Get a timestamp string in one of various formats.
This is the main API class, used for both external and internal processing.
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
A class containing constants representing the names of configuration variables.
const FeedClasses
Name constant for the FeedClasses setting, for use with Config::get()
const Feed
Name constant for the Feed setting, for use with Config::get()
const Sitename
Name constant for the Sitename setting, for use with Config::get()
const LanguageCode
Name constant for the LanguageCode setting, for use with Config::get()
const FeedLimit
Name constant for the FeedLimit setting, for use with Config::get()
Parent class for all special pages.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...