MediaWiki  master
ApiFeedContributions.php
Go to the documentation of this file.
1 <?php
28 
33 
35  private $revisionStore;
36 
38  private $titleParser;
39 
45  public function getCustomPrinter() {
46  return new ApiFormatFeedWrapper( $this->getMain() );
47  }
48 
49  public function execute() {
50  $this->revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
51  $this->titleParser = MediaWikiServices::getInstance()->getTitleParser();
52 
53  $params = $this->extractRequestParams();
54 
55  $config = $this->getConfig();
56  if ( !$config->get( 'Feed' ) ) {
57  $this->dieWithError( 'feed-unavailable' );
58  }
59 
60  $feedClasses = $config->get( 'FeedClasses' );
61  if ( !isset( $feedClasses[$params['feedformat']] ) ) {
62  $this->dieWithError( 'feed-invalid' );
63  }
64 
65  if ( $params['showsizediff'] && $this->getConfig()->get( 'MiserMode' ) ) {
66  $this->dieWithError( 'apierror-sizediffdisabled' );
67  }
68 
69  $msg = wfMessage( 'Contributions' )->inContentLanguage()->text();
70  $feedTitle = $config->get( 'Sitename' ) . ' - ' . $msg .
71  ' [' . $config->get( 'LanguageCode' ) . ']';
72  $feedUrl = SpecialPage::getTitleFor( 'Contributions', $params['user'] )->getFullURL();
73 
74  try {
75  $target = $this->titleParser
76  ->parseTitle( $params['user'], NS_USER )
77  ->getText();
78  } catch ( MalformedTitleException $e ) {
79  $this->dieWithError(
80  [ 'apierror-baduser', 'user', wfEscapeWikiText( $params['user'] ) ],
81  'baduser_' . $this->encodeParamName( 'user' )
82  );
83  }
84 
85  $feed = new $feedClasses[$params['feedformat']] (
86  $feedTitle,
87  htmlspecialchars( $msg ),
88  $feedUrl
89  );
90 
91  // Convert year/month parameters to end parameter
92  $params['start'] = '';
93  $params['end'] = '';
94  $params = ContribsPager::processDateFilter( $params );
95 
96  $pager = new ContribsPager( $this->getContext(), [
97  'target' => $target,
98  'namespace' => $params['namespace'],
99  'start' => $params['start'],
100  'end' => $params['end'],
101  'tagFilter' => $params['tagfilter'],
102  'deletedOnly' => $params['deletedonly'],
103  'topOnly' => $params['toponly'],
104  'newOnly' => $params['newonly'],
105  'hideMinor' => $params['hideminor'],
106  'showSizeDiff' => $params['showsizediff'],
107  ] );
108 
109  $feedLimit = $this->getConfig()->get( 'FeedLimit' );
110  if ( $pager->getLimit() > $feedLimit ) {
111  $pager->setLimit( $feedLimit );
112  }
113 
114  $feedItems = [];
115  if ( $pager->getNumRows() > 0 ) {
116  $count = 0;
117  $limit = $pager->getLimit();
118  foreach ( $pager->mResult as $row ) {
119  // ContribsPager selects one more row for navigation, skip that row
120  if ( ++$count > $limit ) {
121  break;
122  }
123  $item = $this->feedItem( $row );
124  if ( $item !== null ) {
125  $feedItems[] = $item;
126  }
127  }
128  }
129 
130  ApiFormatFeedWrapper::setResult( $this->getResult(), $feed, $feedItems );
131  }
132 
133  protected function feedItem( $row ) {
134  // This hook is the api contributions equivalent to the
135  // ContributionsLineEnding hook. Hook implementers may cancel
136  // the hook to signal the user is not allowed to read this item.
137  $feedItem = null;
138  $hookResult = Hooks::run(
139  'ApiFeedContributions::feedItem',
140  [ $row, $this->getContext(), &$feedItem ]
141  );
142  // Hook returned a valid feed item
143  if ( $feedItem instanceof FeedItem ) {
144  return $feedItem;
145  // Hook was canceled and did not return a valid feed item
146  } elseif ( !$hookResult ) {
147  return null;
148  }
149 
150  // Hook completed and did not return a valid feed item
151  $title = Title::makeTitle( (int)$row->page_namespace, $row->page_title );
152  $user = $this->getUser();
153 
154  if ( $title && $this->getPermissionManager()->userCan( 'read', $user, $title ) ) {
155  $date = $row->rev_timestamp;
156  $comments = $title->getTalkPage()->getFullURL();
157  $revision = $this->revisionStore->newRevisionFromRow( $row, 0, $title );
158 
159  return new FeedItem(
160  $title->getPrefixedText(),
161  $this->feedItemDesc( $revision ),
162  $title->getFullURL( [ 'diff' => $revision->getId() ] ),
163  $date,
164  $this->feedItemAuthor( $revision ),
165  $comments
166  );
167  }
168 
169  return null;
170  }
171 
177  protected function feedItemAuthor( RevisionRecord $revision ) {
178  $user = $revision->getUser();
179  return $user ? $user->getName() : '';
180  }
181 
187  protected function feedItemDesc( RevisionRecord $revision ) {
188  $msg = wfMessage( 'colon-separator' )->inContentLanguage()->text();
189  try {
190  $content = $revision->getContent( SlotRecord::MAIN );
191  } catch ( RevisionAccessException $e ) {
192  $content = null;
193  }
194 
195  if ( $content instanceof TextContent ) {
196  // only textual content has a "source view".
197  $html = nl2br( htmlspecialchars( $content->getText() ) );
198  } else {
199  // XXX: we could get an HTML representation of the content via getParserOutput, but that may
200  // contain JS magic and generally may not be suitable for inclusion in a feed.
201  // Perhaps Content should have a getDescriptiveHtml method and/or a getSourceText method.
202  // Compare also FeedUtils::formatDiffRow.
203  $html = '';
204  }
205 
206  $comment = $revision->getComment();
207 
208  return '<p>' . htmlspecialchars( $this->feedItemAuthor( $revision ) ) . $msg .
209  htmlspecialchars( FeedItem::stripComment( $comment ? $comment->text : '' ) ) .
210  "</p>\n<hr />\n<div>" . $html . '</div>';
211  }
212 
213  public function getAllowedParams() {
214  $feedFormatNames = array_keys( $this->getConfig()->get( 'FeedClasses' ) );
215 
216  $ret = [
217  'feedformat' => [
218  ApiBase::PARAM_DFLT => 'rss',
219  ApiBase::PARAM_TYPE => $feedFormatNames
220  ],
221  'user' => [
222  ApiBase::PARAM_TYPE => 'user',
223  ApiBase::PARAM_REQUIRED => true,
224  ],
225  'namespace' => [
226  ApiBase::PARAM_TYPE => 'namespace'
227  ],
228  'year' => [
229  ApiBase::PARAM_TYPE => 'integer'
230  ],
231  'month' => [
232  ApiBase::PARAM_TYPE => 'integer'
233  ],
234  'tagfilter' => [
235  ApiBase::PARAM_ISMULTI => true,
237  ApiBase::PARAM_DFLT => '',
238  ],
239  'deletedonly' => false,
240  'toponly' => false,
241  'newonly' => false,
242  'hideminor' => false,
243  'showsizediff' => [
244  ApiBase::PARAM_DFLT => false,
245  ],
246  ];
247 
248  if ( $this->getConfig()->get( 'MiserMode' ) ) {
249  $ret['showsizediff'][ApiBase::PARAM_HELP_MSG] = 'api-help-param-disabled-in-miser-mode';
250  }
251 
252  return $ret;
253  }
254 
255  protected function getExamplesMessages() {
256  return [
257  'action=feedcontributions&user=Example'
258  => 'apihelp-feedcontributions-example-simple',
259  ];
260  }
261 }
static stripComment( $text)
Quickie hack...
Definition: FeedItem.php:218
const PARAM_TYPE
(string|string[]) Either an array of allowed value strings, or a string type as described below...
Definition: ApiBase.php:94
static listDefinedTags()
Basically lists defined tags which count even if they aren&#39;t applied to anything. ...
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking, formatting, etc.
getResult()
Get the result object.
Definition: ApiBase.php:640
feedItemDesc(RevisionRecord $revision)
static processDateFilter(array $opts)
Set up date filter options, given request data.
feedItemAuthor(RevisionRecord $revision)
static setResult( $result, $feed, $feedItems)
Call this method to initialize output data.
const PARAM_DFLT
(null|boolean|integer|string) Default value of the parameter.
Definition: ApiBase.php:55
getMain()
Get the main module.
Definition: ApiBase.php:536
const PARAM_REQUIRED
(boolean) Is the parameter required?
Definition: ApiBase.php:118
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:2006
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user...
Definition: ApiBase.php:761
getContent( $role, $audience=self::FOR_PUBLIC, User $user=null)
Returns the Content of the given slot of this revision.
getContext()
Get the base IContextSource object.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don&#39;t need a full Title object...
Definition: SpecialPage.php:83
A base class for outputting syndication feeds (e.g.
Definition: FeedItem.php:33
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter...
Definition: ApiBase.php:131
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:584
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition: ApiBase.php:739
const PARAM_ISMULTI
(boolean) Accept multiple pipe-separated values for this parameter (e.g.
Definition: ApiBase.php:58
Exception representing a failure to look up a revision.
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks...
Definition: ApiBase.php:710
This abstract class implements many basic API functions, and is the base of all API classes...
Definition: ApiBase.php:42
Page revision base class.
getUser( $audience=self::FOR_PUBLIC, User $user=null)
Fetch revision&#39;s author&#39;s user identity, if it&#39;s available to the specified audience.
$content
Definition: router.php:78
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
getCustomPrinter()
This module uses a custom feed wrapper printer.
getComment( $audience=self::FOR_PUBLIC, User $user=null)
Fetch revision comment, if it&#39;s available to the specified audience.
This printer is used to wrap an instance of the Feed class.
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200