diff options
Diffstat (limited to 'includes/logging')
-rw-r--r-- | includes/logging/DeleteLogFormatter.php | 208 | ||||
-rw-r--r-- | includes/logging/LogEntry.php | 126 | ||||
-rw-r--r-- | includes/logging/LogEventsList.php | 235 | ||||
-rw-r--r-- | includes/logging/LogFormatter.php | 126 | ||||
-rw-r--r-- | includes/logging/LogPage.php | 178 | ||||
-rw-r--r-- | includes/logging/LogPager.php | 112 | ||||
-rw-r--r-- | includes/logging/MoveLogFormatter.php | 8 | ||||
-rw-r--r-- | includes/logging/NewUsersLogFormatter.php | 3 | ||||
-rw-r--r-- | includes/logging/PageLangLogFormatter.php | 61 | ||||
-rw-r--r-- | includes/logging/PatrolLog.php | 15 | ||||
-rw-r--r-- | includes/logging/PatrolLogFormatter.php | 2 | ||||
-rw-r--r-- | includes/logging/RightsLogFormatter.php | 1 |
12 files changed, 679 insertions, 396 deletions
diff --git a/includes/logging/DeleteLogFormatter.php b/includes/logging/DeleteLogFormatter.php index 01528b7e..8b30e9ba 100644 --- a/includes/logging/DeleteLogFormatter.php +++ b/includes/logging/DeleteLogFormatter.php @@ -36,6 +36,7 @@ class DeleteLogFormatter extends LogFormatter { return "$key-legacy"; } } + return $key; } @@ -47,11 +48,15 @@ class DeleteLogFormatter extends LogFormatter { $params = parent::getMessageParameters(); $subtype = $this->entry->getSubtype(); if ( in_array( $subtype, array( 'event', 'revision' ) ) ) { - // $params[3] here is 'revision' for page revisions, 'oldimage' for file versions, or a comma-separated list of log_ids for log entries. - // $subtype here is 'revision' for page revisions and file versions, or 'event' for log entries. - if ( - ( $subtype === 'event' && count( $params ) === 6 ) || - ( $subtype === 'revision' && isset( $params[3] ) && ( $params[3] === 'revision' || $params[3] === 'oldimage' ) ) + // $params[3] here is 'revision' or 'archive' for page revisions, 'oldimage' or + // 'filearchive' for file versions, or a comma-separated list of log_ids for log + // entries. $subtype here is 'revision' for page revisions and file + // versions, or 'event' for log entries. + if ( ( $subtype === 'event' && count( $params ) === 6 ) + || ( $subtype === 'revision' && isset( $params[3] ) + && ( $params[3] === 'revision' || $params[3] === 'oldimage' + || $params[3] === 'archive' || $params[3] === 'filearchive' ) + ) ) { $paramStart = $subtype === 'revision' ? 4 : 3; @@ -59,9 +64,11 @@ class DeleteLogFormatter extends LogFormatter { $new = $this->parseBitField( $params[$paramStart + 2] ); list( $hid, $unhid, $extra ) = RevisionDeleter::getChanges( $new, $old ); $changes = array(); + // messages used: revdelete-content-hid, revdelete-summary-hid, revdelete-uname-hid foreach ( $hid as $v ) { $changes[] = $this->msg( "$v-hid" )->plain(); } + // messages used: revdelete-content-unhid, revdelete-summary-unhid, revdelete-uname-unhid foreach ( $unhid as $v ) { $changes[] = $this->msg( "$v-unhid" )->plain(); } @@ -74,19 +81,24 @@ class DeleteLogFormatter extends LogFormatter { $newParams[3] = $changeText; $count = count( explode( ',', $params[$paramStart] ) ); $newParams[4] = $this->context->getLanguage()->formatNum( $count ); - return $this->parsedParametersDeleteLog = $newParams; + + $this->parsedParametersDeleteLog = $newParams; + return $this->parsedParametersDeleteLog; } else { - return $this->parsedParametersDeleteLog = array_slice( $params, 0, 3 ); + $this->parsedParametersDeleteLog = array_slice( $params, 0, 3 ); + return $this->parsedParametersDeleteLog; } } - return $this->parsedParametersDeleteLog = $params; + $this->parsedParametersDeleteLog = $params; + return $this->parsedParametersDeleteLog; } protected function parseBitField( $string ) { // Input is like ofield=2134 or just the number if ( strpos( $string, 'field=' ) === 1 ) { list( , $field ) = explode( '=', $string ); + return (int)$field; } else { return (int)$string; @@ -95,102 +107,106 @@ class DeleteLogFormatter extends LogFormatter { public function getActionLinks() { $user = $this->context->getUser(); - if ( !$user->isAllowed( 'deletedhistory' ) || $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) { + 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] - ) - ); + 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 ''; } - } - - // 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(); + // 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] + ) + ); + } + } - case 'event': // Hidden log items, give review link - $params = $this->extractParameters(); - if ( !isset( $params[3] ) ) { + // 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 ''; - } - // 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 ''; } } } diff --git a/includes/logging/LogEntry.php b/includes/logging/LogEntry.php index b2a8e50d..46c55157 100644 --- a/includes/logging/LogEntry.php +++ b/includes/logging/LogEntry.php @@ -33,7 +33,6 @@ * @since 1.19 */ interface LogEntry { - /** * The main log type. * @return string @@ -89,8 +88,8 @@ interface LogEntry { public function getDeleted(); /** - * @param $field Integer: one of LogPage::DELETED_* bitfield constants - * @return Boolean + * @param int $field One of LogPage::DELETED_* bitfield constants + * @return bool */ public function isDeleted( $field ); } @@ -100,7 +99,6 @@ interface LogEntry { * @since 1.19 */ abstract class LogEntryBase implements LogEntry { - public function getFullType() { return $this->getType() . '/' . $this->getSubtype(); } @@ -117,7 +115,6 @@ abstract class LogEntryBase implements LogEntry { public function isLegacy() { return false; } - } /** @@ -160,12 +157,13 @@ class DatabaseLogEntry extends LogEntryBase { /** * Constructs new LogEntry from database result row. * Supports rows from both logging and recentchanges table. - * @param $row + * @param stdClass|array $row * @return DatabaseLogEntry */ public static function newFromRow( $row ) { - if ( is_array( $row ) && isset( $row['rc_logid'] ) ) { - return new RCDatabaseLogEntry( (object)$row ); + $row = (object)$row; + if ( isset( $row->rc_logid ) ) { + return new RCDatabaseLogEntry( $row ); } else { return new self( $row ); } @@ -173,10 +171,17 @@ class DatabaseLogEntry extends LogEntryBase { // Non-static-> - /// Database result row. + /** @var stdClass Database result row. */ protected $row; + + /** @var User */ protected $performer; + /** @var bool Whether the parameters for this log entry are stored in new + * or old format. + */ + protected $legacy; + protected function __construct( $row ) { $this->row = $row; } @@ -202,6 +207,7 @@ class DatabaseLogEntry extends LogEntryBase { public function isLegacy() { // This does the check $this->getParameters(); + return $this->legacy; } @@ -229,6 +235,7 @@ class DatabaseLogEntry extends LogEntryBase { $this->legacy = true; } } + return $this->params; } @@ -246,6 +253,7 @@ class DatabaseLogEntry extends LogEntryBase { $this->performer = User::newFromName( $userText, false ); } } + return $this->performer; } @@ -253,6 +261,7 @@ class DatabaseLogEntry extends LogEntryBase { $namespace = $this->row->log_namespace; $page = $this->row->log_title; $title = Title::makeTitle( $namespace, $page ); + return $title; } @@ -267,7 +276,6 @@ class DatabaseLogEntry extends LogEntryBase { public function getDeleted() { return $this->row->log_deleted; } - } class RCDatabaseLogEntry extends DatabaseLogEntry { @@ -301,6 +309,7 @@ class RCDatabaseLogEntry extends DatabaseLogEntry { $this->performer = User::newFromName( $userText, false ); } } + return $this->performer; } @@ -308,6 +317,7 @@ class RCDatabaseLogEntry extends DatabaseLogEntry { $namespace = $this->row->rc_namespace; $page = $this->row->rc_title; $title = Title::makeTitle( $namespace, $page ); + return $title; } @@ -322,7 +332,6 @@ class RCDatabaseLogEntry extends DatabaseLogEntry { public function getDeleted() { return $this->row->rc_deleted; } - } /** @@ -331,15 +340,35 @@ class RCDatabaseLogEntry extends DatabaseLogEntry { * @since 1.19 */ class ManualLogEntry extends LogEntryBase { - protected $type; ///!< @var string - protected $subtype; ///!< @var string - protected $parameters = array(); ///!< @var array - protected $relations = array(); ///!< @var array - protected $performer; ///!< @var User - protected $target; ///!< @var Title - protected $timestamp; ///!< @var string - protected $comment = ''; ///!< @var string - protected $deleted; ///!< @var int + /** @var string Type of log entry */ + protected $type; + + /** @var string Sub type of log entry */ + protected $subtype; + + /** @var array Parameters for log entry */ + protected $parameters = array(); + + /** @var array */ + protected $relations = array(); + + /** @var User Performer of the action for the log entry */ + protected $performer; + + /** @var Title Target title for the log entry */ + protected $target; + + /** @var string Timestamp of creation of the log entry */ + protected $timestamp; + + /** @var string Comment for the log entry */ + protected $comment = ''; + + /** @var int Deletion state of the log entry */ + protected $deleted; + + /** @var int ID of the log entry */ + protected $id; /** * Constructor. @@ -378,7 +407,7 @@ class ManualLogEntry extends LogEntryBase { * Declare arbitrary tag/value relations to this log entry. * These can be used to filter log entries later on. * - * @param array Map of (tag => (list of values)) + * @param array $relations Map of (tag => (list of values|value)) * @since 1.22 */ public function setRelations( array $relations ) { @@ -434,7 +463,7 @@ class ManualLogEntry extends LogEntryBase { * * @since 1.19 * - * @param integer $deleted + * @param int $deleted */ public function setDeleted( $deleted ) { $this->deleted = $deleted; @@ -443,7 +472,8 @@ class ManualLogEntry extends LogEntryBase { /** * Inserts the entry into the logging table. * @param IDatabase $dbw - * @return int If of the log entry + * @return int ID of the log entry + * @throws MWException */ public function insert( IDatabase $dbw = null ) { global $wgContLang; @@ -474,6 +504,10 @@ class ManualLogEntry extends LogEntryBase { 'log_comment' => $comment, 'log_params' => serialize( (array)$this->getParameters() ), ); + if ( isset( $this->deleted ) ) { + $data['log_deleted'] = $this->deleted; + } + $dbw->insert( 'logging', $data, __METHOD__ ); $this->id = !is_null( $id ) ? $id : $dbw->insertId(); @@ -482,10 +516,15 @@ class ManualLogEntry extends LogEntryBase { if ( !strlen( $tag ) ) { throw new MWException( "Got empty log search tag." ); } + + if ( !is_array( $values ) ) { + $values = array( $values ); + } + foreach ( $values as $value ) { $rows[] = array( - 'ls_field' => $tag, - 'ls_value' => $value, + 'ls_field' => $tag, + 'ls_value' => $value, 'ls_log_id' => $this->id ); } @@ -494,20 +533,20 @@ class ManualLogEntry extends LogEntryBase { $dbw->insert( 'log_search', $rows, __METHOD__, 'IGNORE' ); } + // Update any bloom filter cache + $member = $this->getTarget()->getNamespace() . ':' . $this->getTarget()->getDBkey(); + BloomCache::get( 'main' )->insert( wfWikiId(), 'TitleHasLogs', $member ); + return $this->id; } /** - * Publishes the log entry. - * @param int $newId id of the log entry. - * @param string $to rcandudp (default), rc, udp + * Get a RecentChanges object for the log entry + * @param int $newId + * @return RecentChange + * @since 1.23 */ - public function publish( $newId, $to = 'rcandudp' ) { - $log = new LogPage( $this->getType() ); - if ( $log->isRestricted() ) { - return; - } - + public function getRecentChange( $newId = 0 ) { $formatter = LogFormatter::newFromEntry( $this ); $context = RequestContext::newExtraneousContext( $this->getTarget() ); $formatter->setContext( $context ); @@ -524,7 +563,8 @@ class ManualLogEntry extends LogEntryBase { $ip = $user->getName(); } } - $rc = RecentChange::newLogEntry( + + return RecentChange::newLogEntry( $this->getTimestamp(), $logpage, $user, @@ -538,6 +578,20 @@ class ManualLogEntry extends LogEntryBase { $newId, $formatter->getIRCActionComment() // Used for IRC feeds ); + } + + /** + * Publishes the log entry. + * @param int $newId Id of the log entry. + * @param string $to One of: rcandudp (default), rc, udp + */ + public function publish( $newId, $to = 'rcandudp' ) { + $log = new LogPage( $this->getType() ); + if ( $log->isRestricted() ) { + return; + } + + $rc = $this->getRecentChange( $newId ); if ( $to === 'rc' || $to === 'rcandudp' ) { $rc->save( 'pleasedontudp' ); @@ -578,6 +632,7 @@ class ManualLogEntry extends LogEntryBase { public function getTimestamp() { $ts = $this->timestamp !== null ? $this->timestamp : wfTimestampNow(); + return wfTimestamp( TS_MW, $ts ); } @@ -588,5 +643,4 @@ class ManualLogEntry extends LogEntryBase { public function getDeleted() { return (int)$this->deleted; } - } diff --git a/includes/logging/LogEventsList.php b/includes/logging/LogEventsList.php index c27b57af..4dc25ef3 100644 --- a/includes/logging/LogEventsList.php +++ b/includes/logging/LogEventsList.php @@ -3,7 +3,7 @@ * Contain classes to list log entries * * Copyright © 2004 Brion Vibber <brion@pobox.com>, 2008 Aaron Schulz - * http://www.mediawiki.org/ + * https://www.mediawiki.org/ * * 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 @@ -31,7 +31,7 @@ class LogEventsList extends ContextSource { public $flags; /** - * @var Array + * @var array */ protected $mDefaultQuery; @@ -40,10 +40,11 @@ class LogEventsList extends ContextSource { * The first two parameters used to be $skin and $out, but now only a context * is needed, that's why there's a second unused parameter. * - * @param $context IContextSource Context to use; formerly it was Skin object. - * @param $unused void Unused; used to be an OutputPage object. - * @param int $flags flags; can be a combinaison of self::NO_ACTION_LINK, - * self::NO_EXTRA_USER_LINKS or self::USE_REVDEL_CHECKBOXES. + * @param IContextSource|Skin $context Context to use; formerly it was + * a Skin object. Use of Skin is deprecated. + * @param null $unused Unused; used to be an OutputPage object. + * @param int $flags Can be a combination of self::NO_ACTION_LINK, + * self::NO_EXTRA_USER_LINKS or self::USE_REVDEL_CHECKBOXES. */ public function __construct( $context, $unused = null, $flags = 0 ) { if ( $context instanceof IContextSource ) { @@ -59,46 +60,29 @@ class LogEventsList extends ContextSource { /** * Deprecated alias for getTitle(); do not use. * - * @deprecated in 1.20; use getTitle() instead. - * @return Title object + * @deprecated since 1.20; use getTitle() instead. + * @return Title */ public function getDisplayTitle() { + wfDeprecated( __METHOD__, '1.20' ); return $this->getTitle(); } /** - * Set page title and show header for this log type - * @param $type Array - * @deprecated in 1.19 - */ - public function showHeader( $type ) { - wfDeprecated( __METHOD__, '1.19' ); - // If only one log type is used, then show a special message... - $headerType = count( $type ) == 1 ? $type[0] : ''; - $out = $this->getOutput(); - if ( LogPage::isLogType( $headerType ) ) { - $page = new LogPage( $headerType ); - $out->setPageTitle( $page->getName()->text() ); - $out->addHTML( $page->getDescription()->parseAsBlock() ); - } else { - $out->addHTML( $this->msg( 'alllogstext' )->parse() ); - } - } - - /** * Show options for the log list * - * @param string $types or Array - * @param $user String - * @param $page String - * @param $pattern String - * @param $year Integer: year - * @param $month Integer: month - * @param $filter: array - * @param $tagFilter: array? + * @param array|string $types + * @param string $user + * @param string $page + * @param string $pattern + * @param int $year Year + * @param int $month Month + * @param array $filter + * @param string $tagFilter Tag to select by default */ - public function showOptions( $types = array(), $user = '', $page = '', $pattern = '', $year = '', - $month = '', $filter = null, $tagFilter = '' ) { + public function showOptions( $types = array(), $user = '', $page = '', $pattern = '', $year = 0, + $month = 0, $filter = null, $tagFilter = '' + ) { global $wgScript, $wgMiserMode; $title = SpecialPage::getTitleFor( 'Log' ); @@ -122,7 +106,7 @@ class LogEventsList extends ContextSource { } // date menu - $html .= Xml::tags( 'p', null, Xml::dateMenu( $year, $month ) ); + $html .= Xml::tags( 'p', null, Xml::dateMenu( (int)$year, (int)$month ) ); // Tag filter if ( $tagSelector ) { @@ -147,8 +131,8 @@ class LogEventsList extends ContextSource { } /** - * @param $filter Array - * @return String: Formatted HTML + * @param array $filter + * @return string Formatted HTML */ private function getFilterLinks( $filter ) { // show/hide links @@ -176,6 +160,7 @@ class LogEventsList extends ContextSource { $links[$type] = $this->msg( "log-show-hide-{$type}" )->rawParams( $link )->escaped(); $hiddens .= Html::hidden( "hide_{$type}_log", $val ) . "\n"; } + // Build links return '<small>' . $this->getLanguage()->pipeList( $links ) . '</small>' . $hiddens; } @@ -191,17 +176,19 @@ class LogEventsList extends ContextSource { unset( $this->mDefaultQuery['month'] ); unset( $this->mDefaultQuery['year'] ); } + return $this->mDefaultQuery; } /** - * @param $queryTypes Array - * @return String: Formatted HTML + * @param array $queryTypes + * @return string Formatted HTML */ private function getTypeMenu( $queryTypes ) { $queryType = count( $queryTypes ) == 1 ? $queryTypes[0] : ''; $selector = $this->getTypeSelector(); $selector->setDefault( $queryType ); + return $selector->getHtml(); } @@ -238,27 +225,39 @@ class LogEventsList extends ContextSource { } /** - * @param $user String - * @return String: Formatted HTML + * @param string $user + * @return string Formatted HTML */ private function getUserInput( $user ) { - return '<span style="white-space: nowrap">' . - Xml::inputLabel( $this->msg( 'specialloguserlabel' )->text(), 'user', 'mw-log-user', 15, $user ) . - '</span>'; + $label = Xml::inputLabel( + $this->msg( 'specialloguserlabel' )->text(), + 'user', + 'mw-log-user', + 15, + $user + ); + + return '<span style="white-space: nowrap">' . $label . '</span>'; } /** - * @param $title String - * @return String: Formatted HTML + * @param string $title + * @return string Formatted HTML */ private function getTitleInput( $title ) { - return '<span style="white-space: nowrap">' . - Xml::inputLabel( $this->msg( 'speciallogtitlelabel' )->text(), 'page', 'mw-log-page', 20, $title ) . - '</span>'; + $label = Xml::inputLabel( + $this->msg( 'speciallogtitlelabel' )->text(), + 'page', + 'mw-log-page', + 20, + $title + ); + + return '<span style="white-space: nowrap">' . $label . '</span>'; } /** - * @param $pattern + * @param string $pattern * @return string Checkbox */ private function getTitlePattern( $pattern ) { @@ -268,7 +267,7 @@ class LogEventsList extends ContextSource { } /** - * @param $types + * @param array $types * @return string */ private function getExtraInputs( $types ) { @@ -281,6 +280,7 @@ class LogEventsList extends ContextSource { return Xml::inputLabel( $this->msg( 'revdelete-offender' )->text(), 'offender', 'mw-log-offender', 20, $offender ); } + return ''; } @@ -299,8 +299,8 @@ class LogEventsList extends ContextSource { } /** - * @param $row Row: a single row from the result set - * @return String: Formatted HTML list item + * @param stdClass $row A single row from the result set + * @return string Formatted HTML list item */ public function logLine( $row ) { $entry = DatabaseLogEntry::newFromRow( $row ); @@ -339,12 +339,15 @@ class LogEventsList extends ContextSource { } /** - * @param $row Row + * @param stdClass $row Row * @return string */ private function getShowHideLinks( $row ) { - if ( ( $this->flags == self::NO_ACTION_LINK ) // we don't want to see the links - || $row->log_type == 'suppress' ) { // no one can hide items from the suppress log + // We don't want to see the links and + // no one can hide items from the suppress log. + if ( ( $this->flags == self::NO_ACTION_LINK ) + || $row->log_type == 'suppress' + ) { return ''; } $del = ''; @@ -352,15 +355,26 @@ class LogEventsList extends ContextSource { // Don't show useless checkbox to people who cannot hide log entries if ( $user->isAllowed( 'deletedhistory' ) ) { $canHide = $user->isAllowed( 'deletelogentry' ); + $canViewSuppressedOnly = $user->isAllowed( 'viewsuppressed' ) && + !$user->isAllowed( 'suppressrevision' ); + $entryIsSuppressed = self::isDeleted( $row, LogPage::DELETED_RESTRICTED ); + $canViewThisSuppressedEntry = $canViewSuppressedOnly && $entryIsSuppressed; if ( $row->log_deleted || $canHide ) { - if ( $canHide && $this->flags & self::USE_REVDEL_CHECKBOXES ) { // Show checkboxes instead of links. - if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $user ) ) { // If event was hidden from sysops + // Show checkboxes instead of links. + if ( $canHide && $this->flags & self::USE_REVDEL_CHECKBOXES && !$canViewThisSuppressedEntry ) { + // If event was hidden from sysops + if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $user ) ) { $del = Xml::check( 'deleterevisions', false, array( 'disabled' => 'disabled' ) ); } else { - $del = Xml::check( 'showhiderevisions', false, array( 'name' => 'ids[' . $row->log_id . ']' ) ); + $del = Xml::check( + 'showhiderevisions', + false, + array( 'name' => 'ids[' . $row->log_id . ']' ) + ); } } else { - if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $user ) ) { // If event was hidden from sysops + // If event was hidden from sysops + if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $user ) ) { $del = Linker::revDeleteLinkDisabled( $canHide ); } else { $query = array( @@ -368,20 +382,25 @@ class LogEventsList extends ContextSource { 'type' => 'logging', 'ids' => $row->log_id, ); - $del = Linker::revDeleteLink( $query, self::isDeleted( $row, LogPage::DELETED_RESTRICTED ), $canHide ); + $del = Linker::revDeleteLink( + $query, + $entryIsSuppressed, + $canHide && !$canViewThisSuppressedEntry + ); } } } } + return $del; } /** - * @param $row Row - * @param $type Mixed: string/array - * @param $action Mixed: string/array - * @param $right string - * @return Boolean + * @param stdClass $row Row + * @param string|array $type + * @param string|array $action + * @param string $right + * @return bool */ public static function typeAction( $row, $type, $action, $right = '' ) { $match = is_array( $type ) ? @@ -394,6 +413,7 @@ class LogEventsList extends ContextSource { $match = $wgUser->isAllowed( $right ); } } + return $match; } @@ -401,10 +421,10 @@ class LogEventsList extends ContextSource { * Determine if the current user is allowed to view a particular * field of this log row, if it's marked as deleted. * - * @param $row Row - * @param $field Integer - * @param $user User object to check, or null to use $wgUser - * @return Boolean + * @param stdClass $row Row + * @param int $field + * @param User $user User to check, or null to use $wgUser + * @return bool */ public static function userCan( $row, $field, User $user = null ) { return self::userCanBitfield( $row->log_deleted, $field, $user ); @@ -414,33 +434,33 @@ class LogEventsList extends ContextSource { * Determine if the current user is allowed to view a particular * field of this log row, if it's marked as deleted. * - * @param $bitfield Integer (current field) - * @param $field Integer - * @param $user User object to check, or null to use $wgUser - * @return Boolean + * @param int $bitfield Current field + * @param int $field + * @param User $user User to check, or null to use $wgUser + * @return bool */ public static function userCanBitfield( $bitfield, $field, User $user = null ) { if ( $bitfield & $field ) { - if ( $bitfield & LogPage::DELETED_RESTRICTED ) { - $permission = 'suppressrevision'; - } else { - $permission = 'deletedhistory'; - } - wfDebug( "Checking for $permission due to $field match on $bitfield\n" ); if ( $user === null ) { global $wgUser; $user = $wgUser; } - return $user->isAllowed( $permission ); - } else { - return true; + if ( $bitfield & LogPage::DELETED_RESTRICTED ) { + $permissions = array( 'suppressrevision', 'viewsuppressed' ); + } else { + $permissions = array( 'deletedhistory' ); + } + $permissionlist = implode( ', ', $permissions ); + wfDebug( "Checking for $permissionlist due to $field match on $bitfield\n" ); + return call_user_func_array( array( $user, 'isAllowedAny' ), $permissions ); } + return true; } /** - * @param $row Row - * @param $field Integer: one of DELETED_* bitfield constants - * @return Boolean + * @param stdClass $row Row + * @param int $field One of DELETED_* bitfield constants + * @return bool */ public static function isDeleted( $row, $field ) { return ( $row->log_deleted & $field ) == $field; @@ -449,7 +469,7 @@ class LogEventsList extends ContextSource { /** * Show log extract. Either with text and a box (set $msgKey) or without (don't set $msgKey) * - * @param $out OutputPage|String-by-reference + * @param OutputPage|string $out By-reference * @param string|array $types Log types to show * @param string|Title $page The page title to show log entries for * @param string $user The user who made the log entries @@ -466,7 +486,8 @@ class LogEventsList extends ContextSource { * - wrap String Wrap the message in html (usually something like "<div ...>$1</div>"). * - flags Integer display flags (NO_ACTION_LINK,NO_EXTRA_USER_LINKS) * - useRequestParams boolean Set true to use Pager-related parameters in the WebRequest - * @return Integer Number of total log items (not limited by $lim) + * - useMaster boolean Use master DB + * @return int Number of total log items (not limited by $lim) */ public static function showLogExtract( &$out, $types = array(), $page = '', $user = '', $param = array() @@ -479,6 +500,7 @@ class LogEventsList extends ContextSource { 'wrap' => "$1", 'flags' => 0, 'useRequestParams' => false, + 'useMaster' => false, ); # The + operator appends elements of remaining keys from the right # handed array to the left handed, whereas duplicated keys are NOT overwritten. @@ -511,17 +533,31 @@ class LogEventsList extends ContextSource { $pager->mOffset = ""; $pager->mIsBackwards = false; } + + if ( $param['useMaster'] ) { + $pager->mDb = wfGetDB( DB_MASTER ); + } if ( isset( $param['offset'] ) ) { # Tell pager to ignore WebRequest offset $pager->setOffset( $param['offset'] ); } + if ( $lim > 0 ) { $pager->mLimit = $lim; } + $logBody = $pager->getBody(); $s = ''; + if ( $logBody ) { if ( $msgKey[0] ) { - $s = '<div class="mw-warning-with-logexcerpt">'; + $dir = $context->getLanguage()->getDir(); + $lang = $context->getLanguage()->getCode(); + + $s = Xml::openElement( 'div', array( + 'class' => "mw-warning-with-logexcerpt mw-content-$dir", + 'dir' => $dir, + 'lang' => $lang, + ) ); if ( count( $msgKey ) == 1 ) { $s .= $context->msg( $msgKey[0] )->parseAsBlock(); @@ -538,6 +574,7 @@ class LogEventsList extends ContextSource { $s = Html::rawElement( 'div', array( 'class' => 'mw-warning-logempty' ), $context->msg( 'logempty' )->parse() ); } + if ( $pager->getNumRows() > $pager->mLimit ) { # Show "Full log" link $urlParam = array(); if ( $page instanceof Title ) { @@ -545,16 +582,20 @@ class LogEventsList extends ContextSource { } elseif ( $page != '' ) { $urlParam['page'] = $page; } + if ( $user != '' ) { $urlParam['user'] = $user; } + if ( !is_array( $types ) ) { # Make it an array, if it isn't $types = array( $types ); } + # If there is exactly one log type, we can link to Special:Log?type=foo if ( count( $types ) == 1 ) { $urlParam['type'] = $types[0]; } + $s .= Linker::link( SpecialPage::getTitleFor( 'Log' ), $context->msg( 'log-fulllog' )->escaped(), @@ -562,6 +603,7 @@ class LogEventsList extends ContextSource { $urlParam ); } + if ( $logBody && $msgKey[0] ) { $s .= '</div>'; } @@ -586,10 +628,10 @@ class LogEventsList extends ContextSource { /** * SQL clause to skip forbidden log types for this user * - * @param $db DatabaseBase - * @param $audience string, public/user - * @param $user User object to check, or null to use $wgUser - * @return Mixed: string or false + * @param DatabaseBase $db + * @param string $audience Public/user + * @param User $user User to check, or null to use $wgUser + * @return string|bool String on success, false on failure. */ public static function getExcludeClause( $db, $audience = 'public', User $user = null ) { global $wgLogRestrictions; @@ -613,6 +655,7 @@ class LogEventsList extends ContextSource { } elseif ( $hiddenLogs ) { return 'log_type NOT IN (' . $db->makeList( $hiddenLogs ) . ')'; } + return false; } } diff --git a/includes/logging/LogFormatter.php b/includes/logging/LogFormatter.php index 8f60aee1..48a565f2 100644 --- a/includes/logging/LogFormatter.php +++ b/includes/logging/LogFormatter.php @@ -39,7 +39,7 @@ class LogFormatter { /** * Constructs a new formatter suitable for given entry. - * @param $entry LogEntry + * @param LogEntry $entry * @return LogFormatter */ public static function newFromEntry( LogEntry $entry ) { @@ -64,7 +64,7 @@ class LogFormatter { /** * Handy shortcut for constructing a formatter directly from * database row. - * @param $row + * @param object $row * @see DatabaseLogEntry::getSelectQueryData * @return LogFormatter */ @@ -74,13 +74,13 @@ class LogFormatter { // Nonstatic-> - /// @var LogEntry + /** @var LogEntryBase */ protected $entry; - /// Integer constant for handling log_deleted + /** @var int Constant for handling log_deleted */ protected $audience = self::FOR_PUBLIC; - /// Whether to output user tool links + /** @var bool Whether to output user tool links */ protected $linkFlood = false; /** @@ -88,10 +88,11 @@ class LogFormatter { * be included in page history or send to IRC feed. Links are replaced * with plaintext or with [[pagename]] kind of syntax, that is parsed * by page histories and IRC feeds. - * @var boolean + * @var string */ protected $plaintext = false; + /** @var string */ protected $irctext = false; protected function __construct( LogEntry $entry ) { @@ -101,7 +102,7 @@ class LogFormatter { /** * Replace the default context - * @param $context IContextSource + * @param IContextSource $context */ public function setContext( IContextSource $context ) { $this->context = $context; @@ -111,7 +112,7 @@ class LogFormatter { * Set the visibility restrictions for displaying content. * 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 + * @param int $audience Const self::FOR_THIS_USER or self::FOR_PUBLIC */ public function setAudience( $audience ) { $this->audience = ( $audience == self::FOR_THIS_USER ) @@ -121,7 +122,7 @@ class LogFormatter { /** * Check if a log item can be displayed - * @param $field integer LogPage::DELETED_* constant + * @param int $field LogPage::DELETED_* constant * @return bool */ protected function canView( $field ) { @@ -137,7 +138,7 @@ class LogFormatter { * If set to true, will produce user tool links after * the user name. This should be replaced with generic * CSS/JS solution. - * @param $value boolean + * @param bool $value */ public function setShowUserToolLinks( $value ) { $this->linkFlood = $value; @@ -148,12 +149,13 @@ class LogFormatter { * Usually you also want to set extraneous request context * to avoid formatting for any particular user. * @see getActionText() - * @return string text + * @return string Plain text */ public function getPlainActionText() { $this->plaintext = true; $text = $this->getActionText(); $this->plaintext = false; + return $text; } @@ -161,7 +163,7 @@ class LogFormatter { * Even uglier hack to maintain backwards compatibilty with IRC bots * (bug 34508). * @see getActionText() - * @return string text + * @return string Text */ public function getIRCActionComment() { $actionComment = $this->getIRCActionText(); @@ -182,7 +184,7 @@ class LogFormatter { * Even uglier hack to maintain backwards compatibilty with IRC bots * (bug 34508). * @see getActionText() - * @return string text + * @return string Text */ public function getIRCActionText() { $this->plaintext = true; @@ -224,15 +226,19 @@ class LogFormatter { $text = wfMessage( 'undeletedarticle' ) ->rawParams( $target )->inContentLanguage()->escaped(); break; + // @codingStandardsIgnoreStart Long line //case 'revision': // Revision deletion //case 'event': // Log deletion - // see https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/LogPage.php?&pathrev=97044&r1=97043&r2=97044 + // see https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/LogPage.php?&pathrev=97044&r1=97043&r2=97044 //default: + // @codingStandardsIgnoreEnd } break; case 'patrol': + // @codingStandardsIgnoreStart Long line // https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/PatrolLog.php?&pathrev=97495&r1=97494&r2=97495 + // @codingStandardsIgnoreEnd // Create a diff link to the patrolled revision if ( $entry->getSubtype() === 'patrol' ) { $diffLink = htmlspecialchars( @@ -247,18 +253,18 @@ class LogFormatter { 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; + 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; @@ -316,8 +322,7 @@ class LogFormatter { break; } break; - - // case 'suppress' --private log -- aaron (sign your messages so we know who to blame in a few years :-D) + // case 'suppress' --private log -- aaron (so we know who to blame in a few years :-D) // default: } if ( is_null( $text ) ) { @@ -326,6 +331,7 @@ class LogFormatter { $this->plaintext = false; $this->irctext = false; + return $text; } @@ -353,12 +359,13 @@ 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|string pre-escaped html + * and entries might return pre-escaped HTML string. + * @return Message|string Pre-escaped HTML */ protected function getActionMessage() { $message = $this->msg( $this->getMessageKey() ); $message->params( $this->getMessageParameters() ); + return $message; } @@ -367,7 +374,7 @@ class LogFormatter { * Default is logentry-TYPE-SUBTYPE for modern logs. Legacy log * types will use custom keys, and subclasses can also alter the * key depending on the entry itself. - * @return string message key + * @return string Message key */ protected function getMessageKey() { $type = $this->entry->getType(); @@ -421,6 +428,7 @@ class LogFormatter { } } } + return $params; } @@ -446,7 +454,9 @@ class LogFormatter { // Bad things happens if the numbers are not in correct order ksort( $params ); - return $this->parsedParameters = $params; + + $this->parsedParameters = $params; + return $this->parsedParameters; } /** @@ -472,8 +482,7 @@ class LogFormatter { * * number: Format value as number * @param string $value The parameter value that should * be formated - * @return string or Message::numParam or Message::rawParam - * Formated value + * @return string|array Formated value * @since 1.21 */ protected function formatParameterValue( $type, $value ) { @@ -524,10 +533,10 @@ class LogFormatter { /** * Helper to make a link to the page, taking the plaintext * value in consideration. - * @param $title Title the page - * @param array $parameters query parameters + * @param Title $title The page + * @param array $parameters Query parameters * @throws MWException - * @return String + * @return string */ protected function makePageLink( Title $title = null, $parameters = array() ) { if ( !$this->plaintext ) { @@ -538,6 +547,7 @@ class LogFormatter { } $link = '[[' . $title->getPrefixedText() . ']]'; } + return $link; } @@ -545,7 +555,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 + * @return string */ public function getPerformerElement() { if ( $this->canView( LogPage::DELETED_USER ) ) { @@ -562,7 +572,7 @@ class LogFormatter { } /** - * Gets the luser provided comment + * Gets the user provided comment * @return string HTML */ public function getComment() { @@ -582,8 +592,8 @@ class LogFormatter { /** * Helper method for displaying restricted element. - * @param $message string - * @return string HTML or wikitext + * @param string $message + * @return string HTML or wiki text */ protected function getRestrictedElement( $message ) { if ( $this->plaintext ) { @@ -592,26 +602,27 @@ class LogFormatter { $content = $this->msg( $message )->escaped(); $attribs = array( 'class' => 'history-deleted' ); + return Html::rawElement( 'span', $attribs, $content ); } /** * Helper method for styling restricted element. - * @param $content string - * @return string HTML or wikitext + * @param string $content + * @return string HTML or wiki text */ protected function styleRestricedElement( $content ) { if ( $this->plaintext ) { return $content; } $attribs = array( 'class' => 'history-deleted' ); + return Html::rawElement( 'span', $attribs, $content ); } /** * Shortcut for wfMessage which honors local context. - * @todo Would it be better to require replacing the global context instead? - * @param $key string + * @param string $key * @return Message */ protected function msg( $key ) { @@ -635,18 +646,19 @@ class LogFormatter { ); } } + return $element; } /** - * @return Array of titles that should be preloaded with LinkBatch. + * @return array Array of titles that should be preloaded with LinkBatch */ public function getPreloadTitles() { return array(); } /** - * @return Output of getMessageParameters() for testing + * @return array Output of getMessageParameters() for testing */ public function getMessageParametersForTesting() { // This function was added because getMessageParameters() is @@ -654,7 +666,6 @@ class LogFormatter { // problems with extensions return $this->getMessageParameters(); } - } /** @@ -667,7 +678,6 @@ 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(), @@ -727,7 +737,8 @@ class LegacyLogFormatter extends LogFormatter { } if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) { - return $this->revert = ''; + $this->revert = ''; + return $this->revert; } $title = $this->entry->getTarget(); @@ -735,7 +746,9 @@ class LegacyLogFormatter extends LogFormatter { $subtype = $this->entry->getSubtype(); // Show unblock/change block link - if ( ( $type == 'block' || $type == 'suppress' ) && ( $subtype == 'block' || $subtype == 'reblock' ) ) { + if ( ( $type == 'block' || $type == 'suppress' ) + && ( $subtype == 'block' || $subtype == 'reblock' ) + ) { if ( !$this->context->getUser()->isAllowed( 'block' ) ) { return ''; } @@ -750,10 +763,13 @@ class LegacyLogFormatter extends LogFormatter { $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' ) ) { + } elseif ( $type == 'protect' + && ( $subtype == 'protect' || $subtype == 'modify' || $subtype == 'unprotect' ) + ) { $links = array( Linker::link( $title, $this->msg( 'hist' )->escaped(), @@ -772,6 +788,7 @@ class LegacyLogFormatter extends LogFormatter { array( 'action' => 'protect' ) ); } + return $this->msg( 'parentheses' )->rawParams( $this->context->getLanguage()->pipeList( $links ) )->escaped(); // Show unmerge link @@ -788,9 +805,11 @@ class LegacyLogFormatter extends LogFormatter { array( 'target' => $params[3], 'dest' => $title->getPrefixedDBkey(), - 'mergepoint' => $params[4] + 'mergepoint' => $params[4], + 'submitted' => 1 // show the revisions immediately ) ); + return $this->msg( 'parentheses' )->rawParams( $revert )->escaped(); } @@ -813,4 +832,3 @@ class LegacyLogFormatter extends LogFormatter { return $this->revert; } } - diff --git a/includes/logging/LogPage.php b/includes/logging/LogPage.php index cc473c18..ce5b972f 100644 --- a/includes/logging/LogPage.php +++ b/includes/logging/LogPage.php @@ -3,7 +3,7 @@ * Contain log classes * * Copyright © 2002, 2004 Brion Vibber <brion@pobox.com> - * http://www.mediawiki.org/ + * https://www.mediawiki.org/ * * 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 @@ -34,32 +34,51 @@ class LogPage { const DELETED_COMMENT = 2; const DELETED_USER = 4; const DELETED_RESTRICTED = 8; + // Convenience fields const SUPPRESSED_USER = 12; const SUPPRESSED_ACTION = 9; - /* @access private */ - var $type, $action, $comment, $params; - /** - * @var User - */ - var $doer; + /** @var bool */ + public $updateRecentChanges; - /** - * @var Title + /** @var bool */ + public $sendToUDP; + + /** @var string Plaintext version of the message for IRC */ + private $ircActionText; + + /** @var string Plaintext version of the message */ + private $actionText; + + /** @var string One of '', 'block', 'protect', 'rights', 'delete', + * 'upload', 'move' */ - var $target; + private $type; + + /** @var string One of '', 'block', 'protect', 'rights', 'delete', + * 'upload', 'move', 'move_redir' */ + private $action; - /* @access public */ - var $updateRecentChanges, $sendToUDP; + /** @var string Comment associated with action */ + private $comment; + + /** @var string Blob made of a parameters array */ + private $params; + + /** @var User The user doing the action */ + private $doer; + + /** @var Title */ + private $target; /** * Constructor * - * @param string $type one of '', 'block', 'protect', 'rights', 'delete', - * 'upload', 'move' - * @param $rc Boolean: whether to update recent changes as well as the logging table - * @param string $udp pass 'UDP' to send to the UDP feed if NOT sent to RC + * @param string $type One of '', 'block', 'protect', 'rights', 'delete', + * 'upload', 'move' + * @param bool $rc Whether to update recent changes as well as the logging table + * @param string $udp Pass 'UDP' to send to the UDP feed if NOT sent to RC */ public function __construct( $type, $rc = true, $udp = 'skipUDP' ) { $this->type = $type; @@ -68,7 +87,7 @@ class LogPage { } /** - * @return int log_id of the inserted log entry + * @return int The log_id of the inserted log entry */ protected function saveContent() { global $wgLogRestrictions; @@ -76,6 +95,7 @@ class LogPage { $dbw = wfGetDB( DB_MASTER ); $log_id = $dbw->nextSequenceValue( 'logging_log_id_seq' ); + // @todo FIXME private/protected/public property? $this->timestamp = $now = wfTimestampNow(); $data = array( 'log_id' => $log_id, @@ -116,8 +136,9 @@ class LogPage { $this->type, $this->action, $this->target, $this->comment, $this->params, $newId, $this->getRcCommentIRC() ); - $rc->notifyRC2UDP(); + $rc->notifyRCFeeds(); } + return $newId; } @@ -163,6 +184,7 @@ class LogPage { /** * Get the comment from the last addEntry() call + * @return string */ public function getComment() { return $this->comment; @@ -171,18 +193,19 @@ class LogPage { /** * Get the list of valid log types * - * @return Array of strings + * @return array Array of strings */ public static function validTypes() { global $wgLogTypes; + return $wgLogTypes; } /** * Is $type a valid log type * - * @param string $type log type to check - * @return Boolean + * @param string $type Log type to check + * @return bool */ public static function isLogType( $type ) { return in_array( $type, LogPage::validTypes() ); @@ -191,13 +214,15 @@ class LogPage { /** * Get the name for the given log type * - * @param string $type logtype - * @return String: log name - * @deprecated in 1.19, warnings in 1.21. Use getName() + * @param string $type Log type + * @return string Log name + * @deprecated since 1.19, warnings in 1.21. Use getName() */ public static function logName( $type ) { global $wgLogNames; + wfDeprecated( __METHOD__, '1.21' ); + if ( isset( $wgLogNames[$type] ) ) { return str_replace( '_', ' ', wfMessage( $wgLogNames[$type] )->text() ); } else { @@ -210,12 +235,15 @@ class LogPage { * Get the log header for the given log type * * @todo handle missing log types - * @param string $type logtype - * @return String: headertext of this logtype - * @deprecated in 1.19, warnings in 1.21. Use getDescription() + * @param string $type Logtype + * @return string Header text of this logtype + * @deprecated since 1.19, warnings in 1.21. Use getDescription() */ public static function logHeader( $type ) { global $wgLogHeaders; + + wfDeprecated( __METHOD__, '1.21' ); + return wfMessage( $wgLogHeaders[$type] )->parse(); } @@ -223,18 +251,18 @@ class LogPage { * Generate text for a log entry. * Only LogFormatter should call this function. * - * @param string $type log type - * @param string $action log action - * @param $title Mixed: Title object or null - * @param $skin Mixed: Skin object or null. If null, we want to use the wiki - * content language, since that will go to the IRC feed. - * @param array $params parameters - * @param $filterWikilinks Boolean: whether to filter wiki links - * @return HTML string + * @param string $type Log type + * @param string $action Log action + * @param Title|null $title Title object or null + * @param Skin|null $skin Skin object or null. If null, we want to use the wiki + * content language, since that will go to the IRC feed. + * @param array $params Parameters + * @param bool $filterWikilinks Whether to filter wiki links + * @return string HTML */ public static function actionText( $type, $action, $title = null, $skin = null, - $params = array(), $filterWikilinks = false ) - { + $params = array(), $filterWikilinks = false + ) { global $wgLang, $wgContLang, $wgLogActions; if ( is_null( $skin ) ) { @@ -254,7 +282,8 @@ class LogPage { $titleLink = self::getTitleLink( $type, $langObjOrNull, $title, $params ); if ( count( $params ) == 0 ) { - $rv = wfMessage( $wgLogActions[$key] )->rawParams( $titleLink )->inLanguage( $langObj )->escaped(); + $rv = wfMessage( $wgLogActions[$key] )->rawParams( $titleLink ) + ->inLanguage( $langObj )->escaped(); } else { $details = ''; array_unshift( $params, $titleLink ); @@ -262,7 +291,12 @@ class LogPage { // User suppression if ( preg_match( '/^(block|suppress)\/(block|reblock)$/', $key ) ) { if ( $skin ) { - $params[1] = '<span class="blockExpiry" title="‎' . htmlspecialchars( $params[1] ) . '">' . + // Localize the duration, and add a tooltip + // in English to help visitors from other wikis. + // The lrm is needed to make sure that the number + // is shown on the correct side of the tooltip text. + $durationTooltip = '‎' . htmlspecialchars( $params[1] ); + $params[1] = "<span class='blockExpiry' title='$durationTooltip'>" . $wgLang->translateBlockExpiry( $params[1] ) . '</span>'; } else { $params[1] = $wgContLang->translateBlockExpiry( $params[1] ); @@ -281,11 +315,16 @@ class LogPage { // Cascading flag... if ( $params[2] ) { - $details .= ' [' . wfMessage( 'protect-summary-cascade' )->inLanguage( $langObj )->text() . ']'; + $text = wfMessage( 'protect-summary-cascade' ) + ->inLanguage( $langObj )->text(); + $details .= ' '; + $details .= wfMessage( 'brackets', $text )->inLanguage( $langObj )->text(); + } } - $rv = wfMessage( $wgLogActions[$key] )->rawParams( $params )->inLanguage( $langObj )->escaped() . $details; + $rv = wfMessage( $wgLogActions[$key] )->rawParams( $params ) + ->inLanguage( $langObj )->escaped() . $details; } } } else { @@ -319,12 +358,12 @@ class LogPage { } /** - * TODO document - * @param $type String - * @param $lang Language or null - * @param $title Title - * @param $params Array - * @return String + * @todo Document + * @param string $type + * @param Language|null $lang + * @param Title $title + * @param array $params + * @return string */ protected static function getTitleLink( $type, $lang, $title, &$params ) { if ( !$lang ) { @@ -402,13 +441,14 @@ class LogPage { /** * Add a log entry * - * @param string $action one of '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'move_redir' - * @param $target Title object - * @param string $comment description associated - * @param array $params parameters passed later to wfMessage function - * @param $doer User object: the user doing the action + * @param string $action One of '', 'block', 'protect', 'rights', 'delete', + * 'upload', 'move', 'move_redir' + * @param Title $target Title object + * @param string $comment Description associated + * @param array $params Parameters passed later to wfMessage function + * @param null|int|User $doer The user doing the action. null for $wgUser * - * @return int log_id of the inserted log entry + * @return int The log_id of the inserted log entry */ public function addEntry( $action, $target, $comment, $params = array(), $doer = null ) { global $wgContLang; @@ -459,10 +499,10 @@ class LogPage { /** * Add relations to log_search table * - * @param $field String - * @param $values Array - * @param $logid Integer - * @return Boolean + * @param string $field + * @param array $values + * @param int $logid + * @return bool */ public function addRelations( $field, $values, $logid ) { if ( !strlen( $field ) || empty( $values ) ) { @@ -488,8 +528,8 @@ class LogPage { /** * Create a blob from a parameter array * - * @param $params Array - * @return String + * @param array $params + * @return string */ public static function makeParamBlob( $params ) { return implode( "\n", $params ); @@ -498,8 +538,8 @@ class LogPage { /** * Extract a parameter array from a blob * - * @param $blob String - * @return Array + * @param string $blob + * @return array */ public static function extractParams( $blob ) { if ( $blob === '' ) { @@ -514,8 +554,8 @@ class LogPage { * into a more readable (and translated) form * * @param string $flags Flags to format - * @param $lang Language object to use - * @return String + * @param Language $lang + * @return string */ public static function formatBlockFlags( $flags, $lang ) { $flags = trim( $flags ); @@ -523,10 +563,12 @@ class LogPage { return ''; //nothing to do } $flags = explode( ',', $flags ); + $flagsCount = count( $flags ); - for ( $i = 0; $i < count( $flags ); $i++ ) { + for ( $i = 0; $i < $flagsCount; $i++ ) { $flags[$i] = self::formatBlockFlag( $flags[$i], $lang ); } + return wfMessage( 'parentheses' )->inLanguage( $lang ) ->rawParams( $lang->commaList( $flags ) )->escaped(); } @@ -535,8 +577,8 @@ class LogPage { * Translate a block log flag if possible * * @param int $flag Flag to translate - * @param $lang Language object to use - * @return String + * @param Language $lang Language object to use + * @return string */ public static function formatBlockFlag( $flag, $lang ) { static $messages = array(); @@ -593,6 +635,7 @@ class LogPage { } else { $key = 'log-description-' . $this->type; } + return wfMessage( $key ); } @@ -609,6 +652,7 @@ class LogPage { // '' always returns true with $user->isAllowed() $restriction = ''; } + return $restriction; } @@ -619,7 +663,7 @@ class LogPage { */ public function isRestricted() { $restriction = $this->getRestriction(); + return $restriction !== '' && $restriction !== '*'; } - } diff --git a/includes/logging/LogPager.php b/includes/logging/LogPager.php index 09ae3b8c..256934e4 100644 --- a/includes/logging/LogPager.php +++ b/includes/logging/LogPager.php @@ -3,7 +3,7 @@ * Contain classes to list log entries * * Copyright © 2004 Brion Vibber <brion@pobox.com>, 2008 Aaron Schulz - * http://www.mediawiki.org/ + * https://www.mediawiki.org/ * * 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 @@ -27,22 +27,36 @@ * @ingroup Pager */ class LogPager extends ReverseChronologicalPager { - private $types = array(), $performer = '', $title = '', $pattern = ''; + /** @var array Log types */ + private $types = array(); + + /** @var string Events limited to those by performer when set */ + private $performer = ''; + + /** @var string|Title Events limited to those about Title when set */ + private $title = ''; + + /** @var string */ + private $pattern = ''; + + /** @var string */ private $typeCGI = ''; + + /** @var LogEventsList */ public $mLogEventsList; /** * Constructor * * @param LogEventsList $list - * @param string $types or Array: log types to show - * @param string $performer the user who made the log entries - * @param string|Title $title the page title the log entries are for - * @param string $pattern do a prefix search rather than an exact title match - * @param array $conds extra conditions for the query - * @param int $year The year to start from - * @param int $month The month to start from - * @param string $tagFilter tag + * @param string|array $types Log types to show + * @param string $performer The user who made the log entries + * @param string|Title $title The page title the log entries are for + * @param string $pattern Do a prefix search rather than an exact title match + * @param array $conds Extra conditions for the query + * @param int|bool $year The year to start from. Default: false + * @param int|bool $month The month to start from. Default: false + * @param string $tagFilter Tag */ public function __construct( $list, $types = array(), $performer = '', $title = '', $pattern = '', $conds = array(), $year = false, $month = false, $tagFilter = '' ) { @@ -56,6 +70,8 @@ class LogPager extends ReverseChronologicalPager { $this->limitTitle( $title, $pattern ); $this->getDateCond( $year, $month ); $this->mTagFilter = $tagFilter; + + $this->mDb = wfGetDB( DB_SLAVE, 'logpager' ); } public function getDefaultQuery() { @@ -64,6 +80,7 @@ class LogPager extends ReverseChronologicalPager { $query['user'] = $this->performer; $query['month'] = $this->mMonth; $query['year'] = $this->mYear; + return $query; } @@ -84,6 +101,7 @@ class LogPager extends ReverseChronologicalPager { } } } + return $filters; } @@ -91,7 +109,7 @@ class LogPager extends ReverseChronologicalPager { * Set the log reader to return only entries of the given type. * Type restrictions enforced here * - * @param string $types or array: Log types ('upload', 'delete', etc); + * @param string|array $types Log types ('upload', 'delete', etc); * empty string means no restriction */ private function limitType( $types ) { @@ -136,43 +154,42 @@ class LogPager extends ReverseChronologicalPager { * Set the log reader to return only entries by the given user. * * @param string $name (In)valid user name - * @return bool + * @return void */ private function limitPerformer( $name ) { if ( $name == '' ) { - return false; + return; } $usertitle = Title::makeTitleSafe( NS_USER, $name ); if ( is_null( $usertitle ) ) { - return false; + return; } /* Fetch userid at first, if known, provides awesome query plan afterwards */ $userid = User::idFromName( $name ); if ( !$userid ) { - /* It should be nicer to abort query at all, - but for now it won't pass anywhere behind the optimizer */ - $this->mConds[] = "NULL"; + $this->mConds['log_user_text'] = IP::sanitizeIP( $name ); } else { $this->mConds['log_user'] = $userid; - // Paranoia: avoid brute force searches (bug 17342) - $user = $this->getUser(); - if ( !$user->isAllowed( 'deletedhistory' ) ) { - $this->mConds[] = $this->mDb->bitAnd( 'log_deleted', LogPage::DELETED_USER ) . ' = 0'; - } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { - $this->mConds[] = $this->mDb->bitAnd( 'log_deleted', LogPage::SUPPRESSED_USER ) . - ' != ' . LogPage::SUPPRESSED_USER; - } - $this->performer = $usertitle->getText(); } + // Paranoia: avoid brute force searches (bug 17342) + $user = $this->getUser(); + if ( !$user->isAllowed( 'deletedhistory' ) ) { + $this->mConds[] = $this->mDb->bitAnd( 'log_deleted', LogPage::DELETED_USER ) . ' = 0'; + } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { + $this->mConds[] = $this->mDb->bitAnd( 'log_deleted', LogPage::SUPPRESSED_USER ) . + ' != ' . LogPage::SUPPRESSED_USER; + } + + $this->performer = $usertitle->getText(); } /** * Set the log reader to return only entries affecting the given page. * (For the block and rights logs, this is a user page.) * - * @param string $page or Title object: Title name - * @param $pattern String - * @return bool + * @param string|Title $page Title name + * @param string $pattern + * @return void */ private function limitTitle( $page, $pattern ) { global $wgMiserMode; @@ -182,7 +199,7 @@ class LogPager extends ReverseChronologicalPager { } else { $title = Title::newFromText( $page ); if ( strlen( $page ) == 0 || !$title instanceof Title ) { - return false; + return; } } @@ -190,6 +207,18 @@ class LogPager extends ReverseChronologicalPager { $ns = $title->getNamespace(); $db = $this->mDb; + $doUserRightsLogLike = false; + if ( $this->types == array( 'rights' ) ) { + global $wgUserrightsInterwikiDelimiter; + $parts = explode( $wgUserrightsInterwikiDelimiter, $title->getDBKey() ); + if ( count( $parts ) == 2 ) { + list( $name, $database ) = array_map( 'trim', $parts ); + if ( strstr( $database, '*' ) ) { // Search for wildcard in database name + $doUserRightsLogLike = true; + } + } + } + # Using the (log_namespace, log_title, log_timestamp) index with a # range scan (LIKE) on the first two parts, instead of simple equality, # makes it unusable for sorting. Sorted retrieval using another index @@ -201,12 +230,19 @@ class LogPager extends ReverseChronologicalPager { # use the page_time index. That should have no more than a few hundred # log entries for even the busiest pages, so it can be safely scanned # in full to satisfy an impossible condition on user or similar. - if ( $pattern && !$wgMiserMode ) { - $this->mConds['log_namespace'] = $ns; - $this->mConds[] = 'log_title ' . $db->buildLike( $title->getDBkey(), $db->anyString() ); + $this->mConds['log_namespace'] = $ns; + if ( $doUserRightsLogLike ) { + $params = array( $name . $wgUserrightsInterwikiDelimiter ); + foreach ( explode( '*', $database ) as $databasepart ) { + $params[] = $databasepart; + $params[] = $db->anyString(); + } + array_pop( $params ); // Get rid of the last % we added. + $this->mConds[] = 'log_title' . $db->buildLike( $params ); + } elseif ( $pattern && !$wgMiserMode ) { + $this->mConds[] = 'log_title' . $db->buildLike( $title->getDBkey(), $db->anyString() ); $this->pattern = $pattern; } else { - $this->mConds['log_namespace'] = $ns; $this->mConds['log_title'] = $title->getDBkey(); } // Paranoia: avoid brute force searches (bug 17342) @@ -242,8 +278,8 @@ class LogPager extends ReverseChronologicalPager { $index['log_search'] = 'ls_field_val'; $index['logging'] = 'PRIMARY'; if ( !$this->hasEqualsClause( 'ls_field' ) - || !$this->hasEqualsClause( 'ls_value' ) ) - { + || !$this->hasEqualsClause( 'ls_value' ) + ) { # Since (ls_field,ls_value,ls_logid) is unique, if the condition is # to match a specific (ls_field,ls_value) tuple, then there will be # no duplicate log rows. Otherwise, we need to remove the duplicates. @@ -266,12 +302,13 @@ class LogPager extends ReverseChronologicalPager { # Add ChangeTags filter query ChangeTags::modifyDisplayQuery( $info['tables'], $info['fields'], $info['conds'], $info['join_conds'], $info['options'], $this->mTagFilter ); + return $info; } /** * Checks if $this->mConds has $field matched to a *single* value - * @param $field + * @param string $field * @return bool */ protected function hasEqualsClause( $field ) { @@ -303,6 +340,7 @@ class LogPager extends ReverseChronologicalPager { $this->mResult->seek( 0 ); } wfProfileOut( __METHOD__ ); + return ''; } diff --git a/includes/logging/MoveLogFormatter.php b/includes/logging/MoveLogFormatter.php index 0978f976..39130163 100644 --- a/includes/logging/MoveLogFormatter.php +++ b/includes/logging/MoveLogFormatter.php @@ -31,6 +31,7 @@ class MoveLogFormatter extends LogFormatter { public function getPreloadTitles() { $params = $this->extractParameters(); + return array( Title::newFromText( $params[3] ) ); } @@ -40,6 +41,7 @@ class MoveLogFormatter extends LogFormatter { if ( isset( $params[4] ) && $params[4] === '1' ) { $key .= '-noredirect'; } + return $key; } @@ -49,14 +51,15 @@ class MoveLogFormatter extends LogFormatter { $newname = $this->makePageLink( Title::newFromText( $params[3] ) ); $params[2] = Message::rawParam( $oldname ); $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' ) ) - { + || !$this->context->getUser()->isAllowed( 'move' ) + ) { return ''; } @@ -77,6 +80,7 @@ class MoveLogFormatter extends LogFormatter { 'wpMovetalk' => 0 ) ); + return $this->msg( 'parentheses' )->rawParams( $revert )->escaped(); } } diff --git a/includes/logging/NewUsersLogFormatter.php b/includes/logging/NewUsersLogFormatter.php index 602728b4..c870d519 100644 --- a/includes/logging/NewUsersLogFormatter.php +++ b/includes/logging/NewUsersLogFormatter.php @@ -41,6 +41,7 @@ class NewUsersLogFormatter extends LogFormatter { $params[2] = Message::rawParam( $this->makeUserLink( $target ) ); $params[3] = $target->getName(); } + return $params; } @@ -51,6 +52,7 @@ class NewUsersLogFormatter extends LogFormatter { # not needed and can contain incorrect links return ''; } + return parent::getComment(); } @@ -60,6 +62,7 @@ class NewUsersLogFormatter extends LogFormatter { //add the user talk to LinkBatch for the userLink return array( Title::makeTitle( NS_USER_TALK, $this->entry->getTarget()->getText() ) ); } + return array(); } } diff --git a/includes/logging/PageLangLogFormatter.php b/includes/logging/PageLangLogFormatter.php new file mode 100644 index 00000000..694fa7f3 --- /dev/null +++ b/includes/logging/PageLangLogFormatter.php @@ -0,0 +1,61 @@ +<?php +/** + * Formatter for changelang 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 Kunal Grover + * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later + * @since 1.24 + */ + +/** + * This class formats language change log entries. + * + * @since 1.24 + */ +class PageLangLogFormatter extends LogFormatter { + protected function getMessageParameters() { + // Get the user language for displaying language names + $userLang = $this->context->getLanguage()->getCode(); + $params = parent::getMessageParameters(); + + // Get the language codes from log + $oldLang = $params[3]; + $kOld = strrpos( $oldLang, '[' ); + if ( $kOld ) { + $oldLang = substr( $oldLang, 0, $kOld ); + } + + $newLang = $params[4]; + $kNew = strrpos( $newLang, '[' ); + if ( $kNew ) { + $newLang = substr( $newLang, 0, $kNew ); + } + + // Convert language codes to names in user language + $logOld = Language::fetchLanguageName( $oldLang, $userLang ) + . ' (' . $oldLang . ')'; + $logNew = Language::fetchLanguageName( $newLang, $userLang ) + . ' (' . $newLang . ')'; + + // Add the default message to languages if required + $params[3] = !$kOld ? $logOld : $logOld . ' [' . $this->msg( 'default' ) . ']'; + $params[4] = !$kNew ? $logNew : $logNew . ' [' . $this->msg( 'default' ) . ']'; + return $params; + } +} diff --git a/includes/logging/PatrolLog.php b/includes/logging/PatrolLog.php index bb76d5a9..4f2a565d 100644 --- a/includes/logging/PatrolLog.php +++ b/includes/logging/PatrolLog.php @@ -27,13 +27,12 @@ * logs of patrol events */ class PatrolLog { - /** * Record a log event for a change being patrolled * - * @param $rc Mixed: change identifier or RecentChange object - * @param $auto Boolean: was this patrol event automatic? - * @param $user User: user performing the action or null to use $wgUser + * @param int|RecentChange $rc Change identifier or RecentChange object + * @param bool $auto Was this patrol event automatic? + * @param User $user User performing the action or null to use $wgUser * * @return bool */ @@ -65,15 +64,16 @@ class PatrolLog { if ( !$auto ) { $entry->publish( $logid, 'udp' ); } + return true; } /** * Prepare log parameters for a patrolled change * - * @param $change RecentChange to represent - * @param $auto Boolean: whether the patrol event was automatic - * @return Array + * @param RecentChange $change RecentChange to represent + * @param bool $auto Whether the patrol event was automatic + * @return array */ private static function buildParams( $change, $auto ) { return array( @@ -82,5 +82,4 @@ class PatrolLog { '6::auto' => (int)$auto ); } - } diff --git a/includes/logging/PatrolLogFormatter.php b/includes/logging/PatrolLogFormatter.php index 507039ba..2abaf173 100644 --- a/includes/logging/PatrolLogFormatter.php +++ b/includes/logging/PatrolLogFormatter.php @@ -35,6 +35,7 @@ class PatrolLogFormatter extends LogFormatter { if ( isset( $params[5] ) && $params[5] ) { $key .= '-auto'; } + return $key; } @@ -58,6 +59,7 @@ class PatrolLogFormatter extends LogFormatter { } $params[3] = Message::rawParam( $revlink ); + return $params; } } diff --git a/includes/logging/RightsLogFormatter.php b/includes/logging/RightsLogFormatter.php index d3daf6ee..ac252aeb 100644 --- a/includes/logging/RightsLogFormatter.php +++ b/includes/logging/RightsLogFormatter.php @@ -55,6 +55,7 @@ class RightsLogFormatter extends LogFormatter { if ( !isset( $params[3] ) && !isset( $params[4] ) ) { $key .= '-legacy'; } + return $key; } |