44use Wikimedia\Timestamp\TimestampException;
81 parent::__construct(
'Log' );
82 $this->linkBatchFactory = $linkBatchFactory;
83 $this->dbProvider = $dbProvider;
84 $this->actorNormalization = $actorNormalization;
85 $this->userIdentityLookup = $userIdentityLookup;
86 $this->userNameUtils = $userNameUtils;
87 $this->logFormatterFactory = $logFormatterFactory;
94 $out->addModules(
'mediawiki.userSuggest' );
95 $out->addModuleStyles(
'mediawiki.interface.helpers.styles' );
99 $opts->
add(
'type',
'' );
100 $opts->add(
'user',
'' );
101 $opts->add(
'page',
'' );
102 $opts->add(
'pattern',
false );
103 $opts->add(
'year',
null, FormOptions::INTNULL );
104 $opts->add(
'month',
null, FormOptions::INTNULL );
105 $opts->add(
'day',
null, FormOptions::INTNULL );
106 $opts->add(
'tagfilter',
'' );
107 $opts->add(
'tagInvert',
false );
108 $opts->add(
'offset',
'' );
109 $opts->add(
'dir',
'' );
110 $opts->add(
'offender',
'' );
111 $opts->add(
'subtype',
'' );
112 $opts->add(
'logid',
'' );
115 if ( $par !==
null ) {
116 $this->parseParams( (
string)$par );
118 $opts->fetchValuesFromRequest( $this->
getRequest() );
121 $dateString = $this->
getRequest()->getVal(
'wpdate' );
124 $dateStamp = MWTimestamp::getInstance( $dateString .
' 00:00:00' );
125 }
catch ( TimestampException $e ) {
131 $opts->setValue(
'year', (
int)$dateStamp->format(
'Y' ) );
132 $opts->setValue(
'month', (
int)$dateStamp->format(
'm' ) );
133 $opts->setValue(
'day', (
int)$dateStamp->format(
'd' ) );
140 $type = $opts->getValue(
'type' );
141 if ( isset( $logRestrictions[$type] )
142 && !$this->
getAuthority()->isAllowed( $logRestrictions[$type] )
147 # TODO: Move this into LogPager like other query conditions.
148 # Handle type-specific inputs
150 $offenderName = $opts->getValue(
'offender' );
151 if ( $opts->getValue(
'type' ) ==
'suppress' && $offenderName !==
'' ) {
152 $dbr = $this->dbProvider->getReplicaDatabase();
153 $offenderId = $this->actorNormalization->findActorIdByName( $offenderName, $dbr );
155 $qc = [
'ls_field' =>
'target_author_actor',
'ls_value' => strval( $offenderId ) ];
163 $opts->getValue(
'type' ), $this->getRequest(), $qc );
166 # TODO: Move this into LogEventList and use it as filter-callback in the field descriptor.
167 # Some log types are only for a 'User:' title but we might have been given
168 # only the username instead of the full title 'User:username'. This part try
169 # to lookup for a user by that name and eventually fix user input. See T3697.
170 if ( in_array( $opts->getValue(
'type' ), self::getLogTypesOnUser( $this->getHookRunner() ) ) ) {
171 # ok we have a type of log which expect a user title.
172 $page = $opts->getValue(
'page' );
173 $target = Title::newFromText( $page );
174 if ( $target && $target->getNamespace() ===
NS_MAIN ) {
175 if ( IPUtils::isValidRange( $target->getText() ) ) {
176 $page = IPUtils::sanitizeRange( $target->getText() );
178 # User forgot to add 'User:', we are adding it for him
179 $target = Title::makeTitleSafe(
NS_USER, $page );
180 } elseif ( $target && $target->getNamespace() ===
NS_USER
181 && IPUtils::isValidRange( $target->getText() )
183 $ipOrRange = IPUtils::sanitizeRange( $target->getText() );
184 if ( $ipOrRange !== $target->getText() ) {
185 $target = Title::makeTitleSafe(
NS_USER, $ipOrRange );
188 if ( $target !==
null ) {
189 $page = $target->getPrefixedText();
190 $opts->setValue(
'page', $page );
195 $this->show( $opts, $qc );
210 static $types =
null;
211 if ( $types !==
null ) {
222 ->onGetLogTypesOnUser( $types );
232 $subpages = LogPage::validTypes();
246 private function parseParams(
string $par ) {
248 $parms = explode(
'/', $par, 2 );
249 $symsForAll = [
'*',
'all' ];
250 if ( $parms[0] !==
'' &&
251 ( in_array( $parms[0], LogPage::validTypes() ) || in_array( $parms[0], $symsForAll ) )
253 $this->
getRequest()->setVal(
'type', $parms[0] );
254 if ( count( $parms ) === 2 ) {
255 $this->
getRequest()->setVal(
'user', $parms[1] );
257 } elseif ( $par !==
'' ) {
262 private function show( FormOptions $opts, array $extraConds ) {
263 # Create a LogPager item to get the results and a LogEventsList item to format them...
267 LogEventsList::USE_CHECKBOXES
269 $pager =
new LogPager(
271 $opts->getValue(
'type' ),
272 $opts->getValue(
'user' ),
273 $opts->getValue(
'page' ),
274 $opts->getValue(
'pattern' ),
276 $opts->getValue(
'year' ),
277 $opts->getValue(
'month' ),
278 $opts->getValue(
'day' ),
279 $opts->getValue(
'tagfilter' ),
280 $opts->getValue(
'subtype' ),
281 $opts->getValue(
'logid' ),
282 $this->linkBatchFactory,
283 $this->actorNormalization,
284 $this->logFormatterFactory,
285 $opts->getValue(
'tagInvert' )
289 $performer = $pager->getPerformer();
291 $performerUser = $this->userIdentityLookup->getUserIdentityByName( $performer );
294 if ( $performerUser && !IPUtils::isValidRange( $performer ) &&
295 ( $this->userNameUtils->isIP( $performer ) || $performerUser->isRegistered() )
297 $this->
getSkin()->setRelevantUser( $performerUser );
302 $succeed = $loglist->showOptions(
303 $opts->getValue(
'type' ),
304 $opts->getValue(
'year' ),
305 $opts->getValue(
'month' ),
306 $opts->getValue(
'day' )
313 (
new LogPage( $opts->getValue(
'type' ) ) )->getName()
317 $logBody = $pager->getBody();
320 $pager->getNavigationBar() .
321 $this->getActionButtons(
322 $loglist->beginLogEventsList() .
324 $loglist->endLogEventsList()
326 $pager->getNavigationBar()
329 $this->
getOutput()->addWikiMsg(
'logempty' );
333 private function getActionButtons( $formcontents ) {
335 ->isAllowedAll(
'deletedhistory',
'deletelogentry' );
337 # If the user doesn't have the ability to delete log entries nor edit tags,
338 # don't bother showing them the button(s).
339 if ( !$canRevDelete && !$showTagEditUI ) {
340 return $formcontents;
343 # Show button to hide log entries and/or edit change tags
344 $s = Html::openElement(
346 [
'action' =>
wfScript(),
'id' =>
'mw-log-deleterevision-submit' ]
348 $s .= Html::hidden(
'type',
'logging' ) .
"\n";
351 if ( $canRevDelete ) {
358 'class' =>
"deleterevision-log-submit mw-log-deleterevision-button mw-ui-button"
360 $this->
msg(
'showhideselectedlogentries' )->text()
363 if ( $showTagEditUI ) {
370 'class' =>
"editchangetags-log-submit mw-log-editchangetags-button mw-ui-button"
372 $this->
msg(
'log-edit-tags' )->text()
376 $buttons .= (
new ListToggle( $this->
getOutput() ) )->getHTML();
378 $s .= $buttons . $formcontents . $buttons;
379 $s .= Html::closeElement(
'form' );
390class_alias( SpecialLog::class,
'SpecialLog' );
wfScript( $script='index')
Get the URL path to a MediaWiki entry point.
Class to simplify the use of log pages.
A class containing constants representing the names of configuration variables.
const LogRestrictions
Name constant for the LogRestrictions setting, for use with Config::get()
Parent class for all special pages.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getSkin()
Shortcut to get the skin being used for this instance.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
getRequest()
Get the WebRequest being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getAuthority()
Shortcut to get the Authority executing this instance.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages By default the message key is the canonical name of...
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Show an error when a user tries to do something they do not have the necessary permissions for.