MediaWiki master
LogPage.php
Go to the documentation of this file.
1<?php
12namespace MediaWiki\Logging;
13
24
34class LogPage {
35 public const DELETED_ACTION = 1;
36 public const DELETED_COMMENT = 2;
37 public const DELETED_USER = 4;
38 public const DELETED_RESTRICTED = 8;
39
40 // Convenience fields
41 public const SUPPRESSED_USER = self::DELETED_USER | self::DELETED_RESTRICTED;
42 public const SUPPRESSED_ACTION = self::DELETED_ACTION | self::DELETED_RESTRICTED;
43
46
48 public $sendToUDP;
49
51 private $ircActionText;
52
54 private $actionText;
55
59 private $type;
60
64 private $action;
65
67 private $comment;
68
70 private $params;
71
73 private $performer;
74
76 private $target;
77
85 public function __construct( $type, $rc = true, $udp = 'skipUDP' ) {
86 $this->type = $type;
87 $this->updateRecentChanges = $rc;
88 $this->sendToUDP = ( $udp == 'UDP' );
89 }
90
94 protected function saveContent() {
96 $logRestrictions = $services->getMainConfig()->get( MainConfigNames::LogRestrictions );
97 $recentChangeStore = $services->getRecentChangeStore();
98 $recentChangeRCFeedNotifier = $services->getRecentChangeRCFeedNotifier();
99 $dbw = $services->getConnectionProvider()->getPrimaryDatabase();
100
101 $now = wfTimestampNow();
102 $actorId = $services->getActorNormalization()
103 ->acquireActorId( $this->performer, $dbw );
104 $data = [
105 'log_type' => $this->type,
106 'log_action' => $this->action,
107 'log_timestamp' => $dbw->timestamp( $now ),
108 'log_actor' => $actorId,
109 'log_namespace' => $this->target->getNamespace(),
110 'log_title' => $this->target->getDBkey(),
111 'log_page' => $this->target->getArticleID(),
112 'log_params' => $this->params
113 ];
114 $data += $services->getCommentStore()->insert(
115 $dbw,
116 'log_comment',
117 $this->comment
118 );
119 $dbw->newInsertQueryBuilder()
120 ->insertInto( 'logging' )
121 ->row( $data )
122 ->caller( __METHOD__ )->execute();
123 $newId = $dbw->insertId();
124
125 // Don't add private logs to RC or send them to UDP
126 if ( isset( $logRestrictions[$this->type] ) && $logRestrictions[$this->type] != '*' ) {
127 return $newId;
128 }
129
130 if ( $this->updateRecentChanges ) {
131 $titleObj = SpecialPage::getTitleFor( 'Log', $this->type );
132
133 $recentChange = $recentChangeStore->createLogRecentChange(
134 $now, $titleObj, $this->performer, $this->getRcComment(), '',
135 $this->type, $this->action, $this->target, $this->comment,
136 $this->params, $newId, $this->getRcCommentIRC()
137 );
138 $recentChangeStore->insertRecentChange( $recentChange );
139 } elseif ( $this->sendToUDP ) {
140 // Notify external application via UDP.
141 // We send this to IRC but do not want to add it the RC table.
142 $titleObj = SpecialPage::getTitleFor( 'Log', $this->type );
143 $recentChange = $recentChangeStore->createLogRecentChange(
144 $now, $titleObj, $this->performer, $this->getRcComment(), '',
145 $this->type, $this->action, $this->target, $this->comment,
146 $this->params, $newId, $this->getRcCommentIRC()
147 );
148 $recentChangeRCFeedNotifier->notifyRCFeeds( $recentChange );
149 }
150
151 return $newId;
152 }
153
159 public function getRcComment() {
160 $rcComment = $this->actionText;
161
162 if ( $this->comment != '' ) {
163 if ( $rcComment == '' ) {
164 $rcComment = $this->comment;
165 } else {
166 $rcComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() .
167 $this->comment;
168 }
169 }
170
171 return $rcComment;
172 }
173
179 public function getRcCommentIRC() {
180 $rcComment = $this->ircActionText;
181
182 if ( $this->comment != '' ) {
183 if ( $rcComment == '' ) {
184 $rcComment = $this->comment;
185 } else {
186 $rcComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() .
187 $this->comment;
188 }
189 }
190
191 return $rcComment;
192 }
193
198 public function getComment() {
199 return $this->comment;
200 }
201
207 public static function validTypes() {
208 $logTypes = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogTypes );
209
210 return $logTypes;
211 }
212
219 public static function isLogType( $type ) {
220 return in_array( $type, self::validTypes() );
221 }
222
236 public static function actionText( $type, $action, $title = null, $skin = null,
237 $params = [], $filterWikilinks = false
238 ) {
239 $config = MediaWikiServices::getInstance()->getMainConfig();
240 $key = "$type/$action";
241
242 $logActions = $config->get( MainConfigNames::LogActions );
243
244 if ( isset( $logActions[$key] ) ) {
245 $message = $logActions[$key];
246 } else {
247 wfDebug( "LogPage::actionText - unknown action $key" );
248 $message = "log-unknown-action";
249 $params = [ $key ];
250 }
251
252 if ( $skin === null ) {
253 $langObj = MediaWikiServices::getInstance()->getContentLanguage();
254 $langObjOrNull = null;
255 } else {
256 $langObj = $langObjOrNull = $skin->getLanguage();
257 }
258 if ( $title === null ) {
259 $rv = wfMessage( $message )->inLanguage( $langObj )->escaped();
260 } else {
261 $titleLink = self::getTitleLink( $title, $langObjOrNull );
262
263 if ( count( $params ) == 0 ) {
264 $rv = wfMessage( $message )->rawParams( $titleLink )
265 ->inLanguage( $langObj )->escaped();
266 } else {
267 array_unshift( $params, $titleLink );
268
269 $rv = wfMessage( $message )->rawParams( $params )
270 ->inLanguage( $langObj )->escaped();
271 }
272 }
273
274 // For the perplexed, this feature was added in r7855 by Erik.
275 // The feature was added because we liked adding [[$1]] in our log entries
276 // but the log entries are parsed as Wikitext on RecentChanges but as HTML
277 // on Special:Log. The hack is essentially that [[$1]] represented a link
278 // to the title in question. The first parameter to the HTML version (Special:Log)
279 // is that link in HTML form, and so this just gets rid of the ugly [[]].
280 // However, this is a horrible hack and it doesn't work like you expect if, say,
281 // you want to link to something OTHER than the title of the log entry.
282 // The real problem, which Erik was trying to fix (and it sort-of works now) is
283 // that the same messages are being treated as both wikitext *and* HTML.
284 if ( $filterWikilinks ) {
285 $rv = str_replace( '[[', '', $rv );
286 $rv = str_replace( ']]', '', $rv );
287 }
288
289 return $rv;
290 }
291
297 private static function getTitleLink( Title $title, ?Language $lang ): string {
298 if ( !$lang ) {
299 return $title->getPrefixedText();
300 }
301
302 $services = MediaWikiServices::getInstance();
303 $linkRenderer = $services->getLinkRenderer();
304
305 if ( $title->isSpecialPage() ) {
306 [ $name, $par ] = $services->getSpecialPageFactory()->resolveAlias( $title->getDBkey() );
307
308 if ( $name === 'Log' ) {
309 $logPage = new LogPage( $par ?? '' );
310 return wfMessage( 'parentheses' )
311 ->rawParams( $linkRenderer->makeLink( $title, $logPage->getName()->text() ) )
312 ->inLanguage( $lang )
313 ->escaped();
314 }
315 }
316
317 return $linkRenderer->makeLink( $title );
318 }
319
333 public function addEntry( $action, $target, $comment, $params, $performer ) {
334 // FIXME $params is only documented to accept an array
335 if ( !is_array( $params ) ) {
336 $params = [ $params ];
337 }
338
339 # Trim spaces on user supplied text
340 $comment = trim( $comment ?? '' );
341
342 $this->action = $action;
343 $this->target = $target;
344 $this->comment = $comment;
345 $this->params = self::makeParamBlob( $params );
346
347 if ( !is_object( $performer ) ) {
348 $performer = User::newFromId( $performer );
349 }
350
351 $this->performer = $performer;
352
353 $logEntry = new ManualLogEntry( $this->type, $action );
354 $logEntry->setTarget( $target );
355 $logEntry->setPerformer( $performer );
356 $logEntry->setParameters( $params );
357 // All log entries using the LogPage to insert into the logging table
358 // are using the old logging system and therefore the legacy flag is
359 // needed to say the LogFormatter the parameters have numeric keys
360 $logEntry->setLegacy( true );
361
362 $formatter = MediaWikiServices::getInstance()->getLogFormatterFactory()->newFromEntry( $logEntry );
363 $context = RequestContext::newExtraneousContext( $target );
364 $formatter->setContext( $context );
365
366 $this->actionText = $formatter->getPlainActionText();
367 $this->ircActionText = $formatter->getIRCActionText();
368
369 return $this->saveContent();
370 }
371
378 public static function makeParamBlob( $params ) {
379 return implode( "\n", $params );
380 }
381
388 public static function extractParams( $blob ) {
389 if ( $blob === '' ) {
390 return [];
391 } else {
392 return explode( "\n", $blob );
393 }
394 }
395
401 public function getName() {
402 $logNames = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogNames );
403
404 // BC
405 $key = $logNames[$this->type] ?? 'log-name-' . $this->type;
406
407 return wfMessage( $key );
408 }
409
415 public function getDescription() {
416 $logHeaders = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogHeaders );
417 // BC
418 $key = $logHeaders[$this->type] ?? 'log-description-' . $this->type;
419
420 return wfMessage( $key );
421 }
422
428 public function getRestriction() {
429 $logRestrictions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogRestrictions );
430 // The empty string fallback will
431 // always return true in permission check
432 return $logRestrictions[$this->type] ?? '';
433 }
434
440 public function isRestricted() {
441 $restriction = $this->getRestriction();
442
443 return $restriction !== '' && $restriction !== '*';
444 }
445}
446
448class_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_SETUP_CALLBACK'))
Definition WebStart.php:69
Group all the pieces relevant to the context of a request into one instance.
Base class for language-specific code.
Definition Language.php:65
Class to simplify the use of log pages.
Definition LogPage.php:34
static validTypes()
Get the list of valid log types.
Definition LogPage.php:207
getComment()
Get the comment from the last addEntry() call.
Definition LogPage.php:198
__construct( $type, $rc=true, $udp='skipUDP')
Definition LogPage.php:85
getRcComment()
Get the RC comment from the last addEntry() call.
Definition LogPage.php:159
getRestriction()
Returns the right needed to read this log type.
Definition LogPage.php:428
getDescription()
Description of this log type.
Definition LogPage.php:415
static actionText( $type, $action, $title=null, $skin=null, $params=[], $filterWikilinks=false)
Generate text for a log entry.
Definition LogPage.php:236
addEntry( $action, $target, $comment, $params, $performer)
Add a log entry.
Definition LogPage.php:333
getRcCommentIRC()
Get the RC comment from the last addEntry() call for IRC.
Definition LogPage.php:179
static makeParamBlob( $params)
Create a blob from a parameter array.
Definition LogPage.php:378
getName()
Name of the log.
Definition LogPage.php:401
static isLogType( $type)
Is $type a valid log type.
Definition LogPage.php:219
isRestricted()
Tells if this log is not viewable by all.
Definition LogPage.php:440
static extractParams( $blob)
Extract a parameter array from a blob.
Definition LogPage.php:388
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:144
The base class for all skins.
Definition Skin.php:53
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,...
Represents a title within MediaWiki.
Definition Title.php:69
getDBkey()
Get the main part with underscores.
Definition Title.php:1028
isSpecialPage()
Returns true if this is a special page.
Definition Title.php:1246
getPrefixedText()
Get the prefixed title with spaces.
Definition Title.php:1857
User class for the MediaWiki software.
Definition User.php:130
Interface for objects representing user identity.