MediaWiki master
SpecialUnblock.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Specials;
8
26
33
35 protected $target;
36
38 protected $block;
39
40 private UnblockUserFactory $unblockUserFactory;
41 private BlockTargetFactory $blockTargetFactory;
42 private DatabaseBlockStore $blockStore;
43 private UserNameUtils $userNameUtils;
44 private UserNamePrefixSearch $userNamePrefixSearch;
45 private WatchlistManager $watchlistManager;
46
47 public function __construct(
48 UnblockUserFactory $unblockUserFactory,
49 BlockTargetFactory $blockTargetFactory,
50 DatabaseBlockStore $blockStore,
51 UserNameUtils $userNameUtils,
52 UserNamePrefixSearch $userNamePrefixSearch,
53 WatchlistManager $watchlistManager
54 ) {
55 parent::__construct( 'Unblock', 'block' );
56 $this->unblockUserFactory = $unblockUserFactory;
57 $this->blockTargetFactory = $blockTargetFactory;
58 $this->blockStore = $blockStore;
59 $this->userNameUtils = $userNameUtils;
60 $this->userNamePrefixSearch = $userNamePrefixSearch;
61 $this->watchlistManager = $watchlistManager;
62 }
63
65 public function doesWrites() {
66 return true;
67 }
68
70 public function execute( $par ) {
71 $this->checkPermissions();
72 $this->checkReadOnly();
73
74 $this->target = $this->getTargetFromRequest( $par, $this->getRequest() );
75
76 // T382539
78 || $this->getRequest()->getBool( 'usecodex' )
79 ) {
80 // If target is null, redirect to Special:Block
81 if ( $this->target === null ) {
82 // Use 301 (Moved Permanently) as this is a deprecation
83 $this->getOutput()->redirect(
84 SpecialPage::getTitleFor( 'Block' )->getFullURL( 'redirected=1' ),
85 '301'
86 );
87 return;
88 }
89 }
90
91 $this->block = $this->blockStore->newFromTarget( $this->target );
92 if ( $this->target instanceof BlockTargetWithUserPage ) {
93 // Set the 'relevant user' in the skin, so it displays links like Contributions,
94 // User logs, UserRights, etc.
95 $this->getSkin()->setRelevantUser( $this->target->getUserIdentity() );
96 }
97
98 $this->setHeaders();
99 $this->outputHeader();
100 $this->addHelpLink( 'Help:Blocking users' );
101
102 $out = $this->getOutput();
103 $out->setPageTitleMsg( $this->msg( 'unblock-target' ) );
104 $out->addModules( [ 'mediawiki.userSuggest', 'mediawiki.special.block' ] );
105
106 $form = HTMLForm::factory( 'ooui', $this->getFields(), $this->getContext() )
107 ->setWrapperLegendMsg( 'unblock-target' )
108 ->setSubmitCallback( function ( array $data, HTMLForm $form ) {
109 if ( $this->target instanceof BlockTargetWithUserPage && $data['Watch'] ) {
110 $this->watchlistManager->addWatchIgnoringRights(
111 $form->getUser(),
112 Title::newFromPageReference( $this->target->getUserPage() )
113 );
114 }
115 $status = $this->unblockUserFactory->newUnblockUser(
116 $this->target,
117 $form->getContext()->getAuthority(),
118 $data['Reason'],
119 $data['Tags'] ?? []
120 )->unblock();
121
122 if ( $status->hasMessage( 'ipb_cant_unblock_multiple_blocks' ) ) {
123 // Add additional message sending users to [[Special:Block/Username]]
124 $status->error( 'unblock-error-multiblocks', $this->target->toString() );
125 }
126 return $status;
127 } )
128 ->setSubmitTextMsg( 'ipusubmit' )
129 ->addPreHtml( $this->msg( 'unblockiptext' )->parseAsBlock() );
130
131 if ( $this->target ) {
132 $userPage = $this->target->getLogPage();
133 $targetName = (string)$this->target;
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 $targetName,
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 $targetName,
168 ],
169 'showIfEmpty' => false
170 ]
171 );
172 if ( $logExtract !== '' ) {
173 $form->addPostHtml( $logExtract );
174 }
175 }
176 }
177
178 if ( $form->show() ) {
179 $msgsByType = [
180 Block::TYPE_IP => 'unblocked-ip',
181 Block::TYPE_USER => 'unblocked',
182 Block::TYPE_RANGE => 'unblocked-range',
183 Block::TYPE_AUTO => 'unblocked-id'
184 ];
185 $out->addWikiMsg(
186 $msgsByType[$this->target->getType()],
187 wfEscapeWikiText( (string)$this->target )
188 );
189 }
190 }
191
201 private function getTargetFromRequest( ?string $par, WebRequest $request ) {
202 $possibleTargets = [
203 $request->getVal( 'wpTarget', null ),
204 $par,
205 $request->getVal( 'ip', null ),
206 // B/C @since 1.18
207 $request->getVal( 'wpBlockAddress', null ),
208 ];
209 foreach ( $possibleTargets as $possibleTarget ) {
210 $target = $this->blockTargetFactory->newFromString( $possibleTarget );
211 // If type is not null then target is valid
212 if ( $target ) {
213 break;
214 }
215 }
216 return $target;
217 }
218
219 protected function getFields(): array {
220 $fields = [
221 'Target' => [
222 'type' => 'text',
223 'label-message' => 'unblock-target-label',
224 'autofocus' => true,
225 'size' => '45',
226 'required' => true,
227 'cssclass' => 'mw-autocomplete-user', // used by mediawiki.userSuggest
228 ],
229 'Name' => [
230 'type' => 'info',
231 'label-message' => 'unblock-target-label',
232 ],
233 'Reason' => [
234 'type' => 'text',
235 'label-message' => 'ipbreason',
236 ]
237 ];
238
239 if ( $this->block instanceof Block ) {
240 $type = $this->block->getType();
241 $targetName = $this->block->getTargetName();
242
243 // Autoblocks are logged as "autoblock #123 because the IP was recently used by
244 // User:Foo, and we've just got any block, auto or not, that applies to a target
245 // the user has specified. Someone could be fishing to connect IPs to autoblocks,
246 // so don't show any distinction between unblocked IPs and autoblocked IPs
247 if ( $type == Block::TYPE_AUTO && $this->target->getType() == Block::TYPE_IP ) {
248 $fields['Target']['default'] = (string)$this->target;
249 unset( $fields['Name'] );
250 } else {
251 $fields['Target']['default'] = $targetName;
252 $fields['Target']['type'] = 'hidden';
253 switch ( $type ) {
254 case Block::TYPE_IP:
255 $fields['Name']['default'] = $this->getLinkRenderer()->makeKnownLink(
256 $this->getSpecialPageFactory()->getTitleForAlias( 'Contributions/' . $targetName ),
257 $targetName
258 );
259 $fields['Name']['raw'] = true;
260 break;
261 case Block::TYPE_USER:
262 $fields['Name']['default'] = $this->getLinkRenderer()->makeLink(
263 new TitleValue( NS_USER, $targetName ),
264 $targetName
265 );
266 $fields['Name']['raw'] = true;
267 break;
268
269 case Block::TYPE_RANGE:
270 $fields['Name']['default'] = $targetName;
271 break;
272
273 case Block::TYPE_AUTO:
274 // Don't expose the real target of the autoblock
275 $fields['Name']['default'] = $this->block->getRedactedName();
276 $fields['Name']['raw'] = true;
277 $fields['Target']['default'] = $this->block->getRedactedTarget()->toString();
278 break;
279 }
280 // Target is hidden, so the reason is the first element
281 $fields['Target']['autofocus'] = false;
282 $fields['Reason']['autofocus'] = true;
283 }
284 } else {
285 $fields['Target']['default'] = $this->target;
286 unset( $fields['Name'] );
287 }
288 // Watchlist their user page? (Only if user is logged in)
289 if ( $this->getUser()->isRegistered() ) {
290 $fields['Watch'] = [
291 'type' => 'check',
292 'label-message' => 'ipbwatchuser',
293 ];
294 }
295
296 return $fields;
297 }
298
307 public function prefixSearchSubpages( $search, $limit, $offset ) {
308 $search = $this->userNameUtils->getCanonical( $search );
309 if ( !$search ) {
310 // No prefix suggestion for invalid user
311 return [];
312 }
313 // Autocomplete subpage as user list - public to allow caching
314 return $this->userNamePrefixSearch
315 ->search( UserNamePrefixSearch::AUDIENCE_PUBLIC, $search, $limit, $offset );
316 }
317
319 protected function getGroupName() {
320 return 'users';
321 }
322}
323
328class_alias( SpecialUnblock::class, 'SpecialUnblock' );
const NS_USER
Definition Defines.php:53
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Factory for BlockTarget objects.
Base class for block targets.
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:195
show()
The here's-one-I-made-earlier option: do the submission if posted, or display the form with or withou...
Definition HTMLForm.php:706
addPostHtml( $html)
Add HTML to the end of the display.
A class containing constants representing the names of configuration variables.
const UseCodexSpecialBlock
Name constant for the UseCodexSpecialBlock setting, for use with Config::get()
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.
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,...
getUser()
Shortcut to get the User executing this instance.
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
checkReadOnly()
If the wiki is currently in readonly mode, throws a ReadOnlyError.
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.
A special page for unblocking users.
execute( $par)
Default execute method Checks user permissions.This must be overridden by subclasses; it will be made...
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....
__construct(UnblockUserFactory $unblockUserFactory, BlockTargetFactory $blockTargetFactory, DatabaseBlockStore $blockStore, UserNameUtils $userNameUtils, UserNamePrefixSearch $userNamePrefixSearch, WatchlistManager $watchlistManager)
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:70
Handles searching prefixes of user names.
UserNameUtils service.
Shared interface for user and single IP targets, that is, for targets with a meaningful user page lin...
Represents a block that may prevent users from performing specific operations.
Definition Block.php:31