43 private $forceGlobalDetach =
false;
45 private $movePages =
true;
47 private $suppressRedirect =
false;
49 private $derived =
false;
51 private readonly LoggerInterface $logger;
84 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
85 $this->logger = LoggerFactory::getInstance(
'RenameUser' );
92 ] as $possibleOption ) {
93 if ( isset( $renameOptions[ $possibleOption ] ) ) {
94 $this->$possibleOption = $renameOptions[ $possibleOption ];
98 $this->performer = $performer;
99 $this->target = $target;
100 $this->oldName = $oldName;
101 $this->newName = $newName;
102 $this->reason = $reason;
112 private function check():
Status {
116 $expectedName = $this->oldName;
117 if ( $this->derived && $this->userFactory->isUserTableShared() ) {
118 $expectedName = $this->newName;
120 if ( $this->target->getName() !== $expectedName ) {
121 return Status::newFatal(
'renameuser-error-unexpected-name' );
125 $newRigor = $this->derived ? UserFactory::RIGOR_NONE : UserFactory::RIGOR_CREATABLE;
126 $oldUser = $this->userFactory->newFromName( $this->oldName, UserFactory::RIGOR_NONE );
127 $newUser = $this->userFactory->newFromName( $this->newName, $newRigor );
129 return Status::newFatal(
'renameusererrorinvalid', $this->oldName );
132 return Status::newFatal(
'renameusererrorinvalid', $this->newName );
134 $currentUser = $this->derived ? $newUser : $oldUser;
135 if ( !$currentUser->isRegistered() ) {
136 return Status::newFatal(
'renameusererrordoesnotexist', $currentUser->getName() );
138 if ( !$this->derived && $newUser->isRegistered() ) {
139 return Status::newFatal(
'renameusererrorexists', $this->newName );
143 if ( $this->userNameUtils->isTemp( $this->oldName ) ) {
144 return Status::newFatal(
'renameuser-error-temp-user', $this->oldName );
147 $this->userNameUtils->isTemp( $this->newName ) ||
148 $this->userNameUtils->isTempReserved( $this->newName )
150 return Status::newFatal(
'renameuser-error-temp-user-reserved', $this->newName );
154 $centralIdLookup = $this->centralIdLookupFactory->getNonLocalLookup();
155 $userCentralAttached = $centralIdLookup && $centralIdLookup->isAttached( $this->target );
156 if ( !$this->forceGlobalDetach && $userCentralAttached ) {
157 return Status::newFatal(
'renameuser-error-global-detaching' );
160 return Status::newGood();
168 $status = $this->check();
169 if ( !$status->isOK() ) {
173 $user = $this->target;
174 $performer = $this->performer;
175 $oldName = $this->oldName;
176 $newName = $this->newName;
179 'reason' => $this->reason,
180 'derived' => $this->derived,
191 $status->merge( $rename->renameUser() );
192 if ( !$status->isOK() ) {
197 if ( $performer->getId() === $user->getId() ) {
198 $performer->setName( $newName );
199 $this->performer->setName( $newName );
203 $status->merge( $this->moveUserPages() );
213 if ( $this->movePages && $this->permissionManager->userHasRight( $this->performer,
'move' ) ) {
214 $suppressRedirect = $this->suppressRedirect
215 && $this->permissionManager->userHasRight( $this->performer,
'suppressredirect' );
216 $oldTitle = $this->titleFactory->makeTitle(
NS_USER, $this->oldName );
217 $newTitle = $this->titleFactory->makeTitle(
NS_USER, $this->newName );
219 $status = $this->movePagesAndSubPages( $this->performer, $oldTitle, $newTitle, $suppressRedirect );
220 if ( !$status->isOK() ) {
224 $oldTalkTitle = $oldTitle->getTalkPageIfDefined();
225 $newTalkTitle = $newTitle->getTalkPageIfDefined();
226 if ( $oldTalkTitle && $newTalkTitle ) {
227 $status = $this->movePagesAndSubPages(
233 if ( !$status->isOK() ) {
238 return Status::newGood();
241 private function movePagesAndSubPages(
242 User $performer, Title $oldTitle, Title $newTitle,
bool $suppressRedirect
244 $status = Status::newGood();
246 $movePage = $this->movePageFactory->newMovePage(
250 $movePage->setMaximumMovedPages( -1 );
251 $logMessage = RequestContext::getMain()->msg(
252 'renameuser-move-log',
253 $oldTitle->getText(),
255 )->inContentLanguage()->text();
257 if ( $oldTitle->exists() ) {
258 $status->merge( $movePage->moveIfAllowed( $performer, $logMessage, !$suppressRedirect ) );
259 if ( !$status->isGood() ) {
264 $batchStatus = $movePage->moveSubpagesIfAllowed( $performer, $logMessage, !$suppressRedirect );
265 foreach ( $batchStatus->getValue() as $titleText => $moveStatus ) {
266 $status->merge( $moveStatus );
282 if ( $this->derived ) {
283 throw new LogicException(
"Can't rename globally with a command created with newDerivedRenameUser()" );
285 $status = $this->renameLocal();
286 if ( !$status->isGood() ) {
291 if ( $this->userFactory->isUserTableShared() ) {
292 foreach ( $this->options->get( MainConfigNames::LocalDatabases ) as $database ) {
293 if ( $database == WikiMap::getCurrentWikiDbDomain()->getId() ) {
296 $status->merge( $this->enqueueRemoteRename( $database ) );
311 private function enqueueRemoteRename(
string $database ): Status {
313 'oldname' => $this->oldName,
314 'newname' => $this->newName,
315 'uid' => $this->target->getId(),
316 'performer' => $this->performer->getId(),
317 'reason' => $this->reason,
318 'movePages' => $this->movePages,
319 'suppressRedirect' => $this->suppressRedirect,
321 $oldTitle = $this->titleFactory->makeTitle(
NS_USER, $this->oldName );
322 $this->logger->info(
"Enqueuing a rename job for domain {$database}" );
323 $job =
new JobSpecification(
'renameUserDerived', $jobParams, [], $oldTitle );
324 $this->jobQueueGroupFactory->makeJobQueueGroup( $database )->push(
$job );
325 return Status::newGood();
338 if ( !$this->derived && $this->userFactory->isUserTableShared() ) {
339 return $this->renameGlobal();
341 return $this->renameLocal();
355 if ( !$this->permissionManager->userHasRight( $this->performer,
'renameuser' ) ) {
356 return Status::newFatal(
'renameuser-error-local-rights' );
360 $centralIdLookup = $this->centralIdLookupFactory->getNonLocalLookup();
361 $userCentralAttached = $centralIdLookup && $centralIdLookup->isAttached( $this->target );
362 if ( ( $this->userFactory->isUserTableShared() || $userCentralAttached )
363 && !$this->permissionManager->userHasRight( $this->performer,
'renameuser-global' ) ) {
364 return Status::newFatal(
'renameuser-error-global-rights' );
367 return $this->renameUnsafe();