MediaWiki REL1_41
ApiMove.php
Go to the documentation of this file.
1<?php
30
35class ApiMove extends ApiBase {
36
38
39 private MovePageFactory $movePageFactory;
40 private RepoGroup $repoGroup;
41
42 public function __construct(
43 ApiMain $mainModule,
44 $moduleName,
45 MovePageFactory $movePageFactory,
46 RepoGroup $repoGroup,
47 WatchlistManager $watchlistManager,
48 UserOptionsLookup $userOptionsLookup
49 ) {
50 parent::__construct( $mainModule, $moduleName );
51
52 $this->movePageFactory = $movePageFactory;
53 $this->repoGroup = $repoGroup;
54
55 // Variables needed in ApiWatchlistTrait trait
56 $this->watchlistExpiryEnabled = $this->getConfig()->get( MainConfigNames::WatchlistExpiry );
57 $this->watchlistMaxDuration =
58 $this->getConfig()->get( MainConfigNames::WatchlistExpiryMaxDuration );
59 $this->watchlistManager = $watchlistManager;
60 $this->userOptionsLookup = $userOptionsLookup;
61 }
62
63 public function execute() {
65
66 $user = $this->getUser();
67 $params = $this->extractRequestParams();
68
69 $this->requireOnlyOneParameter( $params, 'from', 'fromid' );
70
71 if ( isset( $params['from'] ) ) {
72 $fromTitle = Title::newFromText( $params['from'] );
73 if ( !$fromTitle || $fromTitle->isExternal() ) {
74 $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['from'] ) ] );
75 }
76 } elseif ( isset( $params['fromid'] ) ) {
77 $fromTitle = Title::newFromID( $params['fromid'] );
78 if ( !$fromTitle ) {
79 $this->dieWithError( [ 'apierror-nosuchpageid', $params['fromid'] ] );
80 }
81 } else {
82 throw new LogicException( 'Unreachable due to requireOnlyOneParameter' );
83 }
84
85 if ( !$fromTitle->exists() ) {
86 $this->dieWithError( 'apierror-missingtitle' );
87 }
88 $fromTalk = $fromTitle->getTalkPage();
89
90 $toTitle = Title::newFromText( $params['to'] );
91 if ( !$toTitle || $toTitle->isExternal() ) {
92 $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['to'] ) ] );
93 }
94 $toTalk = $toTitle->getTalkPageIfDefined();
95
96 if ( $toTitle->getNamespace() === NS_FILE
97 && !$this->repoGroup->getLocalRepo()->findFile( $toTitle )
98 && $this->repoGroup->findFile( $toTitle )
99 ) {
100 if ( !$params['ignorewarnings'] &&
101 $this->getAuthority()->isAllowed( 'reupload-shared' ) ) {
102 $this->dieWithError( 'apierror-fileexists-sharedrepo-perm' );
103 } elseif ( !$this->getAuthority()->isAllowed( 'reupload-shared' ) ) {
104 $this->dieWithError( 'apierror-cantoverwrite-sharedfile' );
105 }
106 }
107
108 // Move the page
109 $toTitleExists = $toTitle->exists();
110 $mp = $this->movePageFactory->newMovePage( $fromTitle, $toTitle );
111 $status = $mp->moveIfAllowed(
112 $this->getAuthority(),
113 $params['reason'],
114 !$params['noredirect'],
115 $params['tags'] ?: []
116 );
117 if ( !$status->isOK() ) {
118 $this->dieStatus( $status );
119 }
120
121 $r = [
122 'from' => $fromTitle->getPrefixedText(),
123 'to' => $toTitle->getPrefixedText(),
124 'reason' => $params['reason']
125 ];
126
127 // NOTE: we assume that if the old title exists, it's because it was re-created as
128 // a redirect to the new title. This is not safe, but what we did before was
129 // even worse: we just determined whether a redirect should have been created,
130 // and reported that it was created if it should have, without any checks.
131 $r['redirectcreated'] = $fromTitle->exists();
132
133 $r['moveoverredirect'] = $toTitleExists;
134
135 // Move the talk page
136 if ( $params['movetalk'] && $toTalk && $fromTalk->exists() && !$fromTitle->isTalkPage() ) {
137 $toTalkExists = $toTalk->exists();
138 $mp = $this->movePageFactory->newMovePage( $fromTalk, $toTalk );
139 $status = $mp->moveIfAllowed(
140 $this->getAuthority(),
141 $params['reason'],
142 !$params['noredirect'],
143 $params['tags'] ?: []
144 );
145 if ( $status->isOK() ) {
146 $r['talkfrom'] = $fromTalk->getPrefixedText();
147 $r['talkto'] = $toTalk->getPrefixedText();
148 $r['talkmoveoverredirect'] = $toTalkExists;
149 } else {
150 // We're not going to dieWithError() on failure, since we already changed something
151 $r['talkmove-errors'] = $this->getErrorFormatter()->arrayFromStatus( $status );
152 }
153 }
154
155 $result = $this->getResult();
156
157 // Move subpages
158 if ( $params['movesubpages'] ) {
159 $r['subpages'] = $this->moveSubpages(
160 $fromTitle,
161 $toTitle,
162 $params['reason'],
163 $params['noredirect'],
164 $params['tags'] ?: []
165 );
166 ApiResult::setIndexedTagName( $r['subpages'], 'subpage' );
167
168 if ( $params['movetalk'] && $toTalk ) {
169 $r['subpages-talk'] = $this->moveSubpages(
170 $fromTalk,
171 $toTalk,
172 $params['reason'],
173 $params['noredirect'],
174 $params['tags'] ?: []
175 );
176 ApiResult::setIndexedTagName( $r['subpages-talk'], 'subpage' );
177 }
178 }
179
180 $watch = $params['watchlist'] ?? 'preferences';
181 $watchlistExpiry = $this->getExpiryFromParams( $params );
182
183 // Watch pages
184 $this->setWatch( $watch, $fromTitle, $user, 'watchmoves', $watchlistExpiry );
185 $this->setWatch( $watch, $toTitle, $user, 'watchmoves', $watchlistExpiry );
186
187 $result->addValue( null, $this->getModuleName(), $r );
188 }
189
198 public function moveSubpages( $fromTitle, $toTitle, $reason, $noredirect, $changeTags = [] ) {
199 $retval = [];
200
201 $mp = $this->movePageFactory->newMovePage( $fromTitle, $toTitle );
202 $result =
203 $mp->moveSubpagesIfAllowed( $this->getAuthority(), $reason, !$noredirect, $changeTags );
204 if ( !$result->isOK() ) {
205 // This means the whole thing failed
206 return [ 'errors' => $this->getErrorFormatter()->arrayFromStatus( $result ) ];
207 }
208
209 // At least some pages could be moved
210 // Report each of them separately
211 foreach ( $result->getValue() as $oldTitle => $status ) {
213 $r = [ 'from' => $oldTitle ];
214 if ( $status->isOK() ) {
215 $r['to'] = $status->getValue();
216 } else {
217 $r['errors'] = $this->getErrorFormatter()->arrayFromStatus( $status );
218 }
219 $retval[] = $r;
220 }
221
222 return $retval;
223 }
224
225 public function mustBePosted() {
226 return true;
227 }
228
229 public function isWriteMode() {
230 return true;
231 }
232
233 public function getAllowedParams() {
234 $params = [
235 'from' => null,
236 'fromid' => [
237 ParamValidator::PARAM_TYPE => 'integer'
238 ],
239 'to' => [
240 ParamValidator::PARAM_TYPE => 'string',
241 ParamValidator::PARAM_REQUIRED => true
242 ],
243 'reason' => '',
244 'movetalk' => false,
245 'movesubpages' => false,
246 'noredirect' => false,
247 ];
248
249 // Params appear in the docs in the order they are defined,
250 // which is why this is here and not at the bottom.
251 $params += $this->getWatchlistParams();
252
253 return $params + [
254 'ignorewarnings' => false,
255 'tags' => [
256 ParamValidator::PARAM_TYPE => 'tags',
257 ParamValidator::PARAM_ISMULTI => true,
258 ],
259 ];
260 }
261
262 public function needsToken() {
263 return 'csrf';
264 }
265
266 protected function getExamplesMessages() {
267 return [
268 'action=move&from=Badtitle&to=Goodtitle&token=123ABC&' .
269 'reason=Misspelled%20title&movetalk=&noredirect='
270 => 'apihelp-move-example-move',
271 ];
272 }
273
274 public function getHelpUrls() {
275 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Move';
276 }
277}
getExpiryFromParams(array $params)
Get formatted expiry from the given parameters, or null if no expiry was provided.
setWatch(string $watch, Title $title, User $user, ?string $userOption=null, ?string $expiry=null)
Set a watch (or unwatch) based the based on a watchlist parameter.
getWatchlistParams(array $watchOptions=[])
Get additional allow params specific to watchlisting.
const NS_FILE
Definition Defines.php:70
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
This abstract class implements many basic API functions, and is the base of all API classes.
Definition ApiBase.php:62
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1515
getErrorFormatter()
Definition ApiBase.php:678
requireOnlyOneParameter( $params,... $required)
Die if 0 or more than one of a certain set of parameters is set and not false.
Definition ApiBase.php:946
getResult()
Get the result object.
Definition ApiBase.php:667
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:807
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:528
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition ApiBase.php:1570
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition ApiBase.php:1363
This is the main API class, used for both external and internal processing.
Definition ApiMain.php:64
API Module to move pages.
Definition ApiMove.php:35
needsToken()
Returns the token type this module requires in order to execute.
Definition ApiMove.php:262
isWriteMode()
Indicates whether this module requires write mode.
Definition ApiMove.php:229
__construct(ApiMain $mainModule, $moduleName, MovePageFactory $movePageFactory, RepoGroup $repoGroup, WatchlistManager $watchlistManager, UserOptionsLookup $userOptionsLookup)
Definition ApiMove.php:42
moveSubpages( $fromTitle, $toTitle, $reason, $noredirect, $changeTags=[])
Definition ApiMove.php:198
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition ApiMove.php:63
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition ApiMove.php:225
getHelpUrls()
Return links to more detailed help pages about the module.
Definition ApiMove.php:274
getExamplesMessages()
Returns usage examples for this module.
Definition ApiMove.php:266
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition ApiMove.php:233
A class containing constants representing the names of configuration variables.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:58
Represents a title within MediaWiki.
Definition Title.php:76
Provides access to user options.
Prioritized list of file repositories.
Definition RepoGroup.php:30
Service for formatting and validating API parameters.
trait ApiWatchlistTrait
An ApiWatchlistTrait adds class properties and convenience methods for APIs that allow you to watch a...
Service for page rename actions.
return true
Definition router.php:92