* %h will be replaced by the short SHA-1 (7 first chars) and %H by the
* full SHA-1 of the HEAD revision.
* %r will be replaced with a URL-encoded version of $1.
+ * %R will be replaced with $1 and no URL-encoding
*
* @since 1.20
*/
$wgGitRepositoryViewers = [
'https://(?:[a-z0-9_]+@)?gerrit.wikimedia.org/r/(?:p/)?(.*)' =>
- 'https://git.wikimedia.org/tree/%r/%H',
+ 'https://phabricator.wikimedia.org/r/revision/%R;%H',
'ssh://(?:[a-z0-9_]+@)?gerrit.wikimedia.org:29418/(.*)' =>
- 'https://git.wikimedia.org/tree/%r/%H',
+ 'https://phabricator.wikimedia.org/r/revision/%R;%H',
];
/** @} */ # End of maintenance }
'move/move' => 'MoveLogFormatter',
'move/move_redir' => 'MoveLogFormatter',
'patrol/patrol' => 'PatrolLogFormatter',
+ 'patrol/autopatrol' => 'PatrolLogFormatter',
'protect/modify' => 'ProtectLogFormatter',
'protect/move_prot' => 'ProtectLogFormatter',
'protect/protect' => 'ProtectLogFormatter',
'upload/upload' => 'UploadLogFormatter',
];
+/**
+ * List of log types that can be filtered by action types
+ *
+ * To each action is associated the list of log_action
+ * subtypes to search for, usually one, but not necessarily so
+ * Extensions may append to this array
+ * @since 1.27
+ */
+$wgActionFilteredLogs = [
+ 'block' => [
+ 'block' => [ 'block' ],
+ 'reblock' => [ 'reblock' ],
+ 'unblock' => [ 'unblock' ],
+ ],
+ 'delete' => [
+ 'delete' => [ 'delete' ],
+ 'restore' => [ 'restore' ],
+ 'event' => [ 'event' ],
+ 'revision' => [ 'revision' ],
+ ],
+ 'patrol' => [
+ 'patrol' => [ 'patrol' ],
+ 'autopatrol' => [ 'autopatrol' ],
+ ],
+ 'protect' => [
+ 'protect' => [ 'protect' ],
+ 'modify' => [ 'modify' ],
+ 'unprotect' => [ 'unprotect' ],
+ ],
+ 'upload' => [
+ 'upload' => [ 'upload' ],
+ 'overwrite' => [ 'overwrite' ],
+ ],
+];
+
/**
* Maintain a log of newusers at Log/newusers?
*/
if ( $url === false ) {
return false;
}
- if ( substr( $url, -4 ) !== '.git' ) {
- $url .= '.git';
- }
foreach ( self::getViewers() as $repo => $viewer ) {
$pattern = '#^' . $repo . '$#';
if ( preg_match( $pattern, $url, $matches ) ) {
'%h' => substr( $headSHA1, 0, 7 ),
'%H' => $headSHA1,
'%r' => urlencode( $matches[1] ),
+ '%R' => $matches[1],
];
return strtr( $viewerUrl, $replacements );
}
return ( $row && $row->rd_namespace == NS_FILE )
? Title::makeTitle( $row->rd_namespace, $row->rd_title )->getDBkey()
: ''; // negative cache
- }
+ },
+ [ 'pcTTL' => 30 ]
);
// @note: also checks " " for b/c
$this->lastRelayError = self::ERR_NONE;
}
+ /**
+ * Clear the in-process caches; useful for testing
+ *
+ * @since 1.27
+ */
+ public function clearProcessCache() {
+ $this->procCache->clear();
+ }
+
/**
* Do the actual async bus purge of a key
*
*/
protected $showTagEditUI;
+ /**
+ * @var array
+ */
+ protected $allowedActions = null;
+
/**
* Constructor.
* The first two parameters used to be $skin and $out, but now only a context
* @param int $month Month
* @param array $filter
* @param string $tagFilter Tag to select by default
+ * @param string $action
*/
public function showOptions( $types = [], $user = '', $page = '', $pattern = '', $year = 0,
- $month = 0, $filter = null, $tagFilter = ''
+ $month = 0, $filter = null, $tagFilter = '', $action = null
) {
global $wgScript, $wgMiserMode;
$html .= Xml::tags( 'p', null, $this->getFilterLinks( $filter ) );
}
+ // Action filter
+ if ( $action !== null ) {
+ $html .= Xml::tags( 'p', null, $this->getActionSelector( $types, $action ) );
+ }
+
// Submit button
$html .= Xml::submitButton( $this->msg( 'logeventslist-submit' )->text() );
return '';
}
+ /**
+ * Drop down menu for selection of actions that can be used to filter the log
+ * @param array $types
+ * @param string $action
+ * @return string
+ * @since 1.27
+ */
+ private function getActionSelector( $types, $action ) {
+ if ( $this->allowedActions === null || !count( $this->allowedActions ) ) {
+ return '';
+ }
+ $html = '';
+ $html .= xml::label( wfMessage( 'log-action-filter-' . $types[0] )->text(),
+ 'action-filter-' .$types[0] ) . "\n";
+ $select = new XmlSelect( 'subtype' );
+ $select->addOption( wfMessage( 'log-action-filter-all' )->text(), '' );
+ foreach ( $this->allowedActions as $value ) {
+ $msgKey = 'log-action-filter-' . $types[0] . '-' . $value;
+ $select->addOption( wfMessage( $msgKey )->text(), $value );
+ }
+ $select->setDefault( $action );
+ $html .= $select->getHtml();
+ return $html;
+ }
+
+ /**
+ * Sets the action types allowed for log filtering
+ * To one action type may correspond several log_actions
+ * @param array $actions
+ * @since 1.27
+ */
+ public function setAllowedActions( $actions ) {
+ $this->allowedActions = $actions;
+ }
+
/**
* @return string
*/
$user = $wgUser;
}
- $entry = new ManualLogEntry( 'patrol', 'patrol' );
+ $action = $auto ? 'autopatrol' : 'patrol';
+
+ $entry = new ManualLogEntry( 'patrol', $action );
$entry->setTarget( $rc->getTitle() );
$entry->setParameters( self::buildParams( $rc, $auto ) );
$entry->setPerformer( $user );
*/
class PatrolLogFormatter extends LogFormatter {
protected function getMessageKey() {
- $key = parent::getMessageKey();
$params = $this->getMessageParameters();
if ( isset( $params[5] ) && $params[5] ) {
- // Messages: logentry-patrol-patrol-auto
- $key .= '-auto';
+ $key = 'logentry-patrol-patrol-auto';
+ } else {
+ $key = 'logentry-patrol-patrol';
}
return $key;
$opts->add( 'offset', '' );
$opts->add( 'dir', '' );
$opts->add( 'offender', '' );
+ $opts->add( 'subtype', '' );
// Set values
$opts->fetchValuesFromRequest( $this->getRequest() );
null,
LogEventsList::USE_CHECKBOXES
);
+
+ $action = '';
+ // Allow to filter the log by actions
+ $type = $opts->getValue( 'type' );
+ if ( $type !== '' ) {
+ $actions = $this->getConfig()->get( 'ActionFilteredLogs' );
+ if ( isset( $actions[$type] ) ) {
+ // log type can be filtered by actions
+ $loglist->setAllowedActions( array_keys( $actions[$type] ) );
+ $action = $opts->getValue( 'subtype' );
+ if ( $action !== '' && isset( $actions[$type][$action] ) ) {
+ // add condition to query
+ $extraConds['log_action'] = $actions[$type][$action];
+ } else {
+ // no action or invalid action
+ $action = '';
+ }
+ }
+ }
+
$pager = new LogPager(
$loglist,
$opts->getValue( 'type' ),
$pager->getYear(),
$pager->getMonth(),
$pager->getFilterParams(),
- $opts->getValue( 'tagfilter' )
+ $opts->getValue( 'tagfilter' ),
+ $action
);
# Insert list
"sessionprovider-generic": "$1 sessions",
"sessionprovider-mediawiki-session-cookiesessionprovider": "cookie-based sessions",
"sessionprovider-nocookies": "Cookies may be disabled. Ensure you have cookies enabled and start again.",
- "randomrootpage": "Random root page"
+ "randomrootpage": "Random root page",
+ "log-action-filter-block": "Type of block:",
+ "log-action-filter-delete": "Type of deletion:",
+ "log-action-filter-patrol": "Type of patrol:",
+ "log-action-filter-protect": "Type of protection:",
+ "log-action-filter-upload": "Type of upload:",
+ "log-action-filter-all": "All",
+ "log-action-filter-block-block": "Block",
+ "log-action-filter-block-reblock": "Block modification",
+ "log-action-filter-block-unblock": "Unblock",
+ "log-action-filter-delete-delete": "Page deletion",
+ "log-action-filter-delete-restore": "Page undeletion",
+ "log-action-filter-delete-event": "Log deletion",
+ "log-action-filter-delete-revision": "Revision deletion",
+ "log-action-filter-patrol-patrol": "Manual patrol",
+ "log-action-filter-patrol-autopatrol": "Automatic patrol",
+ "log-action-filter-protect-protect": "Protection",
+ "log-action-filter-protect-modify": "Protection modification",
+ "log-action-filter-protect-unprotect": "Unprotection",
+ "log-action-filter-upload-upload": "New upload",
+ "log-action-filter-upload-overwrite": "Reupload"
}
"sessionprovider-generic": "Used to create a generic session type description when one isn't provided via the proper message. Should be phrased to make sense when added to a message such as {{msg-mw|cannotloginnow-text}}.\n\nParameters:\n* $1 - PHP classname.",
"sessionprovider-mediawiki-session-cookiesessionprovider": "Description of the sessions provided by the CookieSessionProvider class, which use HTTP cookies. Should be phrased to make sense when added to a message such as {{msg-mw|cannotloginnow-text}}.",
"sessionprovider-nocookies": "Used to inform the user that sessions may be missing due to lack of cookies.",
- "randomrootpage": "{{doc-special|RandomRootPage}}"
+ "randomrootpage": "{{doc-special|RandomRootPage}}",
+ "log-action-filter-block": "Which type of action to filter for in this log",
+ "log-action-filter-delete": "Which type of action to filter for in this log",
+ "log-action-filter-patrol": "Which type of action to filter for in this log",
+ "log-action-filter-protect": "Which type of action to filter for in this log",
+ "log-action-filter-upload": "Which type of action to filter for in this log",
+ "log-action-filter-all": "All types of action are allowed",
+ "log-action-filter-block-block": "Action to filter for in this log",
+ "log-action-filter-block-reblock": "Action to filter for in this log",
+ "log-action-filter-block-unblock": "Action to filter for in this log",
+ "log-action-filter-delete-delete": "Action to filter for in this log",
+ "log-action-filter-delete-restore": "Action to filter for in this log",
+ "log-action-filter-delete-event": "Action to filter for in this log",
+ "log-action-filter-delete-revision": "Action to filter for in this log",
+ "log-action-filter-patrol-patrol": "Action to filter for in this log",
+ "log-action-filter-patrol-autopatrol": "Action to filter for in this log",
+ "log-action-filter-protect-protect": "Action to filter for in this log",
+ "log-action-filter-protect-modify": "Action to filter for in this log",
+ "log-action-filter-protect-unprotect": "Action to filter for in this log",
+ "log-action-filter-upload-upload": "Action to filter for in this log",
+ "log-action-filter-upload-overwrite": "Action to filter for in this log"
}
'sk' => 'resources/lib/moment/locale/sk.js',
'sl' => 'resources/lib/moment/locale/sl.js',
'sq' => 'resources/lib/moment/locale/sq.js',
- 'sr' => 'resources/lib/moment/locale/sr.js',
'sr-ec' => 'resources/lib/moment/locale/sr-cyrl.js',
+ 'sr-el' => 'resources/lib/moment/locale/sr.js',
'sv' => 'resources/lib/moment/locale/sv.js',
'ta' => 'resources/lib/moment/locale/ta.js',
'th' => 'resources/lib/moment/locale/th.js',
$titleText = 'Parser test';
}
+ ObjectCache::getMainWANInstance()->clearProcessCache();
$local = isset( $opts['local'] );
$preprocessor = isset( $opts['preprocessor'] ) ? $opts['preprocessor'] : null;
$parser = $this->getParser( $preprocessor );
}
DeferredUpdates::clearPendingUpdates();
+ ObjectCache::getMainWANInstance()->clearProcessCache();
ob_start( 'MediaWikiTestCase::wfResetOutputBuffersBarrier' );
}