MediaWiki master
LogPage.php
Go to the documentation of this file.
1<?php
26namespace MediaWiki\Logging;
27
39use Skin;
40
50class LogPage {
51 public const DELETED_ACTION = 1;
52 public const DELETED_COMMENT = 2;
53 public const DELETED_USER = 4;
54 public const DELETED_RESTRICTED = 8;
55
56 // Convenience fields
57 public const SUPPRESSED_USER = self::DELETED_USER | self::DELETED_RESTRICTED;
58 public const SUPPRESSED_ACTION = self::DELETED_ACTION | self::DELETED_RESTRICTED;
59
62
64 public $sendToUDP;
65
67 private $ircActionText;
68
70 private $actionText;
71
75 private $type;
76
80 private $action;
81
83 private $comment;
84
86 private $params;
87
89 private $performer;
90
92 private $target;
93
101 public function __construct( $type, $rc = true, $udp = 'skipUDP' ) {
102 $this->type = $type;
103 $this->updateRecentChanges = $rc;
104 $this->sendToUDP = ( $udp == 'UDP' );
105 }
106
110 protected function saveContent() {
111 $logRestrictions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogRestrictions );
112
113 $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
114
115 $now = wfTimestampNow();
116 $actorId = MediaWikiServices::getInstance()->getActorNormalization()
117 ->acquireActorId( $this->performer, $dbw );
118 $data = [
119 'log_type' => $this->type,
120 'log_action' => $this->action,
121 'log_timestamp' => $dbw->timestamp( $now ),
122 'log_actor' => $actorId,
123 'log_namespace' => $this->target->getNamespace(),
124 'log_title' => $this->target->getDBkey(),
125 'log_page' => $this->target->getArticleID(),
126 'log_params' => $this->params
127 ];
128 $data += MediaWikiServices::getInstance()->getCommentStore()->insert(
129 $dbw,
130 'log_comment',
131 $this->comment
132 );
133 $dbw->newInsertQueryBuilder()
134 ->insertInto( 'logging' )
135 ->row( $data )
136 ->caller( __METHOD__ )->execute();
137 $newId = $dbw->insertId();
138
139 # And update recentchanges
140 if ( $this->updateRecentChanges ) {
141 $titleObj = SpecialPage::getTitleFor( 'Log', $this->type );
142
143 RecentChange::notifyLog(
144 $now, $titleObj, $this->performer, $this->getRcComment(), '',
145 $this->type, $this->action, $this->target, $this->comment,
146 $this->params, $newId, $this->getRcCommentIRC()
147 );
148 } elseif ( $this->sendToUDP ) {
149 # Don't send private logs to UDP
150 if ( isset( $logRestrictions[$this->type] ) && $logRestrictions[$this->type] != '*' ) {
151 return $newId;
152 }
153
154 // Notify external application via UDP.
155 // We send this to IRC but do not want to add it the RC table.
156 $titleObj = SpecialPage::getTitleFor( 'Log', $this->type );
157 $rc = RecentChange::newLogEntry(
158 $now, $titleObj, $this->performer, $this->getRcComment(), '',
159 $this->type, $this->action, $this->target, $this->comment,
160 $this->params, $newId, $this->getRcCommentIRC()
161 );
162 $rc->notifyRCFeeds();
163 }
164
165 return $newId;
166 }
167
173 public function getRcComment() {
174 $rcComment = $this->actionText;
175
176 if ( $this->comment != '' ) {
177 if ( $rcComment == '' ) {
178 $rcComment = $this->comment;
179 } else {
180 $rcComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() .
181 $this->comment;
182 }
183 }
184
185 return $rcComment;
186 }
187
193 public function getRcCommentIRC() {
194 $rcComment = $this->ircActionText;
195
196 if ( $this->comment != '' ) {
197 if ( $rcComment == '' ) {
198 $rcComment = $this->comment;
199 } else {
200 $rcComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() .
201 $this->comment;
202 }
203 }
204
205 return $rcComment;
206 }
207
212 public function getComment() {
213 return $this->comment;
214 }
215
221 public static function validTypes() {
222 $logTypes = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogTypes );
223
224 return $logTypes;
225 }
226
233 public static function isLogType( $type ) {
234 return in_array( $type, self::validTypes() );
235 }
236
250 public static function actionText( $type, $action, $title = null, $skin = null,
251 $params = [], $filterWikilinks = false
252 ) {
253 global $wgLang;
254 $config = MediaWikiServices::getInstance()->getMainConfig();
255 $key = "$type/$action";
256
257 $logActions = $config->get( MainConfigNames::LogActions );
258
259 if ( isset( $logActions[$key] ) ) {
260 $message = $logActions[$key];
261 } else {
262 wfDebug( "LogPage::actionText - unknown action $key" );
263 $message = "log-unknown-action";
264 $params = [ $key ];
265 }
266
267 if ( $skin === null ) {
268 $langObj = MediaWikiServices::getInstance()->getContentLanguage();
269 $langObjOrNull = null;
270 } else {
271 // TODO Is $skin->getLanguage() safe here?
272 StubUserLang::unstub( $wgLang );
273 $langObj = $wgLang;
274 $langObjOrNull = $wgLang;
275 }
276 if ( $title === null ) {
277 $rv = wfMessage( $message )->inLanguage( $langObj )->escaped();
278 } else {
279 $titleLink = self::getTitleLink( $title, $langObjOrNull );
280
281 if ( count( $params ) == 0 ) {
282 $rv = wfMessage( $message )->rawParams( $titleLink )
283 ->inLanguage( $langObj )->escaped();
284 } else {
285 array_unshift( $params, $titleLink );
286
287 $rv = wfMessage( $message )->rawParams( $params )
288 ->inLanguage( $langObj )->escaped();
289 }
290 }
291
292 // For the perplexed, this feature was added in r7855 by Erik.
293 // The feature was added because we liked adding [[$1]] in our log entries
294 // but the log entries are parsed as Wikitext on RecentChanges but as HTML
295 // on Special:Log. The hack is essentially that [[$1]] represented a link
296 // to the title in question. The first parameter to the HTML version (Special:Log)
297 // is that link in HTML form, and so this just gets rid of the ugly [[]].
298 // However, this is a horrible hack and it doesn't work like you expect if, say,
299 // you want to link to something OTHER than the title of the log entry.
300 // The real problem, which Erik was trying to fix (and it sort-of works now) is
301 // that the same messages are being treated as both wikitext *and* HTML.
302 if ( $filterWikilinks ) {
303 $rv = str_replace( '[[', '', $rv );
304 $rv = str_replace( ']]', '', $rv );
305 }
306
307 return $rv;
308 }
309
315 private static function getTitleLink( Title $title, ?Language $lang ): string {
316 if ( !$lang ) {
317 return $title->getPrefixedText();
318 }
319
320 $services = MediaWikiServices::getInstance();
321 $linkRenderer = $services->getLinkRenderer();
322
323 if ( $title->isSpecialPage() ) {
324 [ $name, $par ] = $services->getSpecialPageFactory()->resolveAlias( $title->getDBkey() );
325
326 if ( $name === 'Log' ) {
327 $logPage = new LogPage( $par );
328 return wfMessage( 'parentheses' )
329 ->rawParams( $linkRenderer->makeLink( $title, $logPage->getName()->text() ) )
330 ->inLanguage( $lang )
331 ->escaped();
332 }
333 }
334
335 return $linkRenderer->makeLink( $title );
336 }
337
351 public function addEntry( $action, $target, $comment, $params, $performer ) {
352 // FIXME $params is only documented to accept an array
353 if ( !is_array( $params ) ) {
354 $params = [ $params ];
355 }
356
357 # Trim spaces on user supplied text
358 $comment = trim( $comment ?? '' );
359
360 $this->action = $action;
361 $this->target = $target;
362 $this->comment = $comment;
363 $this->params = self::makeParamBlob( $params );
364
365 if ( !is_object( $performer ) ) {
366 $performer = User::newFromId( $performer );
367 }
368
369 $this->performer = $performer;
370
371 $logEntry = new ManualLogEntry( $this->type, $action );
372 $logEntry->setTarget( $target );
373 $logEntry->setPerformer( $performer );
374 $logEntry->setParameters( $params );
375 // All log entries using the LogPage to insert into the logging table
376 // are using the old logging system and therefore the legacy flag is
377 // needed to say the LogFormatter the parameters have numeric keys
378 $logEntry->setLegacy( true );
379
380 $formatter = MediaWikiServices::getInstance()->getLogFormatterFactory()->newFromEntry( $logEntry );
381 $context = RequestContext::newExtraneousContext( $target );
382 $formatter->setContext( $context );
383
384 $this->actionText = $formatter->getPlainActionText();
385 $this->ircActionText = $formatter->getIRCActionText();
386
387 return $this->saveContent();
388 }
389
396 public static function makeParamBlob( $params ) {
397 return implode( "\n", $params );
398 }
399
406 public static function extractParams( $blob ) {
407 if ( $blob === '' ) {
408 return [];
409 } else {
410 return explode( "\n", $blob );
411 }
412 }
413
419 public function getName() {
420 $logNames = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogNames );
421
422 // BC
423 $key = $logNames[$this->type] ?? 'log-name-' . $this->type;
424
425 return wfMessage( $key );
426 }
427
433 public function getDescription() {
434 $logHeaders = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogHeaders );
435 // BC
436 $key = $logHeaders[$this->type] ?? 'log-description-' . $this->type;
437
438 return wfMessage( $key );
439 }
440
446 public function getRestriction() {
447 $logRestrictions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogRestrictions );
448 // The empty string fallback will
449 // always return true in permission check
450 return $logRestrictions[$this->type] ?? '';
451 }
452
458 public function isRestricted() {
459 $restriction = $this->getRestriction();
460
461 return $restriction !== '' && $restriction !== '*';
462 }
463}
464
466class_alias( LogPage::class, 'LogPage' );
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.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined( 'MW_NO_SESSION') &&MW_ENTRY_POINT !=='cli' $wgLang
Definition Setup.php:558
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
Group all the pieces relevant to the context of a request into one instance.
Base class for language-specific code.
Definition Language.php:82
Class to simplify the use of log pages.
Definition LogPage.php:50
static validTypes()
Get the list of valid log types.
Definition LogPage.php:221
getComment()
Get the comment from the last addEntry() call.
Definition LogPage.php:212
__construct( $type, $rc=true, $udp='skipUDP')
Definition LogPage.php:101
getRcComment()
Get the RC comment from the last addEntry() call.
Definition LogPage.php:173
getRestriction()
Returns the right needed to read this log type.
Definition LogPage.php:446
getDescription()
Description of this log type.
Definition LogPage.php:433
static actionText( $type, $action, $title=null, $skin=null, $params=[], $filterWikilinks=false)
Generate text for a log entry.
Definition LogPage.php:250
addEntry( $action, $target, $comment, $params, $performer)
Add a log entry.
Definition LogPage.php:351
getRcCommentIRC()
Get the RC comment from the last addEntry() call for IRC.
Definition LogPage.php:193
static makeParamBlob( $params)
Create a blob from a parameter array.
Definition LogPage.php:396
getName()
Name of the log.
Definition LogPage.php:419
static isLogType( $type)
Is $type a valid log type.
Definition LogPage.php:233
isRestricted()
Tells if this log is not viewable by all.
Definition LogPage.php:458
static extractParams( $blob)
Extract a parameter array from a blob.
Definition LogPage.php:406
Class for creating new log entries and inserting them into the database.
A class containing constants representing the names of configuration variables.
const LogRestrictions
Name constant for the LogRestrictions setting, for use with Config::get()
const LogNames
Name constant for the LogNames setting, for use with Config::get()
const LogTypes
Name constant for the LogTypes setting, for use with Config::get()
const LogHeaders
Name constant for the LogHeaders setting, for use with Config::get()
const LogActions
Name constant for the LogActions setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:155
Utility class for creating and reading rows in the recentchanges table.
Parent class for all special pages.
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,...
Stub object for the user language.
Represents a title within MediaWiki.
Definition Title.php:78
getDBkey()
Get the main part with underscores.
Definition Title.php:1031
isSpecialPage()
Returns true if this is a special page.
Definition Title.php:1249
getPrefixedText()
Get the prefixed title with spaces.
Definition Title.php:1855
User class for the MediaWiki software.
Definition User.php:120
The base class for all skins.
Definition Skin.php:63
Interface for objects representing user identity.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...