MediaWiki  master
ApiFeedContributions.php
Go to the documentation of this file.
1 <?php
34 
39 
41  private $revisionStore;
42 
44  private $titleParser;
45 
47  private $linkRenderer;
48 
51 
53  private $hookContainer;
54 
56  private $loadBalancer;
57 
59  private $namespaceInfo;
60 
62  private $actorMigration;
63 
65  private $userFactory;
66 
68  private $hookRunner;
69 
83  public function __construct(
84  ApiMain $main,
85  $action,
95  ) {
96  parent::__construct( $main, $action );
97  $this->revisionStore = $revisionStore;
98  $this->titleParser = $titleParser;
99  $this->linkRenderer = $linkRenderer;
100  $this->linkBatchFactory = $linkBatchFactory;
101  $this->hookContainer = $hookContainer;
102  $this->loadBalancer = $loadBalancer;
103  $this->namespaceInfo = $namespaceInfo;
104  $this->actorMigration = $actorMigration;
105  $this->userFactory = $userFactory;
106 
107  $this->hookRunner = new ApiHookRunner( $hookContainer );
108  }
109 
115  public function getCustomPrinter() {
116  return new ApiFormatFeedWrapper( $this->getMain() );
117  }
118 
119  public function execute() {
120  $params = $this->extractRequestParams();
121 
122  $config = $this->getConfig();
123  if ( !$config->get( 'Feed' ) ) {
124  $this->dieWithError( 'feed-unavailable' );
125  }
126 
127  $feedClasses = $config->get( 'FeedClasses' );
128  if ( !isset( $feedClasses[$params['feedformat']] ) ) {
129  $this->dieWithError( 'feed-invalid' );
130  }
131 
132  if ( $params['showsizediff'] && $this->getConfig()->get( 'MiserMode' ) ) {
133  $this->dieWithError( 'apierror-sizediffdisabled' );
134  }
135 
136  $msg = wfMessage( 'Contributions' )->inContentLanguage()->text();
137  $feedTitle = $config->get( 'Sitename' ) . ' - ' . $msg .
138  ' [' . $config->get( 'LanguageCode' ) . ']';
139 
140  $target = $params['user'];
141  if ( ExternalUserNames::isExternal( $target ) ) {
142  // Interwiki names make invalid titles, so put the target in the query instead.
143  $feedUrl = SpecialPage::getTitleFor( 'Contributions' )->getFullURL( [ 'target' => $target ] );
144  } else {
145  $feedUrl = SpecialPage::getTitleFor( 'Contributions', $target )->getFullURL();
146  }
147 
148  $feed = new $feedClasses[$params['feedformat']] (
149  $feedTitle,
150  htmlspecialchars( $msg ),
151  $feedUrl
152  );
153 
154  // Convert year/month parameters to end parameter
155  $params['start'] = '';
156  $params['end'] = '';
157  $params = ContribsPager::processDateFilter( $params );
158 
159  $targetUser = $this->userFactory->newFromName( $target, UserFactory::RIGOR_NONE );
160 
161  $pager = new ContribsPager(
162  $this->getContext(), [
163  'target' => $target,
164  'namespace' => $params['namespace'],
165  'start' => $params['start'],
166  'end' => $params['end'],
167  'tagFilter' => $params['tagfilter'],
168  'deletedOnly' => $params['deletedonly'],
169  'topOnly' => $params['toponly'],
170  'newOnly' => $params['newonly'],
171  'hideMinor' => $params['hideminor'],
172  'showSizeDiff' => $params['showsizediff'],
173  ],
174  $this->linkRenderer,
175  $this->linkBatchFactory,
176  $this->hookContainer,
177  $this->loadBalancer,
178  $this->actorMigration,
179  $this->revisionStore,
180  $this->namespaceInfo,
181  $targetUser
182  );
183 
184  $feedLimit = $this->getConfig()->get( 'FeedLimit' );
185  if ( $pager->getLimit() > $feedLimit ) {
186  $pager->setLimit( $feedLimit );
187  }
188 
189  $feedItems = [];
190  if ( $pager->getNumRows() > 0 ) {
191  $count = 0;
192  $limit = $pager->getLimit();
193  foreach ( $pager->mResult as $row ) {
194  // ContribsPager selects one more row for navigation, skip that row
195  if ( ++$count > $limit ) {
196  break;
197  }
198  $item = $this->feedItem( $row );
199  if ( $item !== null ) {
200  $feedItems[] = $item;
201  }
202  }
203  }
204 
205  ApiFormatFeedWrapper::setResult( $this->getResult(), $feed, $feedItems );
206  }
207 
208  protected function feedItem( $row ) {
209  // This hook is the api contributions equivalent to the
210  // ContributionsLineEnding hook. Hook implementers may cancel
211  // the hook to signal the user is not allowed to read this item.
212  $feedItem = null;
213  $hookResult = $this->hookRunner->onApiFeedContributions__feedItem(
214  $row, $this->getContext(), $feedItem );
215  // Hook returned a valid feed item
216  if ( $feedItem instanceof FeedItem ) {
217  return $feedItem;
218  // Hook was canceled and did not return a valid feed item
219  } elseif ( !$hookResult ) {
220  return null;
221  }
222 
223  // Hook completed and did not return a valid feed item
224  $title = Title::makeTitle( (int)$row->page_namespace, $row->page_title );
225 
226  if ( $title && $this->getAuthority()->authorizeRead( 'read', $title ) ) {
227  $date = $row->rev_timestamp;
228  $comments = $title->getTalkPage()->getFullURL();
229  $revision = $this->revisionStore->newRevisionFromRow( $row, 0, $title );
230 
231  return new FeedItem(
232  $title->getPrefixedText(),
233  $this->feedItemDesc( $revision ),
234  $title->getFullURL( [ 'diff' => $revision->getId() ] ),
235  $date,
236  $this->feedItemAuthor( $revision ),
237  $comments
238  );
239  }
240 
241  return null;
242  }
243 
249  protected function feedItemAuthor( RevisionRecord $revision ) {
250  $user = $revision->getUser();
251  return $user ? $user->getName() : '';
252  }
253 
259  protected function feedItemDesc( RevisionRecord $revision ) {
260  $msg = wfMessage( 'colon-separator' )->inContentLanguage()->text();
261  try {
262  $content = $revision->getContent( SlotRecord::MAIN );
263  } catch ( RevisionAccessException $e ) {
264  $content = null;
265  }
266 
267  if ( $content instanceof TextContent ) {
268  // only textual content has a "source view".
269  $html = nl2br( htmlspecialchars( $content->getText() ) );
270  } else {
271  // XXX: we could get an HTML representation of the content via getParserOutput, but that may
272  // contain JS magic and generally may not be suitable for inclusion in a feed.
273  // Perhaps Content should have a getDescriptiveHtml method and/or a getSourceText method.
274  // Compare also FeedUtils::formatDiffRow.
275  $html = '';
276  }
277 
278  $comment = $revision->getComment();
279 
280  return '<p>' . htmlspecialchars( $this->feedItemAuthor( $revision ) ) . $msg .
281  htmlspecialchars( FeedItem::stripComment( $comment ? $comment->text : '' ) ) .
282  "</p>\n<hr />\n<div>" . $html . '</div>';
283  }
284 
285  public function getAllowedParams() {
286  $feedFormatNames = array_keys( $this->getConfig()->get( 'FeedClasses' ) );
287 
288  $ret = [
289  'feedformat' => [
290  ApiBase::PARAM_DFLT => 'rss',
291  ApiBase::PARAM_TYPE => $feedFormatNames
292  ],
293  'user' => [
294  ApiBase::PARAM_TYPE => 'user',
295  UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name', 'ip', 'cidr', 'id', 'interwiki' ],
296  ApiBase::PARAM_REQUIRED => true,
297  ],
298  'namespace' => [
299  ApiBase::PARAM_TYPE => 'namespace'
300  ],
301  'year' => [
302  ApiBase::PARAM_TYPE => 'integer'
303  ],
304  'month' => [
305  ApiBase::PARAM_TYPE => 'integer'
306  ],
307  'tagfilter' => [
308  ApiBase::PARAM_ISMULTI => true,
310  ApiBase::PARAM_DFLT => '',
311  ],
312  'deletedonly' => false,
313  'toponly' => false,
314  'newonly' => false,
315  'hideminor' => false,
316  'showsizediff' => [
317  ApiBase::PARAM_DFLT => false,
318  ],
319  ];
320 
321  if ( $this->getConfig()->get( 'MiserMode' ) ) {
322  $ret['showsizediff'][ApiBase::PARAM_HELP_MSG] = 'api-help-param-disabled-in-miser-mode';
323  }
324 
325  return $ret;
326  }
327 
328  protected function getExamplesMessages() {
329  return [
330  'action=feedcontributions&user=Example'
331  => 'apihelp-feedcontributions-example-simple',
332  ];
333  }
334 }
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:33
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:47
MediaWiki\Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:47
ApiBase\PARAM_REQUIRED
const PARAM_REQUIRED
Definition: ApiBase.php:78
MediaWiki\Revision\RevisionStore
Service for looking up page revisions.
Definition: RevisionStore.php:88
ApiBase\dieWithError
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:1379
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:105
ApiFeedContributions\getCustomPrinter
getCustomPrinter()
This module uses a custom feed wrapper printer.
Definition: ApiFeedContributions.php:115
MediaWiki\Linker\LinkRenderer
Class that generates HTML links for pages.
Definition: LinkRenderer.php:43
ApiBase\PARAM_TYPE
const PARAM_TYPE
Definition: ApiBase.php:72
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:571
ApiFeedContributions\execute
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition: ApiFeedContributions.php:119
ApiFeedContributions\$loadBalancer
ILoadBalancer $loadBalancer
Definition: ApiFeedContributions.php:56
FeedItem\stripComment
static stripComment( $text)
Quickie hack...
Definition: FeedItem.php:220
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1186
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:107
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\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:865
ApiFeedContributions\$titleParser
TitleParser $titleParser
Definition: ApiFeedContributions.php:44
Wikimedia\ParamValidator\ParamValidator::TypeDef\UserDef
Type definition for user types.
Definition: UserDef.php:26
ApiFeedContributions\$userFactory
UserFactory $userFactory
Definition: ApiFeedContributions.php:65
ApiFeedContributions\$linkBatchFactory
LinkBatchFactory $linkBatchFactory
Definition: ApiFeedContributions.php:50
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:249
MediaWiki\Cache\LinkBatchFactory
Definition: LinkBatchFactory.php:39
ApiFeedContributions\$hookRunner
ApiHookRunner $hookRunner
Definition: ApiFeedContributions.php:68
ApiFeedContributions
Definition: ApiFeedContributions.php:38
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:707
ChangeTags\listDefinedTags
static listDefinedTags()
Basically lists defined tags which count even if they aren't applied to anything.
Definition: ChangeTags.php:1592
$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:651
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:62
ApiFeedContributions\$revisionStore
RevisionStore $revisionStore
Definition: ApiFeedContributions.php:41
ContribsPager
Pager for Special:Contributions.
Definition: ContribsPager.php:41
ApiFeedContributions\$linkRenderer
LinkRenderer $linkRenderer
Definition: ApiFeedContributions.php:47
$content
$content
Definition: router.php:76
ContextSource\getAuthority
getAuthority()
Definition: ContextSource.php:144
ApiFeedContributions\$namespaceInfo
NamespaceInfo $namespaceInfo
Definition: ApiFeedContributions.php:59
TextContent
Content object implementation for representing flat text.
Definition: TextContent.php:39
ApiFeedContributions\feedItemDesc
feedItemDesc(RevisionRecord $revision)
Definition: ApiFeedContributions.php:259
ApiFeedContributions\$hookContainer
HookContainer $hookContainer
Definition: ApiFeedContributions.php:53
ApiBase\PARAM_DFLT
const PARAM_DFLT
Definition: ApiBase.php:70
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
Definition: ApiBase.php:71
ApiFeedContributions\feedItem
feedItem( $row)
Definition: ApiFeedContributions.php:208
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:456
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:285
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:328
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
ApiFeedContributions\__construct
__construct(ApiMain $main, $action, RevisionStore $revisionStore, TitleParser $titleParser, LinkRenderer $linkRenderer, LinkBatchFactory $linkBatchFactory, HookContainer $hookContainer, ILoadBalancer $loadBalancer, NamespaceInfo $namespaceInfo, ActorMigration $actorMigration, UserFactory $userFactory)
Definition: ApiFeedContributions.php:83