summaryrefslogtreecommitdiff
path: root/includes/logging/LogFormatter.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/logging/LogFormatter.php')
-rw-r--r--includes/logging/LogFormatter.php393
1 files changed, 365 insertions, 28 deletions
diff --git a/includes/logging/LogFormatter.php b/includes/logging/LogFormatter.php
index 24490eed..7586bb65 100644
--- a/includes/logging/LogFormatter.php
+++ b/includes/logging/LogFormatter.php
@@ -2,6 +2,21 @@
/**
* Contains classes for formatting log entries
*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
* @file
* @author Niklas Laxström
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
@@ -94,24 +109,24 @@ class LogFormatter {
/**
* Set the visibility restrictions for displaying content.
- * If set to public, and an item is deleted, then it will be replaced
+ * If set to public, and an item is deleted, then it will be replaced
* with a placeholder even if the context user is allowed to view it.
* @param $audience integer self::FOR_THIS_USER or self::FOR_PUBLIC
*/
public function setAudience( $audience ) {
$this->audience = ( $audience == self::FOR_THIS_USER )
- ? self::FOR_THIS_USER
+ ? self::FOR_THIS_USER
: self::FOR_PUBLIC;
}
/**
* Check if a log item can be displayed
* @param $field integer LogPage::DELETED_* constant
- * @return bool
+ * @return bool
*/
protected function canView( $field ) {
if ( $this->audience == self::FOR_THIS_USER ) {
- return LogEventsList::userCanBitfield(
+ return LogEventsList::userCanBitfield(
$this->entry->getDeleted(), $field, $this->context->getUser() );
} else {
return !$this->entry->isDeleted( $field );
@@ -148,14 +163,34 @@ class LogFormatter {
* @see getActionText()
* @return string text
*/
+ public function getIRCActionComment() {
+ $actionComment = $this->getIRCActionText();
+ $comment = $this->entry->getComment();
+
+ if ( $comment != '' ) {
+ if ( $actionComment == '' ) {
+ $actionComment = $comment;
+ } else {
+ $actionComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $comment;
+ }
+ }
+
+ return $actionComment;
+ }
+
+ /**
+ * Even uglier hack to maintain backwards compatibilty with IRC bots
+ * (bug 34508).
+ * @see getActionText()
+ * @return string text
+ */
public function getIRCActionText() {
$this->plaintext = true;
- $text = $this->getActionText();
+ $this->irctext = true;
$entry = $this->entry;
$parameters = $entry->getParameters();
// @see LogPage::actionText()
- $msgOpts = array( 'parsemag', 'escape', 'replaceafter', 'content' );
// Text of title the action is aimed at.
$target = $entry->getTarget()->getPrefixedText() ;
$text = null;
@@ -164,11 +199,13 @@ class LogFormatter {
switch( $entry->getSubtype() ) {
case 'move':
$movesource = $parameters['4::target'];
- $text = wfMsgExt( '1movedto2', $msgOpts, $target, $movesource );
+ $text = wfMessage( '1movedto2' )
+ ->rawParams( $target, $movesource )->inContentLanguage()->escaped();
break;
case 'move_redir':
$movesource = $parameters['4::target'];
- $text = wfMsgExt( '1movedto2_redir', $msgOpts, $target, $movesource );
+ $text = wfMessage( '1movedto2_redir' )
+ ->rawParams( $target, $movesource )->inContentLanguage()->escaped();
break;
case 'move-noredirect':
break;
@@ -180,10 +217,12 @@ class LogFormatter {
case 'delete':
switch( $entry->getSubtype() ) {
case 'delete':
- $text = wfMsgExt( 'deletedarticle', $msgOpts, $target );
+ $text = wfMessage( 'deletedarticle' )
+ ->rawParams( $target )->inContentLanguage()->escaped();
break;
case 'restore':
- $text = wfMsgExt( 'undeletedarticle', $msgOpts, $target );
+ $text = wfMessage( 'undeletedarticle' )
+ ->rawParams( $target )->inContentLanguage()->escaped();
break;
//case 'revision': // Revision deletion
//case 'event': // Log deletion
@@ -197,24 +236,46 @@ class LogFormatter {
// Create a diff link to the patrolled revision
if ( $entry->getSubtype() === 'patrol' ) {
$diffLink = htmlspecialchars(
- wfMsgForContent( 'patrol-log-diff', $parameters['4::curid'] ) );
- $text = wfMsgForContent( 'patrol-log-line', $diffLink, "[[$target]]", "" );
+ wfMessage( 'patrol-log-diff', $parameters['4::curid'] )
+ ->inContentLanguage()->text() );
+ $text = wfMessage( 'patrol-log-line', $diffLink, "[[$target]]", "" )
+ ->inContentLanguage()->text();
} else {
// broken??
}
break;
+ case 'protect':
+ switch( $entry->getSubtype() ) {
+ case 'protect':
+ $text = wfMessage( 'protectedarticle' )
+ ->rawParams( $target . ' ' . $parameters[0] )->inContentLanguage()->escaped();
+ break;
+ case 'unprotect':
+ $text = wfMessage( 'unprotectedarticle' )
+ ->rawParams( $target )->inContentLanguage()->escaped();
+ break;
+ case 'modify':
+ $text = wfMessage( 'modifiedarticleprotection' )
+ ->rawParams( $target . ' ' . $parameters[0] )->inContentLanguage()->escaped();
+ break;
+ }
+ break;
+
case 'newusers':
switch( $entry->getSubtype() ) {
case 'newusers':
case 'create':
- $text = wfMsgExt( 'newuserlog-create-entry', $msgOpts /* no params */ );
+ $text = wfMessage( 'newuserlog-create-entry' )
+ ->inContentLanguage()->escaped();
break;
case 'create2':
- $text = wfMsgExt( 'newuserlog-create2-entry', $msgOpts, $target );
+ $text = wfMessage( 'newuserlog-create2-entry' )
+ ->rawParams( $target )->inContentLanguage()->escaped();
break;
case 'autocreate':
- $text = wfMsgExt( 'newuserlog-autocreate-entry', $msgOpts /* no params */ );
+ $text = wfMessage( 'newuserlog-autocreate-entry' )
+ ->inContentLanguage()->escaped();
break;
}
break;
@@ -222,14 +283,17 @@ class LogFormatter {
case 'upload':
switch( $entry->getSubtype() ) {
case 'upload':
- $text = wfMsgExt( 'uploadedimage', $msgOpts, $target );
+ $text = wfMessage( 'uploadedimage' )
+ ->rawParams( $target )->inContentLanguage()->escaped();
break;
case 'overwrite':
- $text = wfMsgExt( 'overwroteimage', $msgOpts, $target );
+ $text = wfMessage( 'overwroteimage' )
+ ->rawParams( $target )->inContentLanguage()->escaped();
break;
}
break;
+
// case 'suppress' --private log -- aaron (sign your messages so we know who to blame in a few years :-D)
// default:
}
@@ -238,6 +302,7 @@ class LogFormatter {
}
$this->plaintext = false;
+ $this->irctext = false;
return $text;
}
@@ -266,7 +331,7 @@ class LogFormatter {
* Returns a sentence describing the log action. Usually
* a Message object is returned, but old style log types
* and entries might return pre-escaped html string.
- * @return Message|pre-escaped html
+ * @return Message|string pre-escaped html
*/
protected function getActionMessage() {
$message = $this->msg( $this->getMessageKey() );
@@ -289,6 +354,15 @@ class LogFormatter {
}
/**
+ * Returns extra links that comes after the action text, like "revert", etc.
+ *
+ * @return string
+ */
+ public function getActionLinks() {
+ return '';
+ }
+
+ /**
* Extracts the optional extra parameters for use in action messages.
* The array indexes start from number 3.
* @return array
@@ -373,6 +447,7 @@ class LogFormatter {
* Provides the name of the user who performed the log action.
* Used as part of log action message or standalone, depending
* which parts of the log entry has been hidden.
+ * @return String
*/
public function getPerformerElement() {
if ( $this->canView( LogPage::DELETED_USER ) ) {
@@ -442,9 +517,7 @@ class LogFormatter {
* @return Message
*/
protected function msg( $key ) {
- return wfMessage( $key )
- ->inLanguage( $this->context->getLanguage() )
- ->title( $this->context->getTitle() );
+ return $this->context->msg( $key );
}
protected function makeUserLink( User $user ) {
@@ -457,11 +530,9 @@ class LogFormatter {
);
if ( $this->linkFlood ) {
- $element .= Linker::userToolLinks(
+ $element .= Linker::userToolLinksRedContribs(
$user->getId(),
$user->getName(),
- true, // Red if no edits
- 0, // Flags
$user->getEditCount()
);
}
@@ -488,6 +559,41 @@ class LogFormatter {
* @since 1.19
*/
class LegacyLogFormatter extends LogFormatter {
+
+ /**
+ * Backward compatibility for extension changing the comment from
+ * the LogLine hook. This will be set by the first call on getComment(),
+ * then it might be modified by the hook when calling getActionLinks(),
+ * so that the modified value will be returned when calling getComment()
+ * a second time.
+ *
+ * @var string|null
+ */
+ private $comment = null;
+
+ /**
+ * Cache for the result of getActionLinks() so that it does not need to
+ * run multiple times depending on the order that getComment() and
+ * getActionLinks() are called.
+ *
+ * @var string|null
+ */
+ private $revert = null;
+
+ public function getComment() {
+ if ( $this->comment === null ) {
+ $this->comment = parent::getComment();
+ }
+
+ // Make sure we execute the LogLine hook so that we immediately return
+ // the correct value.
+ if ( $this->revert === null ) {
+ $this->getActionLinks();
+ }
+
+ return $this->comment;
+ }
+
protected function getActionMessage() {
$entry = $this->entry;
$action = LogPage::actionText(
@@ -500,9 +606,104 @@ class LegacyLogFormatter extends LogFormatter {
);
$performer = $this->getPerformerElement();
- return $performer . $this->msg( 'word-separator' )->text() . $action;
+ if ( !$this->irctext ) {
+ $action = $performer . $this->msg( 'word-separator' )->text() . $action;
+ }
+
+ return $action;
}
+ public function getActionLinks() {
+ if ( $this->revert !== null ) {
+ return $this->revert;
+ }
+
+ if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
+ return $this->revert = '';
+ }
+
+ $title = $this->entry->getTarget();
+ $type = $this->entry->getType();
+ $subtype = $this->entry->getSubtype();
+
+ // Show unblock/change block link
+ if ( ( $type == 'block' || $type == 'suppress' ) && ( $subtype == 'block' || $subtype == 'reblock' ) ) {
+ if ( !$this->context->getUser()->isAllowed( 'block' ) ) {
+ return '';
+ }
+
+ $links = array(
+ Linker::linkKnown(
+ SpecialPage::getTitleFor( 'Unblock', $title->getDBkey() ),
+ $this->msg( 'unblocklink' )->escaped()
+ ),
+ Linker::linkKnown(
+ SpecialPage::getTitleFor( 'Block', $title->getDBkey() ),
+ $this->msg( 'change-blocklink' )->escaped()
+ )
+ );
+ return $this->msg( 'parentheses' )->rawParams(
+ $this->context->getLanguage()->pipeList( $links ) )->escaped();
+ // Show change protection link
+ } elseif ( $type == 'protect' && ( $subtype == 'protect' || $subtype == 'modify' || $subtype == 'unprotect' ) ) {
+ $links = array(
+ Linker::link( $title,
+ $this->msg( 'hist' )->escaped(),
+ array(),
+ array(
+ 'action' => 'history',
+ 'offset' => $this->entry->getTimestamp()
+ )
+ )
+ );
+ if ( $this->context->getUser()->isAllowed( 'protect' ) ) {
+ $links[] = Linker::linkKnown(
+ $title,
+ $this->msg( 'protect_change' )->escaped(),
+ array(),
+ array( 'action' => 'protect' )
+ );
+ }
+ return $this->msg( 'parentheses' )->rawParams(
+ $this->context->getLanguage()->pipeList( $links ) )->escaped();
+ // Show unmerge link
+ } elseif( $type == 'merge' && $subtype == 'merge' ) {
+ if ( !$this->context->getUser()->isAllowed( 'mergehistory' ) ) {
+ return '';
+ }
+
+ $params = $this->extractParameters();
+ $revert = Linker::linkKnown(
+ SpecialPage::getTitleFor( 'MergeHistory' ),
+ $this->msg( 'revertmerge' )->escaped(),
+ array(),
+ array(
+ 'target' => $params[3],
+ 'dest' => $title->getPrefixedDBkey(),
+ 'mergepoint' => $params[4]
+ )
+ );
+ return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
+ }
+
+ // Do nothing. The implementation is handled by the hook modifiying the
+ // passed-by-ref parameters. This also changes the default value so that
+ // getComment() and getActionLinks() do not call them indefinitely.
+ $this->revert = '';
+
+ // This is to populate the $comment member of this instance so that it
+ // can be modified when calling the hook just below.
+ if ( $this->comment === null ) {
+ $this->getComment();
+ }
+
+ $params = $this->entry->getParameters();
+
+ wfRunHooks( 'LogLine', array( $type, $subtype, $title, $params,
+ &$this->comment, &$this->revert, $this->entry->getTimestamp() ) );
+
+ return $this->revert;
+ }
}
/**
@@ -532,6 +733,34 @@ class MoveLogFormatter extends LogFormatter {
$params[3] = Message::rawParam( $newname );
return $params;
}
+
+ public function getActionLinks() {
+ if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) // Action is hidden
+ || $this->entry->getSubtype() !== 'move'
+ || !$this->context->getUser()->isAllowed( 'move' ) )
+ {
+ return '';
+ }
+
+ $params = $this->extractParameters();
+ $destTitle = Title::newFromText( $params[3] );
+ if ( !$destTitle ) {
+ return '';
+ }
+
+ $revert = Linker::linkKnown(
+ SpecialPage::getTitleFor( 'Movepage' ),
+ $this->msg( 'revertmove' )->escaped(),
+ array(),
+ array(
+ 'wpOldTitle' => $destTitle->getPrefixedDBkey(),
+ 'wpNewTitle' => $this->entry->getTarget()->getPrefixedDBkey(),
+ 'wpReason' => $this->msg( 'revertmove' )->inContentLanguage()->text(),
+ 'wpMovetalk' => 0
+ )
+ );
+ return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
+ }
}
/**
@@ -601,6 +830,107 @@ class DeleteLogFormatter extends LogFormatter {
return (int) $string;
}
}
+
+ public function getActionLinks() {
+ $user = $this->context->getUser();
+ if ( !$user->isAllowed( 'deletedhistory' ) || $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
+ return '';
+ }
+
+ switch ( $this->entry->getSubtype() ) {
+ case 'delete': // Show undelete link
+ if( $user->isAllowed( 'undelete' ) ) {
+ $message = 'undeletelink';
+ } else {
+ $message = 'undeleteviewlink';
+ }
+ $revert = Linker::linkKnown(
+ SpecialPage::getTitleFor( 'Undelete' ),
+ $this->msg( $message )->escaped(),
+ array(),
+ array( 'target' => $this->entry->getTarget()->getPrefixedDBkey() )
+ );
+ return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
+
+ case 'revision': // If an edit was hidden from a page give a review link to the history
+ $params = $this->extractParameters();
+ if ( !isset( $params[3] ) || !isset( $params[4] ) ) {
+ return '';
+ }
+
+ // Different revision types use different URL params...
+ $key = $params[3];
+ // This is a CSV of the IDs
+ $ids = explode( ',', $params[4] );
+
+ $links = array();
+
+ // If there's only one item, we can show a diff link
+ if ( count( $ids ) == 1 ) {
+ // Live revision diffs...
+ if ( $key == 'oldid' || $key == 'revision' ) {
+ $links[] = Linker::linkKnown(
+ $this->entry->getTarget(),
+ $this->msg( 'diff' )->escaped(),
+ array(),
+ array(
+ 'diff' => intval( $ids[0] ),
+ 'unhide' => 1
+ )
+ );
+ // Deleted revision diffs...
+ } elseif ( $key == 'artimestamp' || $key == 'archive' ) {
+ $links[] = Linker::linkKnown(
+ SpecialPage::getTitleFor( 'Undelete' ),
+ $this->msg( 'diff' )->escaped(),
+ array(),
+ array(
+ 'target' => $this->entry->getTarget()->getPrefixedDBKey(),
+ 'diff' => 'prev',
+ 'timestamp' => $ids[0]
+ )
+ );
+ }
+ }
+
+ // View/modify link...
+ $links[] = Linker::linkKnown(
+ SpecialPage::getTitleFor( 'Revisiondelete' ),
+ $this->msg( 'revdel-restore' )->escaped(),
+ array(),
+ array(
+ 'target' => $this->entry->getTarget()->getPrefixedText(),
+ 'type' => $key,
+ 'ids' => implode( ',', $ids ),
+ )
+ );
+
+ return $this->msg( 'parentheses' )->rawParams(
+ $this->context->getLanguage()->pipeList( $links ) )->escaped();
+
+ case 'event': // Hidden log items, give review link
+ $params = $this->extractParameters();
+ if ( !isset( $params[3] ) ) {
+ return '';
+ }
+ // This is a CSV of the IDs
+ $query = $params[3];
+ // Link to each hidden object ID, $params[1] is the url param
+ $revert = Linker::linkKnown(
+ SpecialPage::getTitleFor( 'Revisiondelete' ),
+ $this->msg( 'revdel-restore' )->escaped(),
+ array(),
+ array(
+ 'target' => $this->entry->getTarget()->getPrefixedText(),
+ 'type' => 'logging',
+ 'ids' => $query
+ )
+ );
+ return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
+ default:
+ return '';
+ }
+ }
}
/**
@@ -619,7 +949,6 @@ class PatrolLogFormatter extends LogFormatter {
protected function getMessageParameters() {
$params = parent::getMessageParameters();
- $newParams = array_slice( $params, 0, 3 );
$target = $this->entry->getTarget();
$oldid = $params[3];
@@ -637,8 +966,8 @@ class PatrolLogFormatter extends LogFormatter {
$revlink = htmlspecialchars( $revision );
}
- $newParams[3] = Message::rawParam( $revlink );
- return $newParams;
+ $params[3] = Message::rawParam( $revlink );
+ return $params;
}
}
@@ -670,4 +999,12 @@ class NewUsersLogFormatter extends LogFormatter {
}
return parent::getComment();
}
+
+ public function getPreloadTitles() {
+ if ( $this->entry->getSubtype() === 'create2' ) {
+ //add the user talk to LinkBatch for the userLink
+ return array( Title::makeTitle( NS_USER_TALK, $this->entry->getTarget()->getText() ) );
+ }
+ return array();
+ }
}