Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F2750952
SpecialGlobalRenameQueue.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
30 KB
Referenced Files
None
Subscribers
None
SpecialGlobalRenameQueue.php
View Options
<?php
/**
* @section LICENSE
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup SpecialPage
*/
namespace
MediaWiki\Extension\CentralAuth\Special
;
use
Exception
;
use
LogEventsList
;
use
MailAddress
;
use
MediaWiki\Extension\CentralAuth\CentralAuthDatabaseManager
;
use
MediaWiki\Extension\CentralAuth\CentralAuthUIService
;
use
MediaWiki\Extension\CentralAuth\GlobalRename\GlobalRenameFactory
;
use
MediaWiki\Extension\CentralAuth\GlobalRename\GlobalRenameRequest
;
use
MediaWiki\Extension\CentralAuth\GlobalRename\GlobalRenameRequestStore
;
use
MediaWiki\Extension\CentralAuth\GlobalRename\GlobalRenameUserLogger
;
use
MediaWiki\Extension\CentralAuth\GlobalRename\LocalRenameJob\LocalRenameUserJob
;
use
MediaWiki\Extension\CentralAuth\User\CentralAuthAntiSpoofManager
;
use
MediaWiki\Extension\CentralAuth\User\CentralAuthUser
;
use
MediaWiki\Extension\TitleBlacklist\TitleBlacklist
;
use
MediaWiki\Extension\TitleBlacklist\TitleBlacklistEntry
;
use
MediaWiki\HTMLForm\HTMLForm
;
use
MediaWiki\JobQueue\JobQueueGroupFactory
;
use
MediaWiki\Logger\LoggerFactory
;
use
MediaWiki\Registration\ExtensionRegistry
;
use
MediaWiki\SpecialPage\SpecialPage
;
use
MediaWiki\Status\Status
;
use
MediaWiki\Title\Title
;
use
MediaWiki\User\User
;
use
MediaWiki\User\UserIdentityLookup
;
use
MediaWiki\User\UserNameUtils
;
use
MediaWiki\WikiMap\WikiMap
;
use
MediaWiki\Xml\Xml
;
use
OOUI\MessageWidget
;
use
Psr\Log\LoggerInterface
;
use
RuntimeException
;
use
UserMailer
;
use
Wikimedia\Rdbms\LBFactory
;
/**
* Process account rename requests made via [[Special:GlobalRenameRequest]].
*
* @author Bryan Davis <bd808@wikimedia.org>
* @copyright © 2014 Bryan Davis and Wikimedia Foundation.
* @ingroup SpecialPage
*/
class
SpecialGlobalRenameQueue
extends
SpecialPage
{
private
UserNameUtils
$userNameUtils
;
private
LBFactory
$lbFactory
;
private
CentralAuthDatabaseManager
$databaseManager
;
private
CentralAuthUIService
$uiService
;
private
GlobalRenameRequestStore
$globalRenameRequestStore
;
private
JobQueueGroupFactory
$jobQueueGroupFactory
;
private
CentralAuthAntiSpoofManager
$caAntiSpoofManager
;
private
GlobalRenameFactory
$globalRenameFactory
;
private
UserIdentityLookup
$userIdentityLookup
;
private
LoggerInterface
$logger
;
public
const
PAGE_OPEN_QUEUE
=
'open'
;
public
const
PAGE_PROCESS_REQUEST
=
'request'
;
public
const
PAGE_CLOSED_QUEUE
=
'closed'
;
private
const
ACTION_CANCEL
=
'cancel'
;
public
const
ACTION_VIEW
=
'view'
;
public
function
__construct
(
UserNameUtils
$userNameUtils
,
LBFactory
$lbFactory
,
CentralAuthDatabaseManager
$databaseManager
,
CentralAuthUIService
$uiService
,
GlobalRenameRequestStore
$globalRenameRequestStore
,
JobQueueGroupFactory
$jobQueueGroupFactory
,
CentralAuthAntiSpoofManager
$caAntiSpoofManager
,
GlobalRenameFactory
$globalRenameFactory
,
UserIdentityLookup
$userIdentityLookup
)
{
parent
::
__construct
(
'GlobalRenameQueue'
,
'centralauth-rename'
);
$this
->
userNameUtils
=
$userNameUtils
;
$this
->
lbFactory
=
$lbFactory
;
$this
->
databaseManager
=
$databaseManager
;
$this
->
uiService
=
$uiService
;
$this
->
globalRenameRequestStore
=
$globalRenameRequestStore
;
$this
->
jobQueueGroupFactory
=
$jobQueueGroupFactory
;
$this
->
caAntiSpoofManager
=
$caAntiSpoofManager
;
$this
->
globalRenameFactory
=
$globalRenameFactory
;
$this
->
userIdentityLookup
=
$userIdentityLookup
;
$this
->
logger
=
LoggerFactory
::
getInstance
(
'CentralAuth'
);
}
public
function
doesWrites
()
{
return
true
;
}
/**
* @param string|null $par Subpage string if one was specified
*/
public
function
execute
(
$par
)
{
$navigation
=
explode
(
'/'
,
$par
);
$action
=
array_shift
(
$navigation
);
$this
->
outputHeader
();
$this
->
addSubtitleLinks
();
switch
(
$action
)
{
case
self
::
PAGE_OPEN_QUEUE
:
$this
->
handleOpenQueue
();
break
;
case
self
::
PAGE_CLOSED_QUEUE
:
$this
->
handleClosedQueue
();
break
;
case
self
::
PAGE_PROCESS_REQUEST
:
$this
->
handleProcessRequest
(
$navigation
);
break
;
default
:
$this
->
doRedirectToOpenQueue
();
break
;
}
}
/**
* @param string $titleMessage Message name for page title
* @param array $titleParams Params for page title
*/
protected
function
commonPreamble
(
$titleMessage
,
$titleParams
=
[]
)
{
$out
=
$this
->
getOutput
();
$this
->
setHeaders
();
$this
->
checkPermissions
();
$out
->
setPageTitleMsg
(
$this
->
msg
(
$titleMessage
,
$titleParams
)
);
}
/**
* @inheritDoc
*/
public
function
getAssociatedNavigationLinks
()
{
return
[
$this
->
getPageTitle
(
self
::
PAGE_OPEN_QUEUE
)->
getPrefixedText
(),
$this
->
getPageTitle
(
self
::
PAGE_CLOSED_QUEUE
)->
getPrefixedText
(),
];
}
/**
* @inheritDoc
*/
public
function
getShortDescription
(
string
$path
=
''
):
string
{
switch
(
$path
)
{
case
$this
->
getPageTitle
(
self
::
PAGE_OPEN_QUEUE
)->
getText
():
return
$this
->
msg
(
'globalrenamequeue-nav-openqueue'
)->
text
();
case
$this
->
getPageTitle
(
self
::
PAGE_CLOSED_QUEUE
)->
getText
():
return
$this
->
msg
(
'globalrenamequeue-nav-closedqueue'
)->
text
();
default
:
return
''
;
}
}
private
function
addSubtitleLinks
()
{
if
(
$this
->
getSkin
()->
supportsMenu
(
'associated-pages'
)
)
{
// Already shown by the skin
return
;
}
$links
=
[];
foreach
(
$this
->
getAssociatedNavigationLinks
()
as
$titleText
)
{
$title
=
Title
::
newFromText
(
$titleText
);
$links
[]
=
$this
->
getLinkRenderer
()->
makeKnownLink
(
$title
,
$this
->
getShortDescription
(
$title
->
getText
()
)
);
}
$this
->
getOutput
()->
addSubtitle
(
$this
->
getLanguage
()->
pipeList
(
$links
)
);
}
/**
* Get an array of fields for use by the HTMLForm shown above the pager.
*
* @return array[]
*/
private
function
getCommonFormFieldsArray
()
{
$lang
=
$this
->
getLanguage
();
return
[
'username'
=>
[
'type'
=>
'text'
,
'name'
=>
'username'
,
'label-message'
=>
'globalrenamequeue-form-username'
,
'size'
=>
30
,
],
'newname'
=>
[
'type'
=>
'text'
,
'name'
=>
'newname'
,
'size'
=>
30
,
'label-message'
=>
'globalrenamequeue-form-newname'
,
],
'limit'
=>
[
'type'
=>
'limitselect'
,
'name'
=>
'limit'
,
'label-message'
=>
'table_pager_limit_label'
,
'options'
=>
[
$lang
->
formatNum
(
25
)
=>
25
,
$lang
->
formatNum
(
50
)
=>
50
,
$lang
->
formatNum
(
75
)
=>
75
,
$lang
->
formatNum
(
100
)
=>
100
,
],
],
'type'
=>
[
'type'
=>
'select'
,
'name'
=>
'type'
,
'label-message'
=>
'globalrenamequeue-form-type'
,
'options-messages'
=>
[
'globalrenamequeue-form-type-all'
=>
'all'
,
'globalrenamequeue-form-type-rename'
=>
GlobalRenameRequest
::
RENAME
,
'globalrenamequeue-form-type-vanish'
=>
GlobalRenameRequest
::
VANISH
,
],
'default'
=>
'all'
,
],
];
}
/**
* Initialize and output the HTMLForm used for filtering.
*
* @param array $formDescriptor
*/
private
function
outputFilterForm
(
array
$formDescriptor
)
{
$htmlForm
=
HTMLForm
::
factory
(
'ooui'
,
$formDescriptor
,
$this
->
getContext
()
);
$htmlForm
->
setMethod
(
'get'
)
->
setWrapperLegendMsg
(
'search'
)
->
prepareForm
()->
displayForm
(
false
);
}
/**
* Handle requests to display the open request queue
*/
protected
function
handleOpenQueue
()
{
$this
->
commonPreamble
(
'globalrenamequeue'
);
$this
->
outputFilterForm
(
$this
->
getCommonFormFieldsArray
()
);
$pager
=
new
RenameQueueTablePager
(
$this
->
getContext
(),
$this
->
getLinkRenderer
(),
$this
->
databaseManager
,
$this
->
userNameUtils
,
self
::
PAGE_OPEN_QUEUE
);
$this
->
getOutput
()->
addParserOutputContent
(
$pager
->
getFullOutput
()
);
}
/**
* Handle requests to display the closed request queue
*/
protected
function
handleClosedQueue
()
{
$this
->
commonPreamble
(
'globalrenamequeue'
);
$formDescriptor
=
array_merge
(
$this
->
getCommonFormFieldsArray
(),
[
'status'
=>
[
'type'
=>
'select'
,
'name'
=>
'status'
,
'label-message'
=>
'globalrenamequeue-form-status'
,
'options-messages'
=>
[
'globalrenamequeue-form-status-all'
=>
'all'
,
'globalrenamequeue-view-approved'
=>
GlobalRenameRequest
::
APPROVED
,
'globalrenamequeue-view-rejected'
=>
GlobalRenameRequest
::
REJECTED
,
],
'default'
=>
'all'
,
]
]
);
$this
->
outputFilterForm
(
$formDescriptor
);
$pager
=
new
RenameQueueTablePager
(
$this
->
getContext
(),
$this
->
getLinkRenderer
(),
$this
->
databaseManager
,
$this
->
userNameUtils
,
self
::
PAGE_CLOSED_QUEUE
);
$this
->
getOutput
()->
addParserOutputContent
(
$pager
->
getFullOutput
()
);
}
/**
* Handle requests related to processing a request.
*
* @param array $pathArgs Extra path arguments
*/
protected
function
handleProcessRequest
(
array
$pathArgs
)
{
if
(
!
$pathArgs
)
{
$this
->
doRedirectToOpenQueue
();
return
;
}
$rqId
=
array_shift
(
$pathArgs
);
if
(
!
is_numeric
(
$rqId
)
)
{
$this
->
showUnkownRequest
();
return
;
}
$req
=
$this
->
globalRenameRequestStore
->
newFromId
(
$rqId
);
if
(
!
$req
->
exists
()
)
{
$this
->
showUnkownRequest
();
return
;
}
$action
=
array_shift
(
$pathArgs
);
if
(
!
$req
->
isPending
()
)
{
$action
=
self
::
ACTION_VIEW
;
}
switch
(
$action
)
{
case
self
::
ACTION_CANCEL
:
$this
->
doRedirectToOpenQueue
();
break
;
case
self
::
ACTION_VIEW
:
$this
->
doViewRequest
(
$req
);
break
;
default
:
$this
->
doShowProcessForm
(
$req
);
break
;
}
}
private
function
showUnkownRequest
()
{
$this
->
commonPreamble
(
'globalrenamequeue-request-unknown-title'
);
$this
->
getOutput
()->
addWikiMsg
(
'globalrenamequeue-request-unknown-body'
);
}
protected
function
doRedirectToOpenQueue
()
{
$this
->
getOutput
()->
redirect
(
$this
->
getPageTitle
(
self
::
PAGE_OPEN_QUEUE
)->
getFullURL
()
);
}
/**
* Display a request.
*
* @param GlobalRenameRequest $req
*/
protected
function
doViewRequest
(
GlobalRenameRequest
$req
)
{
$isVanishRequest
=
$req
->
getType
()
===
GlobalRenameRequest
::
VANISH
;
if
(
$isVanishRequest
)
{
$this
->
commonPreamble
(
'globalrenamequeue-request-vanish-status-title'
,
[
$req
->
getName
()
]
);
}
else
{
$this
->
commonPreamble
(
'globalrenamequeue-request-status-title'
,
[
$req
->
getName
(),
$req
->
getNewName
()
]
);
}
$reason
=
$req
->
getReason
()
?:
''
;
$renamer
=
CentralAuthUser
::
newFromId
(
$req
->
getPerformer
()
);
if
(
$renamer
===
false
)
{
throw
new
RuntimeException
(
"The performer's global user id ({$req->getPerformer()}) "
.
"does not exist in the database"
);
}
$homewiki
=
$renamer
->
getHomeWiki
();
if
(
$renamer
->
isAttached
()
||
$homewiki
===
null
)
{
$renamerLink
=
Title
::
makeTitleSafe
(
NS_USER
,
$renamer
->
getName
()
)->
getFullURL
();
}
else
{
$renamerLink
=
WikiMap
::
getForeignURL
(
$homewiki
,
'User:'
.
$renamer
->
getName
()
);
}
if
(
strpos
(
$reason
,
"
\n
"
)
!==
false
)
{
$reason
=
"<dl><dd>"
.
str_replace
(
"
\n
"
,
"</dd><dd>"
,
$reason
)
.
"</dd></dl>"
;
}
else
{
$reason
=
': '
.
$reason
;
}
$status
=
$req
->
getStatus
();
$causerName
=
$status
===
GlobalRenameRequest
::
APPROVED
?
$req
->
getNewName
()
:
$req
->
getName
();
$causer
=
CentralAuthUser
::
getInstanceByName
(
$causerName
);
$attachedWikis
=
$causer
->
exists
()
&&
$causer
->
isAttached
()
?
implode
(
', '
,
array_keys
(
$causer
->
queryAttachedBasic
()
)
)
:
''
;
// Done as one big message so that admins can create a local
// translation to customize the output as they see fit.
// @TODO: Do that actually in here... this is not how we do interfaces in 2015.
if
(
$isVanishRequest
)
{
$viewMsg
=
$this
->
msg
(
'globalrenamequeue-vanish-view'
,
$req
->
getName
(),
$reason
,
$this
->
msg
(
'globalrenamequeue-view-'
.
$status
)->
text
(),
$this
->
getLanguage
()->
userTimeAndDate
(
$req
->
getRequested
(),
$this
->
getUser
()
),
$this
->
getLanguage
()->
userTimeAndDate
(
$req
->
getCompleted
(),
$this
->
getUser
()
),
$attachedWikis
,
$renamerLink
,
$renamer
->
getName
(),
$req
->
getComments
()
)->
parseAsBlock
();
}
else
{
$viewMsg
=
$this
->
msg
(
'globalrenamequeue-view'
,
$req
->
getName
(),
$req
->
getNewName
(),
$reason
,
$this
->
msg
(
'globalrenamequeue-view-'
.
$status
)->
text
(),
$this
->
getLanguage
()->
userTimeAndDate
(
$req
->
getRequested
(),
$this
->
getUser
()
),
$this
->
getLanguage
()->
userTimeAndDate
(
$req
->
getCompleted
(),
$this
->
getUser
()
),
$renamerLink
,
$renamer
->
getName
(),
$req
->
getComments
()
)->
parseAsBlock
();
}
$this
->
getOutput
()->
addHtml
(
'<div class="plainlinks">'
.
$viewMsg
.
'</div>'
);
}
/**
* Display form for approving/denying request or process form submission.
*
* @param GlobalRenameRequest $req Pending request
*/
protected
function
doShowProcessForm
(
GlobalRenameRequest
$req
)
{
$isVanishRequest
=
$req
->
getType
()
===
GlobalRenameRequest
::
VANISH
;
// Set up message keys according to request type (rename/vanish)
if
(
$isVanishRequest
)
{
$commonPreambleMsg
=
'globalrenamequeue-request-vanish-title'
;
$approveButtonMsg
=
'globalrenamequeue-request-vanish-approve-text'
;
$denyButtonMsg
=
'globalrenamequeue-request-vanish-deny-text'
;
$globalUserInfoMsg
=
'globalrenamequeue-request-vanish-userinfo'
;
$headerMsgKey
=
'globalrenamequeue-request-vanish-header'
;
$reasonMsg
=
'globalrenamequeue-request-vanish-reason'
;
$approveConfirmation
=
'mw-renamequeue-approve-vanish'
;
}
else
{
$commonPreambleMsg
=
'globalrenamequeue-request-title'
;
$approveButtonMsg
=
'globalrenamequeue-request-approve-text'
;
$denyButtonMsg
=
'globalrenamequeue-request-deny-text'
;
$globalUserInfoMsg
=
'globalrenamequeue-request-userinfo-global'
;
$headerMsgKey
=
'globalrenamequeue-request-header'
;
$reasonMsg
=
'globalrenamequeue-request-reason'
;
$approveConfirmation
=
'mw-renamequeue-approve'
;
}
$this
->
commonPreamble
(
$commonPreambleMsg
,
[
$req
->
getName
()
]
);
$htmlForm
=
HTMLForm
::
factory
(
'ooui'
,
[
'rid'
=>
[
'default'
=>
$req
->
getId
(),
'name'
=>
'rid'
,
'type'
=>
'hidden'
,
],
'comments'
=>
[
'default'
=>
$this
->
getRequest
()->
getVal
(
'comments'
),
'id'
=>
'mw-renamequeue-comments'
,
'label-message'
=>
'globalrenamequeue-request-comments-label'
,
'name'
=>
'comments'
,
'type'
=>
'textarea'
,
'rows'
=>
5
,
],
],
$this
->
getContext
(),
'globalrenamequeue'
);
// Show tools to approve only when user is not reviewing own request.
if
(
$req
->
getName
()
!==
$this
->
getUser
()->
getName
()
)
{
$htmlForm
->
addFields
(
[
// The following fields need to have their names stay in
// sync with the expectations of GlobalRenameUser::rename()
'reason'
=>
[
'id'
=>
'mw-renamequeue-reason'
,
'label-message'
=>
'globalrenamequeue-request-reason-label'
,
'name'
=>
'reason'
,
'type'
=>
'text'
,
],
'movepages'
=>
[
'id'
=>
'mw-renamequeue-movepages'
,
'name'
=>
'movepages'
,
'label-message'
=>
'globalrenamequeue-request-movepages'
,
'type'
=>
'check'
,
'default'
=>
1
,
],
'suppressredirects'
=>
[
'id'
=>
'mw-renamequeue-suppressredirects'
,
'name'
=>
'suppressredirects'
,
'label-message'
=>
'globalrenamequeue-request-suppressredirects'
,
'type'
=>
'check'
,
'default'
=>
$isVanishRequest
?
1
:
0
,
'disabled'
=>
$isVanishRequest
?
1
:
0
,
],
]
)
->
addButton
(
[
'name'
=>
'approve'
,
'value'
=>
$this
->
msg
(
$approveButtonMsg
)->
text
(),
'id'
=>
$approveConfirmation
,
'flags'
=>
[
'primary'
,
'progressive'
],
'framed'
=>
true
]
);
}
$htmlForm
->
suppressDefaultSubmit
()
->
addButton
(
[
'name'
=>
'deny'
,
'value'
=>
$this
->
msg
(
$denyButtonMsg
)->
text
(),
'id'
=>
'mw-renamequeue-deny'
,
'flags'
=>
[
'destructive'
],
'framed'
=>
true
]
)
->
addButton
(
[
'name'
=>
'cancel'
,
'value'
=>
$this
->
msg
(
'globalrenamequeue-request-cancel-text'
)->
text
(),
'id'
=>
'mw-renamequeue-cancel'
,
]
)
->
setId
(
'mw-globalrenamequeue-request'
);
if
(
$req
->
userIsGlobal
()
)
{
$globalUser
=
CentralAuthUser
::
getInstanceByName
(
$req
->
getName
()
);
$homeWiki
=
$globalUser
->
getHomeWiki
();
$infoMsgKey
=
$globalUserInfoMsg
;
}
else
{
$homeWiki
=
$req
->
getWiki
();
$infoMsgKey
=
'globalrenamequeue-request-userinfo-local'
;
}
if
(
$homeWiki
===
null
)
{
$homeLink
=
Title
::
makeTitleSafe
(
NS_USER
,
$req
->
getName
()
)->
getFullURL
();
}
else
{
$homeLink
=
WikiMap
::
getForeignURL
(
$homeWiki
,
'User:'
.
$req
->
getName
()
);
}
$headerMsg
=
$this
->
msg
(
$headerMsgKey
,
$homeLink
,
$req
->
getName
(),
$req
->
getNewName
()
);
$htmlForm
->
addHeaderHtml
(
'<span class="plainlinks">'
.
$headerMsg
->
parseAsBlock
()
.
'</span>'
);
$homeWikiWiki
=
$homeWiki
?
WikiMap
::
getWiki
(
$homeWiki
)
:
null
;
$infoMsgArgs
=
[
$infoMsgKey
,
$req
->
getName
(),
// homeWikiWiki shouldn't ever be null except in
// a development/testing environment.
(
$homeWikiWiki
?
$homeWikiWiki
->
getDisplayName
()
:
$homeWiki
),
];
// Rename requests need the new username into the info message
if
(
!
$isVanishRequest
)
{
$infoMsgArgs
[]
=
$req
->
getNewName
();
}
$infoMsg
=
$this
->
msg
(
...
$infoMsgArgs
);
if
(
isset
(
$globalUser
)
)
{
$infoMsg
->
numParams
(
$globalUser
->
getGlobalEditCount
()
);
$infoMsg
->
params
(
$this
->
msg
(
$globalUser
->
isBlocked
()
?
'globalrenamequeue-request-vanish-user-blocked'
:
'globalrenamequeue-request-vanish-user-not-blocked'
)
);
}
$htmlForm
->
addHeaderHtml
(
$infoMsg
->
parseAsBlock
()
);
// Handle AntiSpoof integration
$spoofUser
=
$this
->
caAntiSpoofManager
->
getSpoofUser
(
$req
->
getNewName
()
);
$conflicts
=
$this
->
uiService
->
processAntiSpoofConflicts
(
$this
->
getContext
(),
$req
->
getName
(),
$spoofUser
->
getConflicts
()
);
$renamedUser
=
$this
->
caAntiSpoofManager
->
getOldRenamedUserName
(
$req
->
getNewName
()
);
if
(
$renamedUser
!==
null
)
{
$conflicts
[]
=
$renamedUser
;
}
if
(
$conflicts
)
{
$htmlForm
->
addHeaderHtml
(
$this
->
msg
(
'globalrenamequeue-request-antispoof-conflicts'
,
$this
->
getLanguage
()->
commaList
(
$conflicts
)
)->
numParams
(
count
(
$conflicts
)
)->
parseAsBlock
()
);
}
// Show a message if the new username matches the title blacklist.
if
(
ExtensionRegistry
::
getInstance
()->
isLoaded
(
'TitleBlacklist'
)
)
{
$titleBlacklist
=
TitleBlacklist
::
singleton
()->
isBlacklisted
(
Title
::
makeTitleSafe
(
NS_USER
,
$req
->
getNewName
()
),
'new-account'
);
if
(
$titleBlacklist
instanceof
TitleBlacklistEntry
)
{
$htmlForm
->
addHeaderHtml
(
$this
->
msg
(
'globalrenamequeue-request-titleblacklist'
)
->
params
(
wfEscapeWikiText
(
$titleBlacklist
->
getRegex
()
)
)->
parseAsBlock
()
);
}
}
// Show a log entry of previous renames under the requesting user's username
$caTitle
=
SpecialPage
::
getTitleFor
(
'CentralAuth'
,
$req
->
getName
()
);
$extract
=
''
;
$extractCount
=
LogEventsList
::
showLogExtract
(
$extract
,
'gblrename'
,
$caTitle
,
''
,
[
'showIfEmpty'
=>
false
,
]
);
if
(
$extractCount
)
{
$htmlForm
->
addHeaderHtml
(
Xml
::
fieldset
(
$this
->
msg
(
'globalrenamequeue-request-previous-renames'
)
->
numParams
(
$extractCount
)
->
text
(),
$extract
)
);
}
$reason
=
$req
->
getReason
()
?:
''
;
$htmlForm
->
addHeaderHtml
(
$this
->
msg
(
$reasonMsg
,
"<dl><dd>"
.
str_replace
(
"
\n
"
,
"</dd><dd>"
,
$reason
)
.
"</dd></dl>"
)->
parseAsBlock
()
);
// Show warning when reviewing own request
if
(
$req
->
getName
()
===
$this
->
getUser
()->
getName
()
)
{
$message
=
new
MessageWidget
(
[
'label'
=>
$this
->
msg
(
'globalrenamerequest-self-warning'
)->
text
(),
'type'
=>
'warning'
,
'inline'
=>
true
]
);
$htmlForm
->
addHeaderHtml
(
$message
->
toString
()
);
}
$htmlForm
->
setSubmitCallback
(
[
$this
,
'onProcessSubmit'
]
);
$out
=
$this
->
getOutput
();
$out
->
addModuleStyles
(
'ext.centralauth.globalrenamequeue.styles'
);
$out
->
addModules
(
'ext.centralauth.globalrenamequeue'
);
$status
=
$htmlForm
->
show
();
if
(
$status
instanceof
Status
&&
$status
->
isOK
()
)
{
$this
->
getOutput
()->
redirect
(
$this
->
getPageTitle
(
self
::
PAGE_PROCESS_REQUEST
.
"/{$req->getId()}/{$status->value}"
)->
getFullURL
()
);
}
}
/**
* @param array $data
* @return Status
*/
public
function
onProcessSubmit
(
array
$data
)
{
$request
=
$this
->
getContext
()->
getRequest
();
$status
=
new
Status
;
if
(
$request
->
getCheck
(
'approve'
)
)
{
$status
=
$this
->
doResolveRequest
(
true
,
$data
);
}
elseif
(
$request
->
getCheck
(
'deny'
)
)
{
$status
=
$this
->
doResolveRequest
(
false
,
$data
);
}
else
{
$status
->
setResult
(
true
,
'cancel'
);
}
return
$status
;
}
/**
* @param bool $approved
* @param array $data
*
* @return Status
*/
protected
function
doResolveRequest
(
$approved
,
$data
)
{
$request
=
$this
->
globalRenameRequestStore
->
newFromId
(
$data
[
'rid'
]
);
$oldUser
=
User
::
newFromName
(
$request
->
getName
()
);
$newUser
=
User
::
newFromName
(
$request
->
getNewName
(),
'creatable'
);
$status
=
new
Status
;
$session
=
$this
->
getContext
()->
exportSession
();
if
(
$approved
)
{
// Disallow self-renaming
if
(
$request
->
getName
()
===
$this
->
getUser
()->
getName
()
)
{
return
Status
::
newFatal
(
'globalrenamerequest-self-error'
);
}
if
(
$request
->
userIsGlobal
()
)
{
$data
[
'type'
]
=
$request
->
getType
();
$globalRenameUser
=
$this
->
globalRenameFactory
->
newGlobalRenameUser
(
$this
->
getUser
(),
CentralAuthUser
::
getInstanceByName
(
$request
->
getName
()
),
$request
->
getNewName
()
)
->
withSession
(
$session
);
// Credit the vanish performer with account locking logs for
// vanish requests. Renamers cannot normally perform locks and
// thus should not be associated with them.
if
(
$request
->
getType
()
===
GlobalRenameRequest
::
VANISH
)
{
$vanishPerformerName
=
$this
->
getConfig
()->
get
(
'CentralAuthAutomaticVanishPerformer'
);
if
(
isset
(
$vanishPerformerName
)
)
{
$localVanishPerformer
=
$this
->
userIdentityLookup
->
getUserIdentityByName
(
$vanishPerformerName
);
if
(
isset
(
$localVanishPerformer
)
)
{
$globalRenameUser
=
$globalRenameUser
->
withLockPerformingUser
(
$localVanishPerformer
);
}
}
}
// Trigger a global rename job
$status
=
$globalRenameUser
->
rename
(
$data
);
}
else
{
// If the user is local-only:
// * rename the local user using LocalRenameUserJob
// * create a global user attached only to the local wiki
$job
=
new
LocalRenameUserJob
(
Title
::
newFromText
(
'Global rename job'
),
[
'from'
=>
$oldUser
->
getName
(),
'to'
=>
$newUser
->
getName
(),
'renamer'
=>
$this
->
getUser
()->
getName
(),
'movepages'
=>
true
,
'suppressredirects'
=>
true
,
'promotetoglobal'
=>
true
,
'reason'
=>
$data
[
'reason'
],
'session'
=>
$session
,
'type'
=>
$request
->
getType
(),
]
);
$this
->
jobQueueGroupFactory
->
makeJobQueueGroup
(
$request
->
getWiki
()
)->
push
(
$job
);
// Now log it
$this
->
logPromotionRename
(
$oldUser
->
getName
(),
$request
->
getWiki
(),
$newUser
->
getName
(),
$data
[
'reason'
]
);
$status
=
Status
::
newGood
();
}
}
if
(
$status
->
isGood
()
)
{
$request
->
setStatus
(
$approved
?
GlobalRenameRequest
::
APPROVED
:
GlobalRenameRequest
::
REJECTED
);
$request
->
setCompleted
(
wfTimestampNow
()
);
$request
->
setPerformer
(
CentralAuthUser
::
getInstance
(
$this
->
getUser
()
)->
getId
()
);
$request
->
setComments
(
$data
[
'comments'
]
);
if
(
$this
->
globalRenameRequestStore
->
save
(
$request
)
)
{
if
(
$request
->
getType
()
===
GlobalRenameRequest
::
VANISH
)
{
$emailSubjectApprovedMsg
=
'globalrenamequeue-vanish-email-subject-approved'
;
$emailBodyApprovedMsg
=
'globalrenamequeue-vanish-email-body-approved'
;
$emailBodyApprovedWithNoteMsg
=
'globalrenamequeue-vanish-email-body-approved-with-note'
;
$emailSubjectRejectedMsg
=
'globalrenamequeue-vanish-email-subject-rejected'
;
$emailBodyRejectedMsg
=
'globalrenamequeue-vanish-email-body-rejected'
;
$emailBodyMsgArgs
=
[
$oldUser
->
getName
(),
$request
->
getComments
()
];
}
else
{
$emailSubjectApprovedMsg
=
'globalrenamequeue-email-subject-approved'
;
$emailBodyApprovedMsg
=
'globalrenamequeue-email-body-approved'
;
$emailBodyApprovedWithNoteMsg
=
'globalrenamequeue-email-body-approved-with-note'
;
$emailSubjectRejectedMsg
=
'globalrenamequeue-email-subject-rejected'
;
$emailBodyRejectedMsg
=
'globalrenamequeue-email-body-rejected'
;
$emailBodyMsgArgs
=
[
$oldUser
->
getName
(),
$newUser
->
getName
(),
$request
->
getComments
(),
];
}
// Send email to the user about the change in status.
if
(
$approved
)
{
$subject
=
$this
->
msg
(
$emailSubjectApprovedMsg
)->
inContentLanguage
()->
text
();
if
(
$request
->
getComments
()
===
''
)
{
$msgKey
=
$emailBodyApprovedMsg
;
}
else
{
$msgKey
=
$emailBodyApprovedWithNoteMsg
;
}
$body
=
$this
->
msg
(
$msgKey
,
$emailBodyMsgArgs
)->
inContentLanguage
()->
text
();
}
else
{
$recipientConfig
=
$this
->
getConfig
()->
get
(
'CentralAuthRejectVanishUserNotification'
);
if
(
$recipientConfig
)
{
$status
=
$this
->
sendEmailForRejectionOfVanishRequest
(
$request
,
$recipientConfig
);
}
$subject
=
$this
->
msg
(
$emailSubjectRejectedMsg
)->
inContentLanguage
()->
text
();
$body
=
$this
->
msg
(
$emailBodyRejectedMsg
,
$emailBodyMsgArgs
)->
inContentLanguage
()->
text
();
}
if
(
$request
->
userIsGlobal
()
||
$request
->
getWiki
()
===
WikiMap
::
getCurrentWikiId
()
)
{
$notifyEmail
=
MailAddress
::
newFromUser
(
$oldUser
);
}
else
{
$notifyEmail
=
$this
->
getRemoteUserMailAddress
(
$request
->
getWiki
(),
$request
->
getName
()
);
}
if
(
$notifyEmail
!==
null
&&
$notifyEmail
->
address
)
{
$type
=
$approved
?
'approval'
:
'rejection'
;
$this
->
logger
->
info
(
"Send $type email to User:{oldName}"
,
[
'oldName'
=>
$oldUser
->
getName
(),
'component'
=>
'GlobalRename'
,
]
);
$this
->
sendNotificationEmail
(
$notifyEmail
,
$subject
,
$body
);
}
}
else
{
$status
->
fatal
(
'globalrenamequeue-request-savefailed'
);
}
}
return
$status
;
}
/**
* Log a promotion to global rename in the global rename log
*
* @param string $oldName
* @param string $wiki
* @param string $newName
* @param string $reason
*/
protected
function
logPromotionRename
(
$oldName
,
$wiki
,
$newName
,
$reason
)
{
$logger
=
new
GlobalRenameUserLogger
(
$this
->
getUser
()
);
$logger
->
logPromotion
(
$oldName
,
$wiki
,
$newName
,
$reason
);
}
/**
* Get a MailAddress for a user on a remote wiki
*
* @param string $wiki
* @param string $username
* @return MailAddress|null
*/
protected
function
getRemoteUserMailAddress
(
$wiki
,
$username
)
{
$lb
=
$this
->
lbFactory
->
getMainLB
(
$wiki
);
$remoteDB
=
$lb
->
getConnection
(
DB_REPLICA
,
[],
$wiki
);
$row
=
$remoteDB
->
newSelectQueryBuilder
()
->
select
(
[
'user_email'
,
'user_name'
,
'user_real_name'
]
)
->
from
(
'user'
)
->
where
(
[
'user_name'
=>
$this
->
userNameUtils
->
getCanonical
(
$username
),
]
)
->
caller
(
__METHOD__
)
->
fetchRow
();
if
(
$row
===
false
)
{
$address
=
null
;
}
else
{
$address
=
new
MailAddress
(
$row
->
user_email
,
$row
->
user_name
,
$row
->
user_real_name
);
}
return
$address
;
}
/**
* Send an email notifying the user of the result of their request.
*
* @param MailAddress $to
* @param string $subject
* @param string $body
* @return Status
*/
protected
function
sendNotificationEmail
(
MailAddress
$to
,
$subject
,
$body
)
{
$from
=
new
MailAddress
(
$this
->
getConfig
()->
get
(
'PasswordSender'
),
$this
->
msg
(
'emailsender'
)->
inContentLanguage
()->
text
()
);
return
UserMailer
::
send
(
$to
,
$from
,
$subject
,
$body
);
}
/**
* Send an email on account vanishing rejection to the provided recipient.
*
* @param GlobalRenameRequest $request
* @param string $recipientUserName
* @return Status
*/
protected
function
sendEmailForRejectionOfVanishRequest
(
GlobalRenameRequest
$request
,
$recipientUserName
)
{
// Email to legal is only sent when it's a vanish request
if
(
$request
->
getType
()
!==
GlobalRenameRequest
::
VANISH
)
{
return
Status
::
newGood
();
}
if
(
$request
->
userIsGlobal
()
)
{
$globalUser
=
CentralAuthUser
::
getInstanceByName
(
$request
->
getName
()
);
$homeWiki
=
$globalUser
->
getHomeWiki
();
$globalEditCount
=
$globalUser
->
getGlobalEditCount
();
$isBlocked
=
$globalUser
->
isBlocked
()
?
'globalrenamequeue-request-vanish-user-blocked'
:
'globalrenamequeue-request-vanish-user-not-blocked'
;
}
else
{
$homeWiki
=
$request
->
getWiki
();
$globalEditCount
=
''
;
$isBlocked
=
'globalrenamequeue-request-vanish-user-not-blocked'
;
}
// This should never be null except in dev/testing environment.
$homeWikiWiki
=
$homeWiki
?
WikiMap
::
getWiki
(
$homeWiki
)
:
null
;
$rejector
=
CentralAuthUser
::
newFromId
(
$request
->
getPerformer
()
);
$rejectorName
=
$rejector
?
$rejector
->
getName
()
:
$request
->
getPerformer
();
$subject
=
$this
->
msg
(
'globalvanishrequest-rejected-subject-notification'
,
$request
->
getName
(),
)->
inContentLanguage
()->
text
();
$isBlockedMsg
=
$this
->
msg
(
$isBlocked
)->
inContentLanguage
()->
text
();
$bodyMessage
=
$this
->
msg
(
'globalvanishrequest-rejected-body-notification'
,
$request
->
getName
(),
(
$homeWikiWiki
?
$homeWikiWiki
->
getDisplayName
()
:
$homeWiki
),
$globalEditCount
,
$isBlockedMsg
,
$request
->
getReason
(),
$rejectorName
,
$request
->
getComments
(),
$this
->
getLanguage
()->
userTimeAndDate
(
$request
->
getRequested
(),
$this
->
getUser
()
),
$this
->
getLanguage
()->
userTimeAndDate
(
$request
->
getCompleted
(),
$this
->
getUser
()
),
)->
inContentLanguage
()->
text
();
try
{
$contactRecipientUser
=
User
::
newFromName
(
$recipientUserName
);
$contactRecipientAddress
=
MailAddress
::
newFromUser
(
$contactRecipientUser
);
$contactSenderAddress
=
new
MailAddress
(
$this
->
getConfig
()->
get
(
'PasswordSender'
),
$this
->
msg
(
'emailsender'
)->
inContentLanguage
()->
text
()
);
$userMailerStatus
=
UserMailer
::
send
(
$contactRecipientAddress
,
$contactSenderAddress
,
$subject
,
$bodyMessage
,
);
if
(
$userMailerStatus
->
isGood
()
)
{
return
Status
::
newGood
();
}
else
{
return
Status
::
newFatal
(
'globalvanishrequest-rejected-notification-error'
);
}
}
catch
(
Exception
$e
)
{
return
Status
::
newFatal
(
'globalvanishrequest-rejected-notification-error'
);
}
}
/** @inheritDoc */
protected
function
getGroupName
()
{
return
'users'
;
}
/** @inheritDoc */
public
function
getSubpagesForPrefixSearch
()
{
return
[
self
::
PAGE_OPEN_QUEUE
,
self
::
PAGE_PROCESS_REQUEST
,
self
::
PAGE_CLOSED_QUEUE
];
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Fri, Jul 3, 17:32 (14 h, 50 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
dd/44/ee79dfac66f30b4234f48b9b52c7
Default Alt Text
SpecialGlobalRenameQueue.php (30 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment