MediaWiki  master
BlockLogFormatter.php
Go to the documentation of this file.
1 <?php
30 
37  protected function getMessageParameters() {
38  $params = parent::getMessageParameters();
39 
40  $title = $this->entry->getTarget();
41  if ( substr( $title->getText(), 0, 1 ) === '#' ) {
42  // autoblock - no user link possible
43  $params[2] = $title->getText();
44  $params[3] = ''; // no user name for gender use
45  } else {
46  // Create a user link for the blocked
47  $username = $title->getText();
48  // @todo Store the user identifier in the parameters
49  // to make this faster for future log entries
50  $targetUser = User::newFromName( $username, false );
51  $params[2] = Message::rawParam( $this->makeUserLink( $targetUser, Linker::TOOL_LINKS_NOBLOCK ) );
52  $params[3] = $username; // plain user name for gender use
53  }
54 
55  $subtype = $this->entry->getSubtype();
56  if ( $subtype === 'block' || $subtype === 'reblock' ) {
57  if ( !isset( $params[4] ) ) {
58  // Very old log entry without duration: means infinity
59  $params[4] = 'infinity';
60  }
61  // Localize the duration, and add a tooltip
62  // in English to help visitors from other wikis.
63  // The lrm is needed to make sure that the number
64  // is shown on the correct side of the tooltip text.
65  // @phan-suppress-next-line SecurityCheck-DoubleEscaped
66  $durationTooltip = '&lrm;' . htmlspecialchars( $params[4] );
67  $blockExpiry = $this->context->getLanguage()->translateBlockExpiry(
68  $params[4],
69  $this->context->getUser(),
70  (int)wfTimestamp( TS_UNIX, $this->entry->getTimestamp() )
71  );
72  if ( $this->plaintext ) {
73  // @phan-suppress-next-line SecurityCheck-XSS Unlikely positive, only if language format is bad
74  $params[4] = Message::rawParam( $blockExpiry );
75  } else {
76  $params[4] = Message::rawParam(
77  "<span class=\"blockExpiry\" title=\"$durationTooltip\">" .
78  // @phan-suppress-next-line SecurityCheck-DoubleEscaped language class does not escape
79  htmlspecialchars( $blockExpiry ) .
80  '</span>'
81  );
82  }
83  $params[5] = isset( $params[5] ) ?
84  self::formatBlockFlags( $params[5], $this->context->getLanguage() ) : '';
85 
86  // block restrictions
87  if ( isset( $params[6] ) ) {
88  $pages = $params[6]['pages'] ?? [];
89  $pageLinks = [];
90  foreach ( $pages as $page ) {
91  $pageLinks[] = $this->makePageLink( Title::newFromText( $page ) );
92  }
93 
94  $rawNamespaces = $params[6]['namespaces'] ?? [];
95  $namespaces = [];
96  foreach ( $rawNamespaces as $ns ) {
97  $text = (int)$ns === NS_MAIN
98  ? $this->msg( 'blanknamespace' )->escaped()
99  : htmlspecialchars( $this->context->getLanguage()->getFormattedNsText( $ns ) );
100  if ( $this->plaintext ) {
101  // Because the plaintext cannot link to the Special:AllPages
102  // link that is linked to in non-plaintext mode, just return
103  // the name of the namespace.
104  $namespaces[] = $text;
105  } else {
106  $namespaces[] = $this->makePageLink(
107  SpecialPage::getTitleFor( 'Allpages' ),
108  [ 'namespace' => $ns ],
109  $text
110  );
111  }
112  }
113 
114  $rawActions = $params[6]['actions'] ?? [];
115  $actions = [];
116  foreach ( $rawActions as $action ) {
117  $actions[] = $this->msg( 'ipb-action-' . $action )->escaped();
118  }
119 
120  $restrictions = [];
121  if ( $pageLinks ) {
122  $restrictions[] = $this->msg( 'logentry-partialblock-block-page' )
123  ->numParams( count( $pageLinks ) )
124  ->rawParams( $this->context->getLanguage()->listToText( $pageLinks ) )->escaped();
125  }
126 
127  if ( $namespaces ) {
128  $restrictions[] = $this->msg( 'logentry-partialblock-block-ns' )
129  ->numParams( count( $namespaces ) )
130  ->rawParams( $this->context->getLanguage()->listToText( $namespaces ) )->escaped();
131  }
132  $enablePartialActionBlocks = $this->context->getConfig()
133  ->get( MainConfigNames::EnablePartialActionBlocks );
134  if ( $actions && $enablePartialActionBlocks ) {
135  $restrictions[] = $this->msg( 'logentry-partialblock-block-action' )
136  ->numParams( count( $actions ) )
137  ->rawParams( $this->context->getLanguage()->listToText( $actions ) )->escaped();
138  }
139 
140  $params[6] = Message::rawParam( $this->context->getLanguage()->listToText( $restrictions ) );
141  }
142  }
143 
144  return $params;
145  }
146 
147  protected function extractParameters() {
148  $params = parent::extractParameters();
149  // Legacy log params returning the params in index 3 and 4, moved to 4 and 5
150  if ( $this->entry->isLegacy() && isset( $params[3] ) ) {
151  if ( isset( $params[4] ) ) {
152  $params[5] = $params[4];
153  }
154  $params[4] = $params[3];
155  $params[3] = '';
156  }
157  return $params;
158  }
159 
160  public function getPreloadTitles() {
161  $title = $this->entry->getTarget();
162  $preload = [];
163  // Preload user page for non-autoblocks
164  if ( substr( $title->getText(), 0, 1 ) !== '#' && $title->canExist() ) {
165  $preload[] = $title->getTalkPage();
166  }
167  // Preload page restriction
168  $params = $this->extractParameters();
169  if ( isset( $params[6]['pages'] ) ) {
170  foreach ( $params[6]['pages'] as $page ) {
171  $preload[] = Title::newFromText( $page );
172  }
173  }
174  return $preload;
175  }
176 
177  public function getActionLinks() {
178  $subtype = $this->entry->getSubtype();
179  $linkRenderer = $this->getLinkRenderer();
180  if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) // Action is hidden
181  || !( $subtype === 'block' || $subtype === 'reblock' )
182  || !$this->context->getAuthority()->isAllowed( 'block' )
183  ) {
184  return '';
185  }
186 
187  // Show unblock/change block link
188  $title = $this->entry->getTarget();
189  $links = [
190  $linkRenderer->makeKnownLink(
191  SpecialPage::getTitleFor( 'Unblock', $title->getDBkey() ),
192  $this->msg( 'unblocklink' )->text()
193  ),
194  $linkRenderer->makeKnownLink(
195  SpecialPage::getTitleFor( 'Block', $title->getDBkey() ),
196  $this->msg( 'change-blocklink' )->text()
197  )
198  ];
199 
200  return $this->msg( 'parentheses' )->rawParams(
201  $this->context->getLanguage()->pipeList( $links ) )->escaped();
202  }
203 
212  public static function formatBlockFlags( $flags, Language $lang ) {
213  $flags = trim( $flags );
214  if ( $flags === '' ) {
215  return ''; // nothing to do
216  }
217  $flags = explode( ',', $flags );
218  $flagsCount = count( $flags );
219 
220  for ( $i = 0; $i < $flagsCount; $i++ ) {
221  $flags[$i] = self::formatBlockFlag( $flags[$i], $lang );
222  }
223 
224  return wfMessage( 'parentheses' )->inLanguage( $lang )
225  ->rawParams( $lang->commaList( $flags ) )->escaped();
226  }
227 
235  public static function formatBlockFlag( $flag, Language $lang ) {
236  static $messages = [];
237 
238  if ( !isset( $messages[$flag] ) ) {
239  $messages[$flag] = htmlspecialchars( $flag ); // Fallback
240 
241  // For grepping. The following core messages can be used here:
242  // * block-log-flags-angry-autoblock
243  // * block-log-flags-anononly
244  // * block-log-flags-hiddenname
245  // * block-log-flags-noautoblock
246  // * block-log-flags-nocreate
247  // * block-log-flags-noemail
248  // * block-log-flags-nousertalk
249  $msg = wfMessage( 'block-log-flags-' . $flag )->inLanguage( $lang );
250 
251  if ( $msg->exists() ) {
252  $messages[$flag] = $msg->escaped();
253  }
254  }
255 
256  return $messages[$flag];
257  }
258 
259  protected function getParametersForApi() {
261  $params = $entry->getParameters();
262 
263  static $map = [
264  // While this looks wrong to be starting at 5 rather than 4, it's
265  // because getMessageParameters uses $4 for its own purposes.
266  '5::duration',
267  '6:array:flags',
268  '6::flags' => '6:array:flags',
269  ];
270 
271  foreach ( $map as $index => $key ) {
272  if ( isset( $params[$index] ) ) {
273  $params[$key] = $params[$index];
274  unset( $params[$index] );
275  }
276  }
277 
278  ksort( $params );
279 
280  $subtype = $entry->getSubtype();
281  if ( $subtype === 'block' || $subtype === 'reblock' ) {
282  // Defaults for old log entries missing some fields
283  $params += [
284  '5::duration' => 'infinity',
285  '6:array:flags' => [],
286  ];
287 
288  if ( !is_array( $params['6:array:flags'] ) ) {
289  // @phan-suppress-next-line PhanSuspiciousValueComparison
290  $params['6:array:flags'] = $params['6:array:flags'] === ''
291  ? []
292  : explode( ',', $params['6:array:flags'] );
293  }
294 
295  if ( wfIsInfinity( $params['5::duration'] ) ) {
296  // Normalize all possible values to one for pre-T241709 rows
297  $params['5::duration'] = 'infinity';
298  } else {
299  $ts = (int)wfTimestamp( TS_UNIX, $entry->getTimestamp() );
300  $expiry = strtotime( $params['5::duration'], $ts );
301  if ( $expiry !== false && $expiry > 0 ) {
302  $params[':timestamp:expiry'] = $expiry;
303  }
304  }
305  }
306 
307  return $params;
308  }
309 
314  public function formatParametersForApi() {
315  $ret = parent::formatParametersForApi();
316  if ( isset( $ret['flags'] ) ) {
317  ApiResult::setIndexedTagName( $ret['flags'], 'f' );
318  }
319 
320  if ( isset( $ret['restrictions']['pages'] ) ) {
321  $ret['restrictions']['pages'] = array_map( function ( $title ) {
322  return $this->formatParameterValueForApi( 'page', 'title-link', $title );
323  }, $ret['restrictions']['pages'] );
324  ApiResult::setIndexedTagName( $ret['restrictions']['pages'], 'p' );
325  }
326 
327  if ( isset( $ret['restrictions']['namespaces'] ) ) {
328  // @phan-suppress-next-line PhanTypeMismatchArgument False positive
329  ApiResult::setIndexedTagName( $ret['restrictions']['namespaces'], 'ns' );
330  }
331 
332  return $ret;
333  }
334 
335  protected function getMessageKey() {
336  $type = $this->entry->getType();
337  $subtype = $this->entry->getSubtype();
338  $sitewide = $this->entry->getParameters()['sitewide'] ?? true;
339 
340  $key = "logentry-$type-$subtype";
341  if ( ( $subtype === 'block' || $subtype === 'reblock' ) && !$sitewide ) {
342  // $this->getMessageParameters is doing too much. We just need
343  // to check the presence of restrictions ($param[6]) and calling
344  // on parent gives us that
345  $params = parent::getMessageParameters();
346 
347  // message changes depending on whether there are editing restrictions or not
348  if ( isset( $params[6] ) ) {
349  $key = "logentry-partial$type-$subtype";
350  } else {
351  $key = "logentry-non-editing-$type-$subtype";
352  }
353  }
354 
355  return $key;
356  }
357 }
const NS_MAIN
Definition: Defines.php:64
wfIsInfinity( $str)
Determine input string is represents as infinity.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:604
This class formats block log entries.
getMessageKey()
Returns a key to be used for formatting the action sentence.
getMessageParameters()
Formats parameters intended for action message from array of all parameters.
static formatBlockFlags( $flags, Language $lang)
Convert a comma-delimited list of block log flags into a more readable (and translated) form.
static formatBlockFlag( $flag, Language $lang)
Translate a block log flag if possible.
getActionLinks()
Returns extra links that comes after the action text, like "revert", etc.
getParametersForApi()
Get the array of parameters, converted from legacy format if necessary.
formatParametersForApi()
Format parameters for API output.The result array should generally map named keys to values....
extractParameters()
Extracts the optional extra parameters for use in action messages.
Base class for language-specific code.
Definition: Language.php:61
commaList(array $list)
Take a list of strings and build a locale-friendly comma-separated list, using the local comma-separa...
Definition: Language.php:3273
Implements the default log formatting.
LogEntryBase $entry
msg( $key,... $params)
Shortcut for wfMessage which honors local context.
formatParameterValueForApi( $name, $type, $value)
Format a single parameter value for API output.
makePageLink(Title $title=null, $parameters=[], $html=null)
Helper to make a link to the page, taking the plaintext value in consideration.
makeUserLink(UserIdentity $user, $toolFlags=0)
const DELETED_ACTION
Definition: LogPage.php:44
Some internal bits split of from Skin.php.
Definition: Linker.php:65
A class containing constants representing the names of configuration variables.
Parent class for all special pages.
Definition: SpecialPage.php:66
Represents a title within MediaWiki.
Definition: Title.php:76
internal since 1.36
Definition: User.php:98
static rawParam( $raw)
Definition: Message.php:1143
getParameters()
Get the extra parameters stored for this message.
getTimestamp()
Get the timestamp when the action was executed.
getSubtype()
The log subtype.