]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - includes/specials/SpecialLog.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / includes / specials / SpecialLog.php
1 <?php
2 /**
3  * Implements Special:Log
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  * http://www.gnu.org/copyleft/gpl.html
19  *
20  * @file
21  * @ingroup SpecialPage
22  */
23
24 /**
25  * A special page that lists log entries
26  *
27  * @ingroup SpecialPage
28  */
29 class SpecialLog extends SpecialPage {
30         public function __construct() {
31                 parent::__construct( 'Log' );
32         }
33
34         public function execute( $par ) {
35                 $this->setHeaders();
36                 $this->outputHeader();
37                 $this->getOutput()->addModules( 'mediawiki.userSuggest' );
38                 $this->addHelpLink( 'Help:Log' );
39
40                 $opts = new FormOptions;
41                 $opts->add( 'type', '' );
42                 $opts->add( 'user', '' );
43                 $opts->add( 'page', '' );
44                 $opts->add( 'pattern', false );
45                 $opts->add( 'year', null, FormOptions::INTNULL );
46                 $opts->add( 'month', null, FormOptions::INTNULL );
47                 $opts->add( 'tagfilter', '' );
48                 $opts->add( 'offset', '' );
49                 $opts->add( 'dir', '' );
50                 $opts->add( 'offender', '' );
51                 $opts->add( 'subtype', '' );
52                 $opts->add( 'logid', '' );
53
54                 // Set values
55                 $opts->fetchValuesFromRequest( $this->getRequest() );
56                 if ( $par !== null ) {
57                         $this->parseParams( $opts, (string)$par );
58                 }
59
60                 # Don't let the user get stuck with a certain date
61                 if ( $opts->getValue( 'offset' ) || $opts->getValue( 'dir' ) == 'prev' ) {
62                         $opts->setValue( 'year', '' );
63                         $opts->setValue( 'month', '' );
64                 }
65
66                 // If the user doesn't have the right permission to view the specific
67                 // log type, throw a PermissionsError
68                 // If the log type is invalid, just show all public logs
69                 $logRestrictions = $this->getConfig()->get( 'LogRestrictions' );
70                 $type = $opts->getValue( 'type' );
71                 if ( !LogPage::isLogType( $type ) ) {
72                         $opts->setValue( 'type', '' );
73                 } elseif ( isset( $logRestrictions[$type] )
74                         && !$this->getUser()->isAllowed( $logRestrictions[$type] )
75                 ) {
76                         throw new PermissionsError( $logRestrictions[$type] );
77                 }
78
79                 # Handle type-specific inputs
80                 $qc = [];
81                 if ( $opts->getValue( 'type' ) == 'suppress' ) {
82                         $offender = User::newFromName( $opts->getValue( 'offender' ), false );
83                         if ( $offender && $offender->getId() > 0 ) {
84                                 $qc = [ 'ls_field' => 'target_author_id', 'ls_value' => $offender->getId() ];
85                         } elseif ( $offender && IP::isIPAddress( $offender->getName() ) ) {
86                                 $qc = [ 'ls_field' => 'target_author_ip', 'ls_value' => $offender->getName() ];
87                         }
88                 } else {
89                         // Allow extensions to add relations to their search types
90                         Hooks::run(
91                                 'SpecialLogAddLogSearchRelations',
92                                 [ $opts->getValue( 'type' ), $this->getRequest(), &$qc ]
93                         );
94                 }
95
96                 # Some log types are only for a 'User:' title but we might have been given
97                 # only the username instead of the full title 'User:username'. This part try
98                 # to lookup for a user by that name and eventually fix user input. See T3697.
99                 if ( in_array( $opts->getValue( 'type' ), self::getLogTypesOnUser() ) ) {
100                         # ok we have a type of log which expect a user title.
101                         $target = Title::newFromText( $opts->getValue( 'page' ) );
102                         if ( $target && $target->getNamespace() === NS_MAIN ) {
103                                 # User forgot to add 'User:', we are adding it for him
104                                 $opts->setValue( 'page',
105                                         Title::makeTitleSafe( NS_USER, $opts->getValue( 'page' ) )
106                                 );
107                         }
108                 }
109
110                 $this->show( $opts, $qc );
111         }
112
113         /**
114          * List log type for which the target is a user
115          * Thus if the given target is in NS_MAIN we can alter it to be an NS_USER
116          * Title user instead.
117          *
118          * @since 1.25
119          * @return array
120          */
121         public static function getLogTypesOnUser() {
122                 static $types = null;
123                 if ( $types !== null ) {
124                         return $types;
125                 }
126                 $types = [
127                         'block',
128                         'newusers',
129                         'rights',
130                 ];
131
132                 Hooks::run( 'GetLogTypesOnUser', [ &$types ] );
133                 return $types;
134         }
135
136         /**
137          * Return an array of subpages that this special page will accept.
138          *
139          * @return string[] subpages
140          */
141         public function getSubpagesForPrefixSearch() {
142                 $subpages = $this->getConfig()->get( 'LogTypes' );
143                 $subpages[] = 'all';
144                 sort( $subpages );
145                 return $subpages;
146         }
147
148         /**
149          * Set options based on the subpage title parts:
150          * - One part that is a valid log type: Special:Log/logtype
151          * - Two parts: Special:Log/logtype/username
152          * - Otherwise, assume the whole subpage is a username.
153          *
154          * @param FormOptions $opts
155          * @param $par
156          * @throws ConfigException
157          */
158         private function parseParams( FormOptions $opts, $par ) {
159                 # Get parameters
160                 $par = $par !== null ? $par : '';
161                 $parms = explode( '/', $par );
162                 $symsForAll = [ '*', 'all' ];
163                 if ( $parms[0] != '' &&
164                         ( in_array( $par, $this->getConfig()->get( 'LogTypes' ) ) || in_array( $par, $symsForAll ) )
165                 ) {
166                         $opts->setValue( 'type', $par );
167                 } elseif ( count( $parms ) == 2 ) {
168                         $opts->setValue( 'type', $parms[0] );
169                         $opts->setValue( 'user', $parms[1] );
170                 } elseif ( $par != '' ) {
171                         $opts->setValue( 'user', $par );
172                 }
173         }
174
175         private function show( FormOptions $opts, array $extraConds ) {
176                 # Create a LogPager item to get the results and a LogEventsList item to format them...
177                 $loglist = new LogEventsList(
178                         $this->getContext(),
179                         $this->getLinkRenderer(),
180                         LogEventsList::USE_CHECKBOXES
181                 );
182
183                 $pager = new LogPager(
184                         $loglist,
185                         $opts->getValue( 'type' ),
186                         $opts->getValue( 'user' ),
187                         $opts->getValue( 'page' ),
188                         $opts->getValue( 'pattern' ),
189                         $extraConds,
190                         $opts->getValue( 'year' ),
191                         $opts->getValue( 'month' ),
192                         $opts->getValue( 'tagfilter' ),
193                         $opts->getValue( 'subtype' ),
194                         $opts->getValue( 'logid' )
195                 );
196
197                 $this->addHeader( $opts->getValue( 'type' ) );
198
199                 # Set relevant user
200                 if ( $pager->getPerformer() ) {
201                         $performerUser = User::newFromName( $pager->getPerformer(), false );
202                         $this->getSkin()->setRelevantUser( $performerUser );
203                 }
204
205                 # Show form options
206                 $loglist->showOptions(
207                         $pager->getType(),
208                         $pager->getPerformer(),
209                         $pager->getPage(),
210                         $pager->getPattern(),
211                         $pager->getYear(),
212                         $pager->getMonth(),
213                         $pager->getFilterParams(),
214                         $pager->getTagFilter(),
215                         $pager->getAction()
216                 );
217
218                 # Insert list
219                 $logBody = $pager->getBody();
220                 if ( $logBody ) {
221                         $this->getOutput()->addHTML(
222                                 $pager->getNavigationBar() .
223                                         $this->getActionButtons(
224                                                 $loglist->beginLogEventsList() .
225                                                         $logBody .
226                                                         $loglist->endLogEventsList()
227                                         ) .
228                                         $pager->getNavigationBar()
229                         );
230                 } else {
231                         $this->getOutput()->addWikiMsg( 'logempty' );
232                 }
233         }
234
235         private function getActionButtons( $formcontents ) {
236                 $user = $this->getUser();
237                 $canRevDelete = $user->isAllowedAll( 'deletedhistory', 'deletelogentry' );
238                 $showTagEditUI = ChangeTags::showTagEditingUI( $user );
239                 # If the user doesn't have the ability to delete log entries nor edit tags,
240                 # don't bother showing them the button(s).
241                 if ( !$canRevDelete && !$showTagEditUI ) {
242                         return $formcontents;
243                 }
244
245                 # Show button to hide log entries and/or edit change tags
246                 $s = Html::openElement(
247                         'form',
248                         [ 'action' => wfScript(), 'id' => 'mw-log-deleterevision-submit' ]
249                 ) . "\n";
250                 $s .= Html::hidden( 'action', 'historysubmit' ) . "\n";
251                 $s .= Html::hidden( 'type', 'logging' ) . "\n";
252
253                 $buttons = '';
254                 if ( $canRevDelete ) {
255                         $buttons .= Html::element(
256                                 'button',
257                                 [
258                                         'type' => 'submit',
259                                         'name' => 'revisiondelete',
260                                         'value' => '1',
261                                         'class' => "deleterevision-log-submit mw-log-deleterevision-button"
262                                 ],
263                                 $this->msg( 'showhideselectedlogentries' )->text()
264                         ) . "\n";
265                 }
266                 if ( $showTagEditUI ) {
267                         $buttons .= Html::element(
268                                 'button',
269                                 [
270                                         'type' => 'submit',
271                                         'name' => 'editchangetags',
272                                         'value' => '1',
273                                         'class' => "editchangetags-log-submit mw-log-editchangetags-button"
274                                 ],
275                                 $this->msg( 'log-edit-tags' )->text()
276                         ) . "\n";
277                 }
278
279                 $buttons .= ( new ListToggle( $this->getOutput() ) )->getHTML();
280
281                 $s .= $buttons . $formcontents . $buttons;
282                 $s .= Html::closeElement( 'form' );
283
284                 return $s;
285         }
286
287         /**
288          * Set page title and show header for this log type
289          * @param string $type
290          * @since 1.19
291          */
292         protected function addHeader( $type ) {
293                 $page = new LogPage( $type );
294                 $this->getOutput()->setPageTitle( $page->getName() );
295                 $this->getOutput()->addHTML( $page->getDescription()
296                         ->setContext( $this->getContext() )->parseAsBlock() );
297         }
298
299         protected function getGroupName() {
300                 return 'changes';
301         }
302 }