44use Wikimedia\Timestamp\TimestampException;
73 parent::__construct(
'Log' );
74 $this->linkBatchFactory = $linkBatchFactory;
75 $this->dbProvider = $dbProvider;
76 $this->actorNormalization = $actorNormalization;
77 $this->userIdentityLookup = $userIdentityLookup;
78 $this->userNameUtils = $userNameUtils;
79 $this->logFormatterFactory = $logFormatterFactory;
86 $out->addModuleStyles(
'mediawiki.interface.helpers.styles' );
90 $opts->
add(
'type',
'' );
91 $opts->add(
'user',
'' );
92 $opts->add(
'page',
'' );
93 $opts->add(
'pattern',
false );
94 $opts->add(
'year',
null, FormOptions::INTNULL );
95 $opts->add(
'month',
null, FormOptions::INTNULL );
96 $opts->add(
'day',
null, FormOptions::INTNULL );
97 $opts->add(
'tagfilter',
'' );
98 $opts->add(
'tagInvert',
false );
99 $opts->add(
'offset',
'' );
100 $opts->add(
'dir',
'' );
101 $opts->add(
'offender',
'' );
102 $opts->add(
'subtype',
'' );
103 $opts->add(
'logid',
'' );
106 if ( $par !==
null ) {
107 $this->parseParams( (
string)$par );
109 $opts->fetchValuesFromRequest( $this->
getRequest() );
112 $dateString = $this->
getRequest()->getVal(
'wpdate' );
115 $dateStamp = MWTimestamp::getInstance( $dateString .
' 00:00:00' );
116 }
catch ( TimestampException $e ) {
122 $opts->setValue(
'year', (
int)$dateStamp->format(
'Y' ) );
123 $opts->setValue(
'month', (
int)$dateStamp->format(
'm' ) );
124 $opts->setValue(
'day', (
int)$dateStamp->format(
'd' ) );
131 $type = $opts->getValue(
'type' );
132 if ( isset( $logRestrictions[$type] )
133 && !$this->
getAuthority()->isAllowed( $logRestrictions[$type] )
138 # TODO: Move this into LogPager like other query conditions.
139 # Handle type-specific inputs
141 $offenderName = $opts->getValue(
'offender' );
142 if ( $opts->getValue(
'type' ) ==
'suppress' && $offenderName !==
'' ) {
143 $dbr = $this->dbProvider->getReplicaDatabase();
144 $offenderId = $this->actorNormalization->findActorIdByName( $offenderName, $dbr );
146 $qc = [
'ls_field' =>
'target_author_actor',
'ls_value' => strval( $offenderId ) ];
154 $opts->getValue(
'type' ), $this->getRequest(), $qc );
157 # TODO: Move this into LogEventList and use it as filter-callback in the field descriptor.
158 # Some log types are only for a 'User:' title but we might have been given
159 # only the username instead of the full title 'User:username'. This part try
160 # to lookup for a user by that name and eventually fix user input. See T3697.
161 if ( in_array( $opts->getValue(
'type' ), self::getLogTypesOnUser( $this->getHookRunner() ) ) ) {
162 # ok we have a type of log which expect a user title.
163 $page = $opts->getValue(
'page' );
164 $target = Title::newFromText( $page );
165 if ( $target && $target->getNamespace() ===
NS_MAIN ) {
166 if ( IPUtils::isValidRange( $target->getText() ) ) {
167 $page = IPUtils::sanitizeRange( $target->getText() );
169 # User forgot to add 'User:', we are adding it for them
170 $target = Title::makeTitleSafe(
NS_USER, $page );
171 } elseif ( $target && $target->getNamespace() ===
NS_USER
172 && IPUtils::isValidRange( $target->getText() )
174 $ipOrRange = IPUtils::sanitizeRange( $target->getText() );
175 if ( $ipOrRange !== $target->getText() ) {
176 $target = Title::makeTitleSafe(
NS_USER, $ipOrRange );
179 if ( $target !==
null ) {
180 $page = $target->getPrefixedText();
181 $opts->setValue(
'page', $page );
186 $this->show( $opts, $qc );
201 static $types =
null;
202 if ( $types !==
null ) {
213 ->onGetLogTypesOnUser( $types );
223 $subpages = LogPage::validTypes();
237 private function parseParams(
string $par ) {
239 $parms = explode(
'/', $par, 2 );
240 $symsForAll = [
'*',
'all' ];
241 if ( $parms[0] !==
'' &&
242 ( in_array( $parms[0], LogPage::validTypes() ) || in_array( $parms[0], $symsForAll ) )
244 $this->
getRequest()->setVal(
'type', $parms[0] );
245 if ( count( $parms ) === 2 ) {
246 $this->
getRequest()->setVal(
'user', $parms[1] );
248 } elseif ( $par !==
'' ) {
253 private function show( FormOptions $opts, array $extraConds ) {
254 # Create a LogPager item to get the results and a LogEventsList item to format them...
255 $loglist =
new LogEventsList(
258 LogEventsList::USE_CHECKBOXES
260 $pager =
new LogPager(
262 $opts->getValue(
'type' ),
263 $opts->getValue(
'user' ),
264 $opts->getValue(
'page' ),
265 $opts->getValue(
'pattern' ),
267 $opts->getValue(
'year' ),
268 $opts->getValue(
'month' ),
269 $opts->getValue(
'day' ),
270 $opts->getValue(
'tagfilter' ),
271 $opts->getValue(
'subtype' ),
272 $opts->getValue(
'logid' ),
273 $this->linkBatchFactory,
274 $this->actorNormalization,
275 $this->logFormatterFactory,
276 $opts->getValue(
'tagInvert' )
280 $performer = $pager->getPerformer();
282 $performerUser = $this->userIdentityLookup->getUserIdentityByName( $performer );
285 if ( $performerUser && !IPUtils::isValidRange( $performer ) &&
286 ( $this->userNameUtils->isIP( $performer ) || $performerUser->isRegistered() )
288 $this->
getSkin()->setRelevantUser( $performerUser );
293 $succeed = $loglist->showOptions(
294 $opts->getValue(
'type' ),
295 $opts->getValue(
'year' ),
296 $opts->getValue(
'month' ),
297 $opts->getValue(
'day' )
304 (
new LogPage( $opts->getValue(
'type' ) ) )->getName()
308 $logBody = $pager->getBody();
311 $pager->getNavigationBar() .
312 $this->getActionButtons(
313 $loglist->beginLogEventsList() .
315 $loglist->endLogEventsList()
317 $pager->getNavigationBar()
320 $this->
getOutput()->addWikiMsg(
'logempty' );
324 private function getActionButtons(
string $formcontents ): string {
326 ->isAllowedAll(
'deletedhistory',
'deletelogentry' );
327 $showTagEditUI = ChangeTags::showTagEditingUI( $this->
getAuthority() );
328 # If the user doesn't have the ability to delete log entries nor edit tags,
329 # don't bother showing them the button(s).
330 if ( !$canRevDelete && !$showTagEditUI ) {
331 return $formcontents;
334 # Show button to hide log entries and/or edit change tags
335 $s = Html::openElement(
337 [
'action' =>
wfScript(),
'id' =>
'mw-log-deleterevision-submit' ]
339 $s .= Html::hidden(
'type',
'logging' ) .
"\n";
342 if ( $canRevDelete ) {
349 'class' =>
"deleterevision-log-submit mw-log-deleterevision-button mw-ui-button"
351 $this->
msg(
'showhideselectedlogentries' )->text()
354 if ( $showTagEditUI ) {
361 'class' =>
"editchangetags-log-submit mw-log-editchangetags-button mw-ui-button"
363 $this->
msg(
'log-edit-tags' )->text()
367 $buttons .= (
new ListToggle( $this->
getOutput() ) )->getHTML();
369 $s .= $buttons . $formcontents . $buttons;
370 $s .= Html::closeElement(
'form' );
381class_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.