MediaWiki master
SpecialUnblock.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Specials;
22
38use Wikimedia\IPUtils;
39
46
48 protected $target;
49
51 protected $type;
52
54 protected $block;
55
56 private UnblockUserFactory $unblockUserFactory;
57 private BlockUtils $blockUtils;
58 private DatabaseBlockStore $blockStore;
59 private UserNameUtils $userNameUtils;
60 private UserNamePrefixSearch $userNamePrefixSearch;
61 private WatchlistManager $watchlistManager;
62
71 public function __construct(
72 UnblockUserFactory $unblockUserFactory,
73 BlockUtils $blockUtils,
74 DatabaseBlockStore $blockStore,
75 UserNameUtils $userNameUtils,
76 UserNamePrefixSearch $userNamePrefixSearch,
77 WatchlistManager $watchlistManager
78 ) {
79 parent::__construct( 'Unblock', 'block' );
80 $this->unblockUserFactory = $unblockUserFactory;
81 $this->blockUtils = $blockUtils;
82 $this->blockStore = $blockStore;
83 $this->userNameUtils = $userNameUtils;
84 $this->userNamePrefixSearch = $userNamePrefixSearch;
85 $this->watchlistManager = $watchlistManager;
86 }
87
88 public function doesWrites() {
89 return true;
90 }
91
92 public function execute( $par ) {
93 $this->checkPermissions();
94 $this->checkReadOnly();
95
96 [ $this->target, $this->type ] = $this->getTargetAndType( $par, $this->getRequest() );
97 $this->block = $this->blockStore->newFromTarget( $this->target );
98 if ( $this->target instanceof UserIdentity ) {
99 // Set the 'relevant user' in the skin, so it displays links like Contributions,
100 // User logs, UserRights, etc.
101 $this->getSkin()->setRelevantUser( $this->target );
102 }
103
104 $this->setHeaders();
105 $this->outputHeader();
106 $this->addHelpLink( 'Help:Blocking users' );
107
108 $out = $this->getOutput();
109 $out->setPageTitleMsg( $this->msg( 'unblockip' ) );
110 $out->addModules( [ 'mediawiki.userSuggest', 'mediawiki.special.block' ] );
111
112 $form = HTMLForm::factory( 'ooui', $this->getFields(), $this->getContext() )
113 ->setWrapperLegendMsg( 'unblockip' )
114 ->setSubmitCallback( function ( array $data, HTMLForm $form ) {
115 if ( $this->type != Block::TYPE_RANGE
116 && $this->type != Block::TYPE_AUTO
117 && $data['Watch']
118 ) {
119 $this->watchlistManager->addWatchIgnoringRights(
120 $form->getUser(),
121 Title::makeTitle( NS_USER, $this->target )
122 );
123 }
124 return $this->unblockUserFactory->newUnblockUser(
125 $data['Target'],
126 $form->getContext()->getAuthority(),
127 $data['Reason'],
128 $data['Tags'] ?? []
129 )->unblock();
130 } )
131 ->setSubmitTextMsg( 'ipusubmit' )
132 ->addPreHtml( $this->msg( 'unblockiptext' )->parseAsBlock() );
133
134 $userPage = $this->getTargetUserTitle( $this->target );
135 if ( $userPage ) {
136 // Get relevant extracts from the block and suppression logs, if possible
137 $logExtract = '';
138 LogEventsList::showLogExtract(
139 $logExtract,
140 'block',
141 $userPage,
142 '',
143 [
144 'lim' => 10,
145 'msgKey' => [
146 'unblocklog-showlog',
147 $userPage->getText(),
148 ],
149 'showIfEmpty' => false
150 ]
151 );
152 if ( $logExtract !== '' ) {
153 $form->addPostHtml( $logExtract );
154 }
155
156 // Add suppression block entries if allowed
157 if ( $this->getAuthority()->isAllowed( 'suppressionlog' ) ) {
158 $logExtract = '';
159 LogEventsList::showLogExtract(
160 $logExtract,
161 'suppress',
162 $userPage,
163 '',
164 [
165 'lim' => 10,
166 'conds' => [ 'log_action' => [ 'block', 'reblock', 'unblock' ] ],
167 'msgKey' => [
168 'unblocklog-showsuppresslog',
169 $userPage->getText(),
170 ],
171 'showIfEmpty' => false
172 ]
173 );
174 if ( $logExtract !== '' ) {
175 $form->addPostHtml( $logExtract );
176 }
177 }
178 }
179
180 if ( $form->show() ) {
181 switch ( $this->type ) {
182 case Block::TYPE_IP:
183 $out->addWikiMsg( 'unblocked-ip', wfEscapeWikiText( $this->target ) );
184 break;
185 case Block::TYPE_USER:
186 $out->addWikiMsg( 'unblocked', wfEscapeWikiText( $this->target ) );
187 break;
188 case Block::TYPE_RANGE:
189 $out->addWikiMsg( 'unblocked-range', wfEscapeWikiText( $this->target ) );
190 break;
191 case Block::TYPE_ID:
192 case Block::TYPE_AUTO:
193 $out->addWikiMsg( 'unblocked-id', wfEscapeWikiText( $this->target ) );
194 break;
195 }
196 }
197 }
198
209 private function getTargetAndType( ?string $par, WebRequest $request ) {
210 $possibleTargets = [
211 $request->getVal( 'wpTarget', null ),
212 $par,
213 $request->getVal( 'ip', null ),
214 // B/C @since 1.18
215 $request->getVal( 'wpBlockAddress', null ),
216 ];
217 foreach ( $possibleTargets as $possibleTarget ) {
218 $targetAndType = $this->blockUtils->parseBlockTarget( $possibleTarget );
219 // If type is not null then target is valid
220 if ( $targetAndType[ 1 ] !== null ) {
221 break;
222 }
223 }
224 return $targetAndType;
225 }
226
233 private function getTargetUserTitle( $target ): ?Title {
234 if ( $target instanceof UserIdentity ) {
235 return Title::makeTitle( NS_USER, $target->getName() );
236 }
237
238 if ( is_string( $target ) && IPUtils::isIPAddress( $target ) ) {
239 return Title::makeTitle( NS_USER, $target );
240 }
241
242 return null;
243 }
244
245 protected function getFields() {
246 $fields = [
247 'Target' => [
248 'type' => 'text',
249 'label-message' => 'ipaddressorusername',
250 'autofocus' => true,
251 'size' => '45',
252 'required' => true,
253 'cssclass' => 'mw-autocomplete-user', // used by mediawiki.userSuggest
254 ],
255 'Name' => [
256 'type' => 'info',
257 'label-message' => 'ipaddressorusername',
258 ],
259 'Reason' => [
260 'type' => 'text',
261 'label-message' => 'ipbreason',
262 ]
263 ];
264
265 if ( $this->block instanceof Block ) {
266 $type = $this->block->getType();
267 $targetName = $this->block->getTargetName();
268
269 // Autoblocks are logged as "autoblock #123 because the IP was recently used by
270 // User:Foo, and we've just got any block, auto or not, that applies to a target
271 // the user has specified. Someone could be fishing to connect IPs to autoblocks,
272 // so don't show any distinction between unblocked IPs and autoblocked IPs
273 if ( $type == Block::TYPE_AUTO && $this->type == Block::TYPE_IP ) {
274 $fields['Target']['default'] = $this->target;
275 unset( $fields['Name'] );
276 } else {
277 $fields['Target']['default'] = $targetName;
278 $fields['Target']['type'] = 'hidden';
279 switch ( $type ) {
280 case Block::TYPE_IP:
281 $fields['Name']['default'] = $this->getLinkRenderer()->makeKnownLink(
282 $this->getSpecialPageFactory()->getTitleForAlias( 'Contributions/' . $targetName ),
283 $targetName
284 );
285 $fields['Name']['raw'] = true;
286 break;
287 case Block::TYPE_USER:
288 $fields['Name']['default'] = $this->getLinkRenderer()->makeLink(
289 new TitleValue( NS_USER, $targetName ),
290 $targetName
291 );
292 $fields['Name']['raw'] = true;
293 break;
294
295 case Block::TYPE_RANGE:
296 $fields['Name']['default'] = $targetName;
297 break;
298
299 case Block::TYPE_AUTO:
300 $fields['Name']['default'] = $this->block->getRedactedName();
301 $fields['Name']['raw'] = true;
302 // Don't expose the real target of the autoblock
303 $fields['Target']['default'] = "#{$this->target}";
304 break;
305 }
306 // Target is hidden, so the reason is the first element
307 $fields['Target']['autofocus'] = false;
308 $fields['Reason']['autofocus'] = true;
309 }
310 } else {
311 $fields['Target']['default'] = $this->target;
312 unset( $fields['Name'] );
313 }
314 // Watchlist their user page? (Only if user is logged in)
315 if ( $this->getUser()->isRegistered() ) {
316 $fields['Watch'] = [
317 'type' => 'check',
318 'label-message' => 'ipbwatchuser',
319 ];
320 }
321
322 return $fields;
323 }
324
333 public function prefixSearchSubpages( $search, $limit, $offset ) {
334 $search = $this->userNameUtils->getCanonical( $search );
335 if ( !$search ) {
336 // No prefix suggestion for invalid user
337 return [];
338 }
339 // Autocomplete subpage as user list - public to allow caching
340 return $this->userNamePrefixSearch
341 ->search( UserNamePrefixSearch::AUDIENCE_PUBLIC, $search, $limit, $offset );
342 }
343
344 protected function getGroupName() {
345 return 'users';
346 }
347}
348
353class_alias( SpecialUnblock::class, 'SpecialUnblock' );
const NS_USER
Definition Defines.php:67
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.
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
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:209
show()
The here's-one-I-made-earlier option: do the submission if posted, or display the form with or withou...
Definition HTMLForm.php:716
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,...
getVal( $name, $default=null)
Fetch a text string from this web request's $_GET, $_POST or path router vars and partially normalize...
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 By default the message key is the canonical name of...
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 POST requests to this special page require write access to the wiki.
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.