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 public function __construct(
41 private readonly UnblockUserFactory $unblockUserFactory,
42 private readonly BlockTargetFactory $blockTargetFactory,
43 private readonly DatabaseBlockStore $blockStore,
44 private readonly UserNameUtils $userNameUtils,
45 private readonly UserNamePrefixSearch $userNamePrefixSearch,
46 private readonly WatchlistManager $watchlistManager,
47 ) {
48 parent::__construct( 'Unblock', 'block' );
49 }
50
52 public function doesWrites() {
53 return true;
54 }
55
57 public function execute( $par ) {
58 $this->checkPermissions();
59 $this->checkReadOnly();
60
61 $this->target = $this->getTargetFromRequest( $par, $this->getRequest() );
62
63 // T382539
65 || $this->getRequest()->getBool( 'usecodex' )
66 ) {
67 // If target is null, redirect to Special:Block
68 if ( $this->target === null ) {
69 // Use 301 (Moved Permanently) as this is a deprecation
70 $this->getOutput()->redirect(
71 SpecialPage::getTitleFor( 'Block' )->getFullURL( 'redirected=1' ),
72 '301'
73 );
74 return;
75 }
76 }
77
78 $this->block = $this->blockStore->newFromTarget( $this->target );
79 if ( $this->target instanceof BlockTargetWithUserPage ) {
80 // Set the 'relevant user' in the skin, so it displays links like Contributions,
81 // User logs, UserRights, etc.
82 $this->getSkin()->setRelevantUser( $this->target->getUserIdentity() );
83 }
84
85 $this->setHeaders();
86 $this->outputHeader();
87 $this->addHelpLink( 'Help:Blocking users' );
88
89 $out = $this->getOutput();
90 $out->setPageTitleMsg( $this->msg( 'unblock-target' ) );
91 $out->addModules( [ 'mediawiki.userSuggest', 'mediawiki.special.block' ] );
92
93 $form = HTMLForm::factory( 'ooui', $this->getFields(), $this->getContext() )
94 ->setWrapperLegendMsg( 'unblock-target' )
95 ->setSubmitCallback( function ( array $data, HTMLForm $form ) {
96 if ( $this->target instanceof BlockTargetWithUserPage && $data['Watch'] ) {
97 $this->watchlistManager->addWatchIgnoringRights(
98 $form->getUser(),
99 Title::newFromPageReference( $this->target->getUserPage() )
100 );
101 }
102 $status = $this->unblockUserFactory->newUnblockUser(
103 $this->target,
104 $form->getContext()->getAuthority(),
105 $data['Reason'],
106 $data['Tags'] ?? []
107 )->unblock();
108
109 if ( $status->hasMessage( 'ipb_cant_unblock_multiple_blocks' ) ) {
110 // Add additional message sending users to [[Special:Block/Username]]
111 $status->error( 'unblock-error-multiblocks', $this->target->toString() );
112 }
113 return $status;
114 } )
115 ->setSubmitTextMsg( 'ipusubmit' )
116 ->addPreHtml( $this->msg( 'unblockiptext' )->parseAsBlock() );
117
118 if ( $this->target ) {
119 $userPage = $this->target->getLogPage();
120 $targetName = (string)$this->target;
121 // Get relevant extracts from the block and suppression logs, if possible
122 $logExtract = '';
123 LogEventsList::showLogExtract(
124 $logExtract,
125 'block',
126 $userPage,
127 '',
128 [
129 'lim' => 10,
130 'msgKey' => [
131 'unblocklog-showlog',
132 $targetName,
133 ],
134 'showIfEmpty' => false
135 ]
136 );
137 if ( $logExtract !== '' ) {
138 $form->addPostHtml( $logExtract );
139 }
140
141 // Add suppression block entries if allowed
142 if ( $this->getAuthority()->isAllowed( 'suppressionlog' ) ) {
143 $logExtract = '';
144 LogEventsList::showLogExtract(
145 $logExtract,
146 'suppress',
147 $userPage,
148 '',
149 [
150 'lim' => 10,
151 'conds' => [ 'log_action' => [ 'block', 'reblock', 'unblock' ] ],
152 'msgKey' => [
153 'unblocklog-showsuppresslog',
154 $targetName,
155 ],
156 'showIfEmpty' => false
157 ]
158 );
159 if ( $logExtract !== '' ) {
160 $form->addPostHtml( $logExtract );
161 }
162 }
163 }
164
165 if ( $form->show() ) {
166 $msgsByType = [
167 Block::TYPE_IP => 'unblocked-ip',
168 Block::TYPE_USER => 'unblocked',
169 Block::TYPE_RANGE => 'unblocked-range',
170 Block::TYPE_AUTO => 'unblocked-id'
171 ];
172 $out->addWikiMsg(
173 $msgsByType[$this->target->getType()],
174 wfEscapeWikiText( (string)$this->target )
175 );
176 }
177 }
178
188 private function getTargetFromRequest( ?string $par, WebRequest $request ) {
189 $possibleTargets = [
190 $request->getVal( 'wpTarget', null ),
191 $par,
192 $request->getVal( 'ip', null ),
193 // B/C @since 1.18
194 $request->getVal( 'wpBlockAddress', null ),
195 ];
196 foreach ( $possibleTargets as $possibleTarget ) {
197 $target = $this->blockTargetFactory->newFromString( $possibleTarget );
198 // If type is not null then target is valid
199 if ( $target ) {
200 break;
201 }
202 }
203 return $target;
204 }
205
206 protected function getFields(): array {
207 $fields = [
208 'Target' => [
209 'type' => 'text',
210 'label-message' => 'unblock-target-label',
211 'autofocus' => true,
212 'size' => '45',
213 'required' => true,
214 'cssclass' => 'mw-autocomplete-user', // used by mediawiki.userSuggest
215 ],
216 'Name' => [
217 'type' => 'info',
218 'label-message' => 'unblock-target-label',
219 ],
220 'Reason' => [
221 'type' => 'text',
222 'label-message' => 'ipbreason',
223 ]
224 ];
225
226 if ( $this->block instanceof Block ) {
227 $type = $this->block->getType();
228 $targetName = $this->block->getTargetName();
229
230 // Autoblocks are logged as "autoblock #123 because the IP was recently used by
231 // User:Foo, and we've just got any block, auto or not, that applies to a target
232 // the user has specified. Someone could be fishing to connect IPs to autoblocks,
233 // so don't show any distinction between unblocked IPs and autoblocked IPs
234 if ( $type == Block::TYPE_AUTO && $this->target->getType() == Block::TYPE_IP ) {
235 $fields['Target']['default'] = (string)$this->target;
236 unset( $fields['Name'] );
237 } else {
238 $fields['Target']['default'] = $targetName;
239 $fields['Target']['type'] = 'hidden';
240 switch ( $type ) {
241 case Block::TYPE_IP:
242 $fields['Name']['default'] = $this->getLinkRenderer()->makeKnownLink(
243 $this->getSpecialPageFactory()->getTitleForAlias( 'Contributions/' . $targetName ),
244 $targetName
245 );
246 $fields['Name']['raw'] = true;
247 break;
248 case Block::TYPE_USER:
249 $fields['Name']['default'] = $this->getLinkRenderer()->makeLink(
250 new TitleValue( NS_USER, $targetName ),
251 $targetName
252 );
253 $fields['Name']['raw'] = true;
254 break;
255
256 case Block::TYPE_RANGE:
257 $fields['Name']['default'] = $targetName;
258 break;
259
260 case Block::TYPE_AUTO:
261 // Don't expose the real target of the autoblock
262 $fields['Name']['default'] = $this->block->getRedactedName();
263 $fields['Name']['raw'] = true;
264 $fields['Target']['default'] = $this->block->getRedactedTarget()->toString();
265 break;
266 }
267 // Target is hidden, so the reason is the first element
268 $fields['Target']['autofocus'] = false;
269 $fields['Reason']['autofocus'] = true;
270 }
271 } else {
272 $fields['Target']['default'] = $this->target;
273 unset( $fields['Name'] );
274 }
275 // Watchlist their user page? (Only if user is logged in)
276 if ( $this->getUser()->isRegistered() ) {
277 $fields['Watch'] = [
278 'type' => 'check',
279 'label-message' => 'ipbwatchuser',
280 ];
281 }
282
283 return $fields;
284 }
285
294 public function prefixSearchSubpages( $search, $limit, $offset ) {
295 $search = $this->userNameUtils->getCanonical( $search );
296 if ( !$search ) {
297 // No prefix suggestion for invalid user
298 return [];
299 }
300 // Autocomplete subpage as user list - public to allow caching
301 return $this->userNamePrefixSearch
302 ->search( UserNamePrefixSearch::AUDIENCE_PUBLIC, $search, $limit, $offset );
303 }
304
306 protected function getGroupName() {
307 return 'users';
308 }
309}
310
315class_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:207
show()
The here's-one-I-made-earlier option: do the submission if posted, or display the form with or withou...
Definition HTMLForm.php:726
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...
__construct(private readonly UnblockUserFactory $unblockUserFactory, private readonly BlockTargetFactory $blockTargetFactory, private readonly DatabaseBlockStore $blockStore, private readonly UserNameUtils $userNameUtils, private readonly UserNamePrefixSearch $userNamePrefixSearch, private readonly WatchlistManager $watchlistManager,)
doesWrites()
Indicates whether POST requests to this special page require write access to the wiki....
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:69
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