MediaWiki  master
ApiFeedContributions.php
Go to the documentation of this file.
1 <?php
35 
40 
42  private $revisionStore;
43 
45  private $titleParser;
46 
48  private $linkRenderer;
49 
52 
54  private $hookContainer;
55 
57  private $loadBalancer;
58 
60  private $namespaceInfo;
61 
63  private $actorMigration;
64 
66  private $userFactory;
67 
70 
72  private $hookRunner;
73 
88  public function __construct(
89  ApiMain $main,
90  $action,
101  ) {
102  parent::__construct( $main, $action );
103  $this->revisionStore = $revisionStore;
104  $this->titleParser = $titleParser;
105  $this->linkRenderer = $linkRenderer;
106  $this->linkBatchFactory = $linkBatchFactory;
107  $this->hookContainer = $hookContainer;
108  $this->loadBalancer = $loadBalancer;
109  $this->namespaceInfo = $namespaceInfo;
110  $this->actorMigration = $actorMigration;
111  $this->userFactory = $userFactory;
112  $this->commentFormatter = $commentFormatter;
113 
114  $this->hookRunner = new ApiHookRunner( $hookContainer );
115  }
116 
122  public function getCustomPrinter() {
123  return new ApiFormatFeedWrapper( $this->getMain() );
124  }
125 
126  public function execute() {
127  $params = $this->extractRequestParams();
128 
129  $config = $this->getConfig();
130  if ( !$config->get( 'Feed' ) ) {
131  $this->dieWithError( 'feed-unavailable' );
132  }
133 
134  $feedClasses = $config->get( 'FeedClasses' );
135  if ( !isset( $feedClasses[$params['feedformat']] ) ) {
136  $this->dieWithError( 'feed-invalid' );
137  }
138 
139  if ( $params['showsizediff'] && $this->getConfig()->get( 'MiserMode' ) ) {
140  $this->dieWithError( 'apierror-sizediffdisabled' );
141  }
142 
143  $msg = wfMessage( 'Contributions' )->inContentLanguage()->text();
144  $feedTitle = $config->get( 'Sitename' ) . ' - ' . $msg .
145  ' [' . $config->get( 'LanguageCode' ) . ']';
146 
147  $target = $params['user'];
148  if ( ExternalUserNames::isExternal( $target ) ) {
149  // Interwiki names make invalid titles, so put the target in the query instead.
150  $feedUrl = SpecialPage::getTitleFor( 'Contributions' )->getFullURL( [ 'target' => $target ] );
151  } else {
152  $feedUrl = SpecialPage::getTitleFor( 'Contributions', $target )->getFullURL();
153  }
154 
155  $feed = new $feedClasses[$params['feedformat']] (
156  $feedTitle,
157  htmlspecialchars( $msg ),
158  $feedUrl
159  );
160 
161  // Convert year/month parameters to end parameter
162  $params['start'] = '';
163  $params['end'] = '';
164  $params = ContribsPager::processDateFilter( $params );
165 
166  $targetUser = $this->userFactory->newFromName( $target, UserFactory::RIGOR_NONE );
167 
168  $pager = new ContribsPager(
169  $this->getContext(), [
170  'target' => $target,
171  'namespace' => $params['namespace'],
172  'start' => $params['start'],
173  'end' => $params['end'],
174  'tagFilter' => $params['tagfilter'],
175  'deletedOnly' => $params['deletedonly'],
176  'topOnly' => $params['toponly'],
177  'newOnly' => $params['newonly'],
178  'hideMinor' => $params['hideminor'],
179  'showSizeDiff' => $params['showsizediff'],
180  ],
181  $this->linkRenderer,
182  $this->linkBatchFactory,
183  $this->hookContainer,
184  $this->loadBalancer,
185  $this->actorMigration,
186  $this->revisionStore,
187  $this->namespaceInfo,
188  $targetUser,
189  $this->commentFormatter
190  );
191 
192  $feedLimit = $this->getConfig()->get( 'FeedLimit' );
193  if ( $pager->getLimit() > $feedLimit ) {
194  $pager->setLimit( $feedLimit );
195  }
196 
197  $feedItems = [];
198  if ( $pager->getNumRows() > 0 ) {
199  $count = 0;
200  $limit = $pager->getLimit();
201  foreach ( $pager->mResult as $row ) {
202  // ContribsPager selects one more row for navigation, skip that row
203  if ( ++$count > $limit ) {
204  break;
205  }
206  $item = $this->feedItem( $row );
207  if ( $item !== null ) {
208  $feedItems[] = $item;
209  }
210  }
211  }
212 
213  ApiFormatFeedWrapper::setResult( $this->getResult(), $feed, $feedItems );
214  }
215 
216  protected function feedItem( $row ) {
217  // This hook is the api contributions equivalent to the
218  // ContributionsLineEnding hook. Hook implementers may cancel
219  // the hook to signal the user is not allowed to read this item.
220  $feedItem = null;
221  $hookResult = $this->hookRunner->onApiFeedContributions__feedItem(
222  $row, $this->getContext(), $feedItem );
223  // Hook returned a valid feed item
224  if ( $feedItem instanceof FeedItem ) {
225  return $feedItem;
226  // Hook was canceled and did not return a valid feed item
227  } elseif ( !$hookResult ) {
228  return null;
229  }
230 
231  // Hook completed and did not return a valid feed item
232  $title = Title::makeTitle( (int)$row->page_namespace, $row->page_title );
233 
234  if ( $title && $this->getAuthority()->authorizeRead( 'read', $title ) ) {
235  $date = $row->rev_timestamp;
236  $comments = $title->getTalkPage()->getFullURL();
237  $revision = $this->revisionStore->newRevisionFromRow( $row, 0, $title );
238 
239  return new FeedItem(
240  $title->getPrefixedText(),
241  $this->feedItemDesc( $revision ),
242  $title->getFullURL( [ 'diff' => $revision->getId() ] ),
243  $date,
244  $this->feedItemAuthor( $revision ),
245  $comments
246  );
247  }
248 
249  return null;
250  }
251 
257  protected function feedItemAuthor( RevisionRecord $revision ) {
258  $user = $revision->getUser();
259  return $user ? $user->getName() : '';
260  }
261 
267  protected function feedItemDesc( RevisionRecord $revision ) {
268  $msg = wfMessage( 'colon-separator' )->inContentLanguage()->text();
269  try {
270  $content = $revision->getContent( SlotRecord::MAIN );
271  } catch ( RevisionAccessException $e ) {
272  $content = null;
273  }
274 
275  if ( $content instanceof TextContent ) {
276  // only textual content has a "source view".
277  $html = nl2br( htmlspecialchars( $content->getText() ) );
278  } else {
279  // XXX: we could get an HTML representation of the content via getParserOutput, but that may
280  // contain JS magic and generally may not be suitable for inclusion in a feed.
281  // Perhaps Content should have a getDescriptiveHtml method and/or a getSourceText method.
282  // Compare also FeedUtils::formatDiffRow.
283  $html = '';
284  }
285 
286  $comment = $revision->getComment();
287 
288  return '<p>' . htmlspecialchars( $this->feedItemAuthor( $revision ) ) . $msg .
289  htmlspecialchars( FeedItem::stripComment( $comment ? $comment->text : '' ) ) .
290  "</p>\n<hr />\n<div>" . $html . '</div>';
291  }
292 
293  public function getAllowedParams() {
294  $feedFormatNames = array_keys( $this->getConfig()->get( 'FeedClasses' ) );
295 
296  $ret = [
297  'feedformat' => [
298  ApiBase::PARAM_DFLT => 'rss',
299  ApiBase::PARAM_TYPE => $feedFormatNames
300  ],
301  'user' => [
302  ApiBase::PARAM_TYPE => 'user',
303  UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name', 'ip', 'cidr', 'id', 'interwiki' ],
304  ApiBase::PARAM_REQUIRED => true,
305  ],
306  'namespace' => [
307  ApiBase::PARAM_TYPE => 'namespace'
308  ],
309  'year' => [
310  ApiBase::PARAM_TYPE => 'integer'
311  ],
312  'month' => [
313  ApiBase::PARAM_TYPE => 'integer'
314  ],
315  'tagfilter' => [
316  ApiBase::PARAM_ISMULTI => true,
318  ApiBase::PARAM_DFLT => '',
319  ],
320  'deletedonly' => false,
321  'toponly' => false,
322  'newonly' => false,
323  'hideminor' => false,
324  'showsizediff' => [
325  ApiBase::PARAM_DFLT => false,
326  ],
327  ];
328 
329  if ( $this->getConfig()->get( 'MiserMode' ) ) {
330  $ret['showsizediff'][ApiBase::PARAM_HELP_MSG] = 'api-help-param-disabled-in-miser-mode';
331  }
332 
333  return $ret;
334  }
335 
336  protected function getExamplesMessages() {
337  return [
338  'action=feedcontributions&user=Example'
339  => 'apihelp-feedcontributions-example-simple',
340  ];
341  }
342 }
ApiMain
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:49
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:72
MediaWiki\Revision\RevisionAccessException
Exception representing a failure to look up a revision.
Definition: RevisionAccessException.php:37
MediaWiki\Revision\RevisionRecord\getContent
getContent( $role, $audience=self::FOR_PUBLIC, Authority $performer=null)
Returns the Content of the given slot of this revision.
Definition: RevisionRecord.php:156
MediaWiki\Revision\RevisionRecord\getUser
getUser( $audience=self::FOR_PUBLIC, Authority $performer=null)
Fetch revision's author's user identity, if it's available to the specified audience.
Definition: RevisionRecord.php:389
FeedItem
A base class for outputting syndication feeds (e.g.
Definition: FeedItem.php:35
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:47
MediaWiki\Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:47
ApiFeedContributions\__construct
__construct(ApiMain $main, $action, RevisionStore $revisionStore, TitleParser $titleParser, LinkRenderer $linkRenderer, LinkBatchFactory $linkBatchFactory, HookContainer $hookContainer, ILoadBalancer $loadBalancer, NamespaceInfo $namespaceInfo, ActorMigration $actorMigration, UserFactory $userFactory, CommentFormatter $commentFormatter)
Definition: ApiFeedContributions.php:88
ApiBase\PARAM_REQUIRED
const PARAM_REQUIRED
Definition: ApiBase.php:105
MediaWiki\Revision\RevisionStore
Service for looking up page revisions.
Definition: RevisionStore.php:89
ApiBase\dieWithError
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:1436
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:162
ApiFeedContributions\getCustomPrinter
getCustomPrinter()
This module uses a custom feed wrapper printer.
Definition: ApiFeedContributions.php:122
MediaWiki\Linker\LinkRenderer
Class that generates HTML links for pages.
Definition: LinkRenderer.php:43
ApiBase\PARAM_TYPE
const PARAM_TYPE
Definition: ApiBase.php:81
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:628
ApiFeedContributions\execute
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition: ApiFeedContributions.php:126
ApiFeedContributions\$loadBalancer
ILoadBalancer $loadBalancer
Definition: ApiFeedContributions.php:57
FeedItem\stripComment
static stripComment( $text)
Quickie hack...
Definition: FeedItem.php:222
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1167
SpecialPage\getTitleFor
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,...
Definition: SpecialPage.php:131
ActorMigration
This is not intended to be a long-term part of MediaWiki; it will be deprecated and removed once acto...
Definition: ActorMigration.php:15
MediaWiki\CommentFormatter\CommentFormatter
This is the main service interface for converting single-line comments from various DB comment fields...
Definition: CommentFormatter.php:16
MediaWiki\Api\ApiHookRunner
This class provides an implementation of the hook interfaces used by the core Action API,...
Definition: ApiHookRunner.php:55
ApiBase
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:55
ContribsPager\processDateFilter
static processDateFilter(array $opts)
Set up date filter options, given request data.
Definition: ContribsPager.php:910
ApiFeedContributions\$titleParser
TitleParser $titleParser
Definition: ApiFeedContributions.php:45
Wikimedia\ParamValidator\ParamValidator::TypeDef\UserDef
Type definition for user types.
Definition: UserDef.php:26
ApiFeedContributions\$userFactory
UserFactory $userFactory
Definition: ApiFeedContributions.php:66
ApiFeedContributions\$linkBatchFactory
LinkBatchFactory $linkBatchFactory
Definition: ApiFeedContributions.php:51
ApiFormatFeedWrapper
This printer is used to wrap an instance of the Feed class.
Definition: ApiFormatFeedWrapper.php:27
ApiFeedContributions\feedItemAuthor
feedItemAuthor(RevisionRecord $revision)
Definition: ApiFeedContributions.php:257
MediaWiki\Cache\LinkBatchFactory
Definition: LinkBatchFactory.php:39
ApiFeedContributions\$hookRunner
ApiHookRunner $hookRunner
Definition: ApiFeedContributions.php:72
ApiFeedContributions
Definition: ApiFeedContributions.php:39
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:764
ChangeTags\listDefinedTags
static listDefinedTags()
Basically lists defined tags which count even if they aren't applied to anything.
Definition: ChangeTags.php:1608
$title
$title
Definition: testCompression.php:38
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:648
TitleParser
A title parser service for MediaWiki.
Definition: TitleParser.php:33
MediaWiki\Revision\RevisionRecord\getComment
getComment( $audience=self::FOR_PUBLIC, Authority $performer=null)
Fetch revision comment, if it's available to the specified audience.
Definition: RevisionRecord.php:413
ApiFeedContributions\$actorMigration
ActorMigration $actorMigration
Definition: ApiFeedContributions.php:63
ApiFeedContributions\$revisionStore
RevisionStore $revisionStore
Definition: ApiFeedContributions.php:42
ContribsPager
Pager for Special:Contributions.
Definition: ContribsPager.php:42
ApiFeedContributions\$linkRenderer
LinkRenderer $linkRenderer
Definition: ApiFeedContributions.php:48
$content
$content
Definition: router.php:76
ContextSource\getAuthority
getAuthority()
Definition: ContextSource.php:144
ApiFeedContributions\$commentFormatter
CommentFormatter $commentFormatter
Definition: ApiFeedContributions.php:69
ApiFeedContributions\$namespaceInfo
NamespaceInfo $namespaceInfo
Definition: ApiFeedContributions.php:60
TextContent
Content object implementation for representing flat text.
Definition: TextContent.php:39
ApiFeedContributions\feedItemDesc
feedItemDesc(RevisionRecord $revision)
Definition: ApiFeedContributions.php:267
ApiFeedContributions\$hookContainer
HookContainer $hookContainer
Definition: ApiFeedContributions.php:54
ApiBase\PARAM_DFLT
const PARAM_DFLT
Definition: ApiBase.php:73
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
Definition: ApiBase.php:77
ApiFeedContributions\feedItem
feedItem( $row)
Definition: ApiFeedContributions.php:216
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:513
MediaWiki\HookContainer\HookContainer
HookContainer class.
Definition: HookContainer.php:45
ApiFeedContributions\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiFeedContributions.php:293
NamespaceInfo
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Definition: NamespaceInfo.php:35
ApiFeedContributions\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiFeedContributions.php:336
ExternalUserNames\isExternal
static isExternal( $username)
Tells whether the username is external or not.
Definition: ExternalUserNames.php:149
MediaWiki\User\UserFactory
Creates User objects.
Definition: UserFactory.php:41
ApiFormatFeedWrapper\setResult
static setResult( $result, $feed, $feedItems)
Call this method to initialize output data.
Definition: ApiFormatFeedWrapper.php:39
Wikimedia\Rdbms\ILoadBalancer
Database cluster connection, tracking, load balancing, and transaction manager interface.
Definition: ILoadBalancer.php:81
MediaWiki\Revision\SlotRecord
Value object representing a content slot associated with a page revision.
Definition: SlotRecord.php:40