MediaWiki master
LogPage.php
Go to the documentation of this file.
1<?php
12namespace MediaWiki\Logging;
13
25
35class LogPage {
36 public const DELETED_ACTION = 1;
37 public const DELETED_COMMENT = 2;
38 public const DELETED_USER = 4;
39 public const DELETED_RESTRICTED = 8;
40
41 // Convenience fields
42 public const SUPPRESSED_USER = self::DELETED_USER | self::DELETED_RESTRICTED;
43 public const SUPPRESSED_ACTION = self::DELETED_ACTION | self::DELETED_RESTRICTED;
44
47
49 public $sendToUDP;
50
52 private $ircActionText;
53
55 private $actionText;
56
60 private $type;
61
65 private $action;
66
68 private $comment;
69
71 private $params;
72
74 private $performer;
75
77 private $target;
78
86 public function __construct( $type, $rc = true, $udp = 'skipUDP' ) {
87 $this->type = $type;
88 $this->updateRecentChanges = $rc;
89 $this->sendToUDP = ( $udp == 'UDP' );
90 }
91
95 protected function saveContent() {
97 $logRestrictions = $services->getMainConfig()->get( MainConfigNames::LogRestrictions );
98 $recentChangeStore = $services->getRecentChangeStore();
99 $recentChangeRCFeedNotifier = $services->getRecentChangeRCFeedNotifier();
100 $dbw = $services->getConnectionProvider()->getPrimaryDatabase();
101
102 $now = wfTimestampNow();
103 $actorId = $services->getActorNormalization()
104 ->acquireActorId( $this->performer, $dbw );
105 $data = [
106 'log_type' => $this->type,
107 'log_action' => $this->action,
108 'log_timestamp' => $dbw->timestamp( $now ),
109 'log_actor' => $actorId,
110 'log_namespace' => $this->target->getNamespace(),
111 'log_title' => $this->target->getDBkey(),
112 'log_page' => $this->target->getArticleID(),
113 'log_params' => $this->params
114 ];
115 $data += $services->getCommentStore()->insert(
116 $dbw,
117 'log_comment',
118 $this->comment
119 );
120 $dbw->newInsertQueryBuilder()
121 ->insertInto( 'logging' )
122 ->row( $data )
123 ->caller( __METHOD__ )->execute();
124 $newId = $dbw->insertId();
125
126 // Don't add private logs to RC or send them to UDP
127 if ( isset( $logRestrictions[$this->type] ) && $logRestrictions[$this->type] != '*' ) {
128 return $newId;
129 }
130
131 if ( $this->updateRecentChanges ) {
132 $titleObj = SpecialPage::getTitleFor( 'Log', $this->type );
133
134 $recentChange = $recentChangeStore->createLogRecentChange(
135 $now, $titleObj, $this->performer, $this->getRcComment(), '',
136 $this->type, $this->action, $this->target, $this->comment,
137 $this->params, $newId, $this->getRcCommentIRC()
138 );
139 $recentChangeStore->insertRecentChange( $recentChange );
140 } elseif ( $this->sendToUDP ) {
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 );
144 $recentChange = $recentChangeStore->createLogRecentChange(
145 $now, $titleObj, $this->performer, $this->getRcComment(), '',
146 $this->type, $this->action, $this->target, $this->comment,
147 $this->params, $newId, $this->getRcCommentIRC()
148 );
149 $recentChangeRCFeedNotifier->notifyRCFeeds( $recentChange );
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 $key = "$type/$action";
243
244 $logActions = $config->get( MainConfigNames::LogActions );
245
246 if ( isset( $logActions[$key] ) ) {
247 $message = $logActions[$key];
248 } else {
249 wfDebug( "LogPage::actionText - unknown action $key" );
250 $message = "log-unknown-action";
251 $params = [ $key ];
252 }
253
254 if ( $skin === null ) {
255 $langObj = MediaWikiServices::getInstance()->getContentLanguage();
256 $langObjOrNull = null;
257 } else {
258 // TODO Is $skin->getLanguage() safe here?
259 StubUserLang::unstub( $wgLang );
260 $langObj = $wgLang;
261 $langObjOrNull = $wgLang;
262 }
263 if ( $title === null ) {
264 $rv = wfMessage( $message )->inLanguage( $langObj )->escaped();
265 } else {
266 $titleLink = self::getTitleLink( $title, $langObjOrNull );
267
268 if ( count( $params ) == 0 ) {
269 $rv = wfMessage( $message )->rawParams( $titleLink )
270 ->inLanguage( $langObj )->escaped();
271 } else {
272 array_unshift( $params, $titleLink );
273
274 $rv = wfMessage( $message )->rawParams( $params )
275 ->inLanguage( $langObj )->escaped();
276 }
277 }
278
279 // For the perplexed, this feature was added in r7855 by Erik.
280 // The feature was added because we liked adding [[$1]] in our log entries
281 // but the log entries are parsed as Wikitext on RecentChanges but as HTML
282 // on Special:Log. The hack is essentially that [[$1]] represented a link
283 // to the title in question. The first parameter to the HTML version (Special:Log)
284 // is that link in HTML form, and so this just gets rid of the ugly [[]].
285 // However, this is a horrible hack and it doesn't work like you expect if, say,
286 // you want to link to something OTHER than the title of the log entry.
287 // The real problem, which Erik was trying to fix (and it sort-of works now) is
288 // that the same messages are being treated as both wikitext *and* HTML.
289 if ( $filterWikilinks ) {
290 $rv = str_replace( '[[', '', $rv );
291 $rv = str_replace( ']]', '', $rv );
292 }
293
294 return $rv;
295 }
296
302 private static function getTitleLink( Title $title, ?Language $lang ): string {
303 if ( !$lang ) {
304 return $title->getPrefixedText();
305 }
306
307 $services = MediaWikiServices::getInstance();
308 $linkRenderer = $services->getLinkRenderer();
309
310 if ( $title->isSpecialPage() ) {
311 [ $name, $par ] = $services->getSpecialPageFactory()->resolveAlias( $title->getDBkey() );
312
313 if ( $name === 'Log' ) {
314 $logPage = new LogPage( $par ?? '' );
315 return wfMessage( 'parentheses' )
316 ->rawParams( $linkRenderer->makeLink( $title, $logPage->getName()->text() ) )
317 ->inLanguage( $lang )
318 ->escaped();
319 }
320 }
321
322 return $linkRenderer->makeLink( $title );
323 }
324
338 public function addEntry( $action, $target, $comment, $params, $performer ) {
339 // FIXME $params is only documented to accept an array
340 if ( !is_array( $params ) ) {
341 $params = [ $params ];
342 }
343
344 # Trim spaces on user supplied text
345 $comment = trim( $comment ?? '' );
346
347 $this->action = $action;
348 $this->target = $target;
349 $this->comment = $comment;
350 $this->params = self::makeParamBlob( $params );
351
352 if ( !is_object( $performer ) ) {
353 $performer = User::newFromId( $performer );
354 }
355
356 $this->performer = $performer;
357
358 $logEntry = new ManualLogEntry( $this->type, $action );
359 $logEntry->setTarget( $target );
360 $logEntry->setPerformer( $performer );
361 $logEntry->setParameters( $params );
362 // All log entries using the LogPage to insert into the logging table
363 // are using the old logging system and therefore the legacy flag is
364 // needed to say the LogFormatter the parameters have numeric keys
365 $logEntry->setLegacy( true );
366
367 $formatter = MediaWikiServices::getInstance()->getLogFormatterFactory()->newFromEntry( $logEntry );
368 $context = RequestContext::newExtraneousContext( $target );
369 $formatter->setContext( $context );
370
371 $this->actionText = $formatter->getPlainActionText();
372 $this->ircActionText = $formatter->getIRCActionText();
373
374 return $this->saveContent();
375 }
376
383 public static function makeParamBlob( $params ) {
384 return implode( "\n", $params );
385 }
386
393 public static function extractParams( $blob ) {
394 if ( $blob === '' ) {
395 return [];
396 } else {
397 return explode( "\n", $blob );
398 }
399 }
400
406 public function getName() {
407 $logNames = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogNames );
408
409 // BC
410 $key = $logNames[$this->type] ?? 'log-name-' . $this->type;
411
412 return wfMessage( $key );
413 }
414
420 public function getDescription() {
421 $logHeaders = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogHeaders );
422 // BC
423 $key = $logHeaders[$this->type] ?? 'log-description-' . $this->type;
424
425 return wfMessage( $key );
426 }
427
433 public function getRestriction() {
434 $logRestrictions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LogRestrictions );
435 // The empty string fallback will
436 // always return true in permission check
437 return $logRestrictions[$this->type] ?? '';
438 }
439
445 public function isRestricted() {
446 $restriction = $this->getRestriction();
447
448 return $restriction !== '' && $restriction !== '*';
449 }
450}
451
453class_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(MW_ENTRY_POINT==='index') if(!defined( 'MW_NO_SESSION') &&MW_ENTRY_POINT !=='cli' $wgLang
Definition Setup.php:551
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:68
Class to simplify the use of log pages.
Definition LogPage.php:35
static validTypes()
Get the list of valid log types.
Definition LogPage.php:208
getComment()
Get the comment from the last addEntry() call.
Definition LogPage.php:199
__construct( $type, $rc=true, $udp='skipUDP')
Definition LogPage.php:86
getRcComment()
Get the RC comment from the last addEntry() call.
Definition LogPage.php:160
getRestriction()
Returns the right needed to read this log type.
Definition LogPage.php:433
getDescription()
Description of this log type.
Definition LogPage.php:420
static actionText( $type, $action, $title=null, $skin=null, $params=[], $filterWikilinks=false)
Generate text for a log entry.
Definition LogPage.php:237
addEntry( $action, $target, $comment, $params, $performer)
Add a log entry.
Definition LogPage.php:338
getRcCommentIRC()
Get the RC comment from the last addEntry() call for IRC.
Definition LogPage.php:180
static makeParamBlob( $params)
Create a blob from a parameter array.
Definition LogPage.php:383
getName()
Name of the log.
Definition LogPage.php:406
static isLogType( $type)
Is $type a valid log type.
Definition LogPage.php:220
isRestricted()
Tells if this log is not viewable by all.
Definition LogPage.php:445
static extractParams( $blob)
Extract a parameter array from a blob.
Definition LogPage.php:393
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:52
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: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.