MediaWiki  master
LogPage.php
Go to the documentation of this file.
1 <?php
30 
40 class LogPage {
41  public const DELETED_ACTION = 1;
42  public const DELETED_COMMENT = 2;
43  public const DELETED_USER = 4;
44  public const DELETED_RESTRICTED = 8;
45 
46  // Convenience fields
47  public const SUPPRESSED_USER = self::DELETED_USER | self::DELETED_RESTRICTED;
48  public const SUPPRESSED_ACTION = self::DELETED_ACTION | self::DELETED_RESTRICTED;
49 
52 
54  public $sendToUDP;
55 
57  private $ircActionText;
58 
60  private $actionText;
61 
65  private $type;
66 
70  private $action;
71 
73  private $comment;
74 
76  private $params;
77 
79  private $performer;
80 
82  private $target;
83 
91  public function __construct( $type, $rc = true, $udp = 'skipUDP' ) {
92  $this->type = $type;
93  $this->updateRecentChanges = $rc;
94  $this->sendToUDP = ( $udp == 'UDP' );
95  }
96 
100  protected function saveContent() {
101  $logRestrictions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogRestrictions );
102 
103  $dbw = wfGetDB( DB_PRIMARY );
104 
105  $now = wfTimestampNow();
106  $actorId = MediaWikiServices::getInstance()->getActorNormalization()
107  ->acquireActorId( $this->performer, $dbw );
108  $data = [
109  'log_type' => $this->type,
110  'log_action' => $this->action,
111  'log_timestamp' => $dbw->timestamp( $now ),
112  'log_actor' => $actorId,
113  'log_namespace' => $this->target->getNamespace(),
114  'log_title' => $this->target->getDBkey(),
115  'log_page' => $this->target->getArticleID(),
116  'log_params' => $this->params
117  ];
118  $data += MediaWikiServices::getInstance()->getCommentStore()->insert(
119  $dbw,
120  'log_comment',
121  $this->comment
122  );
123  $dbw->insert( 'logging', $data, __METHOD__ );
124  $newId = $dbw->insertId();
125 
126  # And update recentchanges
127  if ( $this->updateRecentChanges ) {
128  $titleObj = SpecialPage::getTitleFor( 'Log', $this->type );
129 
131  $now, $titleObj, $this->performer, $this->getRcComment(), '',
132  $this->type, $this->action, $this->target, $this->comment,
133  $this->params, $newId, $this->getRcCommentIRC()
134  );
135  } elseif ( $this->sendToUDP ) {
136  # Don't send private logs to UDP
137  if ( isset( $logRestrictions[$this->type] ) && $logRestrictions[$this->type] != '*' ) {
138  return $newId;
139  }
140 
141  // Notify external application via UDP.
142  // We send this to IRC but do not want to add it the RC table.
143  $titleObj = SpecialPage::getTitleFor( 'Log', $this->type );
145  $now, $titleObj, $this->performer, $this->getRcComment(), '',
146  $this->type, $this->action, $this->target, $this->comment,
147  $this->params, $newId, $this->getRcCommentIRC()
148  );
149  $rc->notifyRCFeeds();
150  }
151 
152  return $newId;
153  }
154 
160  public function getRcComment() {
161  $rcComment = $this->actionText;
162 
163  if ( $this->comment != '' ) {
164  if ( $rcComment == '' ) {
165  $rcComment = $this->comment;
166  } else {
167  $rcComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() .
168  $this->comment;
169  }
170  }
171 
172  return $rcComment;
173  }
174 
180  public function getRcCommentIRC() {
181  $rcComment = $this->ircActionText;
182 
183  if ( $this->comment != '' ) {
184  if ( $rcComment == '' ) {
185  $rcComment = $this->comment;
186  } else {
187  $rcComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() .
188  $this->comment;
189  }
190  }
191 
192  return $rcComment;
193  }
194 
199  public function getComment() {
200  return $this->comment;
201  }
202 
208  public static function validTypes() {
209  $logTypes = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogTypes );
210 
211  return $logTypes;
212  }
213 
220  public static function isLogType( $type ) {
221  return in_array( $type, self::validTypes() );
222  }
223 
237  public static function actionText( $type, $action, $title = null, $skin = null,
238  $params = [], $filterWikilinks = false
239  ) {
240  global $wgLang;
241  $config = MediaWikiServices::getInstance()->getMainConfig();
242  $logActions = $config->get( MainConfigNames::LogActions );
243  $key = "$type/$action";
244 
245  if ( isset( $logActions[$key] ) ) {
246  if ( $skin === null ) {
247  $langObj = MediaWikiServices::getInstance()->getContentLanguage();
248  $langObjOrNull = null;
249  } else {
250  // TODO Is $skin->getLanguage() safe here?
251  StubUserLang::unstub( $wgLang );
252  $langObj = $wgLang;
253  $langObjOrNull = $wgLang;
254  }
255  if ( $title === null ) {
256  $rv = wfMessage( $logActions[$key] )->inLanguage( $langObj )->escaped();
257  } else {
258  $titleLink = self::getTitleLink( $title, $langObjOrNull );
259 
260  if ( count( $params ) == 0 ) {
261  $rv = wfMessage( $logActions[$key] )->rawParams( $titleLink )
262  ->inLanguage( $langObj )->escaped();
263  } else {
264  array_unshift( $params, $titleLink );
265 
266  $rv = wfMessage( $logActions[$key] )->rawParams( $params )
267  ->inLanguage( $langObj )->escaped();
268  }
269  }
270  } else {
271  $logActionsHandlers = $config->get( MainConfigNames::LogActionsHandlers );
272 
273  if ( isset( $logActionsHandlers[$key] ) ) {
274  $args = func_get_args();
275  $rv = call_user_func_array( $logActionsHandlers[$key], $args );
276  } else {
277  wfDebug( "LogPage::actionText - unknown action $key" );
278  $rv = "$action";
279  }
280  }
281 
282  // For the perplexed, this feature was added in r7855 by Erik.
283  // The feature was added because we liked adding [[$1]] in our log entries
284  // but the log entries are parsed as Wikitext on RecentChanges but as HTML
285  // on Special:Log. The hack is essentially that [[$1]] represented a link
286  // to the title in question. The first parameter to the HTML version (Special:Log)
287  // is that link in HTML form, and so this just gets rid of the ugly [[]].
288  // However, this is a horrible hack and it doesn't work like you expect if, say,
289  // you want to link to something OTHER than the title of the log entry.
290  // The real problem, which Erik was trying to fix (and it sort-of works now) is
291  // that the same messages are being treated as both wikitext *and* HTML.
292  if ( $filterWikilinks ) {
293  $rv = str_replace( '[[', '', $rv );
294  $rv = str_replace( ']]', '', $rv );
295  }
296 
297  return $rv;
298  }
299 
305  private static function getTitleLink( Title $title, ?Language $lang ): string {
306  if ( !$lang ) {
307  return $title->getPrefixedText();
308  }
309 
310  $services = MediaWikiServices::getInstance();
311  $linkRenderer = $services->getLinkRenderer();
312 
313  if ( $title->isSpecialPage() ) {
314  [ $name, $par ] = $services->getSpecialPageFactory()->resolveAlias( $title->getDBkey() );
315 
316  if ( $name === 'Log' ) {
317  $logPage = new LogPage( $par );
318  return wfMessage( 'parentheses' )
319  ->rawParams( $linkRenderer->makeLink( $title, $logPage->getName()->text() ) )
320  ->inLanguage( $lang )
321  ->escaped();
322  }
323  }
324 
325  return $linkRenderer->makeLink( $title );
326  }
327 
341  public function addEntry( $action, $target, $comment, $params, $performer ) {
342  // FIXME $params is only documented to accept an array
343  if ( !is_array( $params ) ) {
344  $params = [ $params ];
345  }
346 
347  # Trim spaces on user supplied text
348  $comment = trim( $comment ?? '' );
349 
350  $this->action = $action;
351  $this->target = $target;
352  $this->comment = $comment;
353  $this->params = self::makeParamBlob( $params );
354 
355  if ( !is_object( $performer ) ) {
356  $performer = User::newFromId( $performer );
357  }
358 
359  $this->performer = $performer;
360 
361  $logEntry = new ManualLogEntry( $this->type, $action );
362  $logEntry->setTarget( $target );
363  $logEntry->setPerformer( $performer );
364  $logEntry->setParameters( $params );
365  // All log entries using the LogPage to insert into the logging table
366  // are using the old logging system and therefore the legacy flag is
367  // needed to say the LogFormatter the parameters have numeric keys
368  $logEntry->setLegacy( true );
369 
370  $formatter = LogFormatter::newFromEntry( $logEntry );
371  $context = RequestContext::newExtraneousContext( $target );
372  $formatter->setContext( $context );
373 
374  $this->actionText = $formatter->getPlainActionText();
375  $this->ircActionText = $formatter->getIRCActionText();
376 
377  return $this->saveContent();
378  }
379 
388  public function addRelations( $field, $values, $logid ) {
389  if ( !strlen( $field ) || empty( $values ) ) {
390  return false;
391  }
392 
393  $data = [];
394 
395  foreach ( $values as $value ) {
396  $data[] = [
397  'ls_field' => $field,
398  'ls_value' => $value,
399  'ls_log_id' => $logid
400  ];
401  }
402 
403  $dbw = wfGetDB( DB_PRIMARY );
404  $dbw->insert( 'log_search', $data, __METHOD__, [ 'IGNORE' ] );
405 
406  return true;
407  }
408 
415  public static function makeParamBlob( $params ) {
416  return implode( "\n", $params );
417  }
418 
425  public static function extractParams( $blob ) {
426  if ( $blob === '' ) {
427  return [];
428  } else {
429  return explode( "\n", $blob );
430  }
431  }
432 
438  public function getName() {
439  $logNames = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogNames );
440 
441  // BC
442  $key = $logNames[$this->type] ?? 'log-name-' . $this->type;
443 
444  return wfMessage( $key );
445  }
446 
452  public function getDescription() {
453  $logHeaders = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogHeaders );
454  // BC
455  $key = $logHeaders[$this->type] ?? 'log-description-' . $this->type;
456 
457  return wfMessage( $key );
458  }
459 
465  public function getRestriction() {
466  $logRestrictions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogRestrictions );
467  // The empty string fallback will
468  // always return true in permission check
469  return $logRestrictions[$this->type] ?? '';
470  }
471 
477  public function isRestricted() {
478  $restriction = $this->getRestriction();
479 
480  return $restriction !== '' && $restriction !== '*';
481  }
482 }
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined( 'MW_NO_SESSION') &&! $wgCommandLineMode) $wgLang
Definition: Setup.php:508
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
Definition: WebStart.php:82
Base class for language-specific code.
Definition: Language.php:56
static newFromEntry(LogEntry $entry)
Constructs a new formatter suitable for given entry.
Class to simplify the use of log pages.
Definition: LogPage.php:40
static actionText( $type, $action, $title=null, $skin=null, $params=[], $filterWikilinks=false)
Generate text for a log entry.
Definition: LogPage.php:237
getRestriction()
Returns the right needed to read this log type.
Definition: LogPage.php:465
const SUPPRESSED_USER
Definition: LogPage.php:47
__construct( $type, $rc=true, $udp='skipUDP')
Definition: LogPage.php:91
const DELETED_USER
Definition: LogPage.php:43
static makeParamBlob( $params)
Create a blob from a parameter array.
Definition: LogPage.php:415
const DELETED_RESTRICTED
Definition: LogPage.php:44
bool $sendToUDP
Definition: LogPage.php:54
isRestricted()
Tells if this log is not viewable by all.
Definition: LogPage.php:477
static extractParams( $blob)
Extract a parameter array from a blob.
Definition: LogPage.php:425
static isLogType( $type)
Is $type a valid log type.
Definition: LogPage.php:220
getName()
Name of the log.
Definition: LogPage.php:438
saveContent()
Definition: LogPage.php:100
const DELETED_COMMENT
Definition: LogPage.php:42
getComment()
Get the comment from the last addEntry() call.
Definition: LogPage.php:199
bool $updateRecentChanges
Definition: LogPage.php:51
getRcComment()
Get the RC comment from the last addEntry() call.
Definition: LogPage.php:160
addRelations( $field, $values, $logid)
Add relations to log_search table.
Definition: LogPage.php:388
static validTypes()
Get the list of valid log types.
Definition: LogPage.php:208
getRcCommentIRC()
Get the RC comment from the last addEntry() call for IRC.
Definition: LogPage.php:180
getDescription()
Description of this log type.
Definition: LogPage.php:452
const DELETED_ACTION
Definition: LogPage.php:41
const SUPPRESSED_ACTION
Definition: LogPage.php:48
addEntry( $action, $target, $comment, $params, $performer)
Add a log entry.
Definition: LogPage.php:341
Class for creating new log entries and inserting them into the database.
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
Stub object for the user language.
static newLogEntry( $timestamp, $logPage, $user, $actionComment, $ip, $type, $action, $target, $logComment, $params, $newId=0, $actionCommentIRC='', $revId=0, $isPatrollable=false)
static notifyLog( $timestamp, $logPage, $user, $actionComment, $ip, $type, $action, $target, $logComment, $params, $newId=0, $actionCommentIRC='')
static newExtraneousContext(Title $title, $request=[])
Create a new extraneous context.
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,...
Represents a title within MediaWiki.
Definition: Title.php:52
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition: User.php:632
Interface for objects representing user identity.
const DB_PRIMARY
Definition: defines.php:28
if(!isset( $args[0])) $lang