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