MediaWiki master
SpecialUnblock.php
Go to the documentation of this file.
1<?php
24namespace MediaWiki\Specials;
25
40use Wikimedia\IPUtils;
41
48
50 protected $target;
51
53 protected $type;
54
55 protected $block;
56
57 private UnblockUserFactory $unblockUserFactory;
58 private BlockUtils $blockUtils;
59 private DatabaseBlockStore $blockStore;
60 private UserNameUtils $userNameUtils;
61 private UserNamePrefixSearch $userNamePrefixSearch;
62 private WatchlistManager $watchlistManager;
63
72 public function __construct(
73 UnblockUserFactory $unblockUserFactory,
74 BlockUtils $blockUtils,
75 DatabaseBlockStore $blockStore,
76 UserNameUtils $userNameUtils,
77 UserNamePrefixSearch $userNamePrefixSearch,
78 WatchlistManager $watchlistManager
79 ) {
80 parent::__construct( 'Unblock', 'block' );
81 $this->unblockUserFactory = $unblockUserFactory;
82 $this->blockUtils = $blockUtils;
83 $this->blockStore = $blockStore;
84 $this->userNameUtils = $userNameUtils;
85 $this->userNamePrefixSearch = $userNamePrefixSearch;
86 $this->watchlistManager = $watchlistManager;
87 }
88
89 public function doesWrites() {
90 return true;
91 }
92
93 public function execute( $par ) {
94 $this->checkPermissions();
95 $this->checkReadOnly();
96
97 [ $this->target, $this->type ] = $this->getTargetAndType( $par, $this->getRequest() );
98 $this->block = $this->blockStore->newFromTarget( $this->target );
99 if ( $this->target instanceof UserIdentity ) {
100 // Set the 'relevant user' in the skin, so it displays links like Contributions,
101 // User logs, UserRights, etc.
102 $this->getSkin()->setRelevantUser( $this->target );
103 }
104
105 $this->setHeaders();
106 $this->outputHeader();
107 $this->addHelpLink( 'Help:Blocking users' );
108
109 $out = $this->getOutput();
110 $out->setPageTitleMsg( $this->msg( 'unblockip' ) );
111 $out->addModules( [ 'mediawiki.userSuggest', 'mediawiki.special.block' ] );
112
113 $form = HTMLForm::factory( 'ooui', $this->getFields(), $this->getContext() )
114 ->setWrapperLegendMsg( 'unblockip' )
115 ->setSubmitCallback( function ( array $data, HTMLForm $form ) {
116 if ( $this->type != Block::TYPE_RANGE
117 && $this->type != Block::TYPE_AUTO
118 && $data['Watch']
119 ) {
120 $this->watchlistManager->addWatchIgnoringRights(
121 $form->getUser(),
122 Title::makeTitle( NS_USER, $this->target )
123 );
124 }
125 return $this->unblockUserFactory->newUnblockUser(
126 $data['Target'],
127 $form->getContext()->getAuthority(),
128 $data['Reason'],
129 $data['Tags'] ?? []
130 )->unblock();
131 } )
132 ->setSubmitTextMsg( 'ipusubmit' )
133 ->addPreHtml( $this->msg( 'unblockiptext' )->parseAsBlock() );
134
135 $userPage = $this->getTargetUserTitle( $this->target );
136 if ( $userPage ) {
137 // Get relevant extracts from the block and suppression logs, if possible
138 $logExtract = '';
139 LogEventsList::showLogExtract(
140 $logExtract,
141 'block',
142 $userPage,
143 '',
144 [
145 'lim' => 10,
146 'msgKey' => [
147 'unblocklog-showlog',
148 $userPage->getText(),
149 ],
150 'showIfEmpty' => false
151 ]
152 );
153 if ( $logExtract !== '' ) {
154 $form->addPostHtml( $logExtract );
155 }
156
157 // Add suppression block entries if allowed
158 if ( $this->getAuthority()->isAllowed( 'suppressionlog' ) ) {
159 $logExtract = '';
160 LogEventsList::showLogExtract(
161 $logExtract,
162 'suppress',
163 $userPage,
164 '',
165 [
166 'lim' => 10,
167 'conds' => [ 'log_action' => [ 'block', 'reblock', 'unblock' ] ],
168 'msgKey' => [
169 'unblocklog-showsuppresslog',
170 $userPage->getText(),
171 ],
172 'showIfEmpty' => false
173 ]
174 );
175 if ( $logExtract !== '' ) {
176 $form->addPostHtml( $logExtract );
177 }
178 }
179 }
180
181 if ( $form->show() ) {
182 switch ( $this->type ) {
183 case Block::TYPE_IP:
184 $out->addWikiMsg( 'unblocked-ip', wfEscapeWikiText( $this->target ) );
185 break;
186 case Block::TYPE_USER:
187 $out->addWikiMsg( 'unblocked', wfEscapeWikiText( $this->target ) );
188 break;
189 case Block::TYPE_RANGE:
190 $out->addWikiMsg( 'unblocked-range', wfEscapeWikiText( $this->target ) );
191 break;
192 case Block::TYPE_ID:
193 case Block::TYPE_AUTO:
194 $out->addWikiMsg( 'unblocked-id', wfEscapeWikiText( $this->target ) );
195 break;
196 }
197 }
198 }
199
210 private function getTargetAndType( ?string $par, WebRequest $request ) {
211 $possibleTargets = [
212 $request->getVal( 'wpTarget', null ),
213 $par,
214 $request->getVal( 'ip', null ),
215 // B/C @since 1.18
216 $request->getVal( 'wpBlockAddress', null ),
217 ];
218 foreach ( $possibleTargets as $possibleTarget ) {
219 $targetAndType = $this->blockUtils->parseBlockTarget( $possibleTarget );
220 // If type is not null then target is valid
221 if ( $targetAndType[ 1 ] !== null ) {
222 break;
223 }
224 }
225 return $targetAndType;
226 }
227
234 private function getTargetUserTitle( $target ): ?Title {
235 if ( $target instanceof UserIdentity ) {
236 return Title::makeTitle( NS_USER, $target->getName() );
237 }
238
239 if ( is_string( $target ) && IPUtils::isIPAddress( $target ) ) {
240 return Title::makeTitle( NS_USER, $target );
241 }
242
243 return null;
244 }
245
246 protected function getFields() {
247 $fields = [
248 'Target' => [
249 'type' => 'text',
250 'label-message' => 'ipaddressorusername',
251 'autofocus' => true,
252 'size' => '45',
253 'required' => true,
254 'cssclass' => 'mw-autocomplete-user', // used by mediawiki.userSuggest
255 ],
256 'Name' => [
257 'type' => 'info',
258 'label-message' => 'ipaddressorusername',
259 ],
260 'Reason' => [
261 'type' => 'text',
262 'label-message' => 'ipbreason',
263 ]
264 ];
265
266 if ( $this->block instanceof Block ) {
267 $type = $this->block->getType();
268 $targetName = $this->block->getTargetName();
269
270 // Autoblocks are logged as "autoblock #123 because the IP was recently used by
271 // User:Foo, and we've just got any block, auto or not, that applies to a target
272 // the user has specified. Someone could be fishing to connect IPs to autoblocks,
273 // so don't show any distinction between unblocked IPs and autoblocked IPs
274 if ( $type == Block::TYPE_AUTO && $this->type == Block::TYPE_IP ) {
275 $fields['Target']['default'] = $this->target;
276 unset( $fields['Name'] );
277 } else {
278 $fields['Target']['default'] = $targetName;
279 $fields['Target']['type'] = 'hidden';
280 switch ( $type ) {
281 case Block::TYPE_IP:
282 $fields['Name']['default'] = $this->getLinkRenderer()->makeKnownLink(
283 $this->getSpecialPageFactory()->getTitleForAlias( 'Contributions/' . $targetName ),
284 $targetName
285 );
286 $fields['Name']['raw'] = true;
287 break;
288 case Block::TYPE_USER:
289 $fields['Name']['default'] = $this->getLinkRenderer()->makeLink(
290 new TitleValue( NS_USER, $targetName ),
291 $targetName
292 );
293 $fields['Name']['raw'] = true;
294 break;
295
296 case Block::TYPE_RANGE:
297 $fields['Name']['default'] = $targetName;
298 break;
299
300 case Block::TYPE_AUTO:
301 $fields['Name']['default'] = $this->block->getRedactedName();
302 $fields['Name']['raw'] = true;
303 // Don't expose the real target of the autoblock
304 $fields['Target']['default'] = "#{$this->target}";
305 break;
306 }
307 // Target is hidden, so the reason is the first element
308 $fields['Target']['autofocus'] = false;
309 $fields['Reason']['autofocus'] = true;
310 }
311 } else {
312 $fields['Target']['default'] = $this->target;
313 unset( $fields['Name'] );
314 }
315 // Watchlist their user page? (Only if user is logged in)
316 if ( $this->getUser()->isRegistered() ) {
317 $fields['Watch'] = [
318 'type' => 'check',
319 'label-message' => 'ipbwatchuser',
320 ];
321 }
322
323 return $fields;
324 }
325
334 public function prefixSearchSubpages( $search, $limit, $offset ) {
335 $search = $this->userNameUtils->getCanonical( $search );
336 if ( !$search ) {
337 // No prefix suggestion for invalid user
338 return [];
339 }
340 // Autocomplete subpage as user list - public to allow caching
341 return $this->userNamePrefixSearch
342 ->search( UserNamePrefixSearch::AUDIENCE_PUBLIC, $search, $limit, $offset );
343 }
344
345 protected function getGroupName() {
346 return 'users';
347 }
348}
349
354class_alias( SpecialUnblock::class, 'SpecialUnblock' );
getUser()
const NS_USER
Definition Defines.php:66
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
Backend class for blocking utils.
getContext()
Get the base IContextSource object.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:206
show()
The here's-one-I-made-earlier option: do the submission if posted, or display the form with or withou...
Definition HTMLForm.php:687
addPostHtml( $html)
Add HTML to the end of the display.
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
getVal( $name, $default=null)
Fetch a text string and partially normalize it.
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.
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
checkReadOnly()
If the wiki is currently in readonly mode, throws a ReadOnlyError.
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 Per default the message key is the canonical name o...
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
A special page for unblocking users.
UserIdentity string null $target
execute( $par)
Default execute method Checks user permissions.
__construct(UnblockUserFactory $unblockUserFactory, BlockUtils $blockUtils, DatabaseBlockStore $blockStore, UserNameUtils $userNameUtils, UserNamePrefixSearch $userNamePrefixSearch, WatchlistManager $watchlistManager)
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
doesWrites()
Indicates whether this special page may perform database writes.
int null $type
Block::TYPE_ constant.
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
Represents the target of a wiki link.
Represents a title within MediaWiki.
Definition Title.php:78
Handles searching prefixes of user names.
UserNameUtils service.
Represents a block that may prevent users from performing specific operations.
Definition Block.php:45
Interface for objects representing user identity.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...