$this->fakeTemplate = $fakeTemplate; // FIXME there should be a saner way to pass this to the hook
// this will call onAuthChangeFormFields()
$formDescriptor = static::fieldInfoToFormDescriptor( $requests, $fieldInfo, $this->authAction );
- $this->postProcessFormDescriptor( $formDescriptor );
+ $this->postProcessFormDescriptor( $formDescriptor, $requests );
$context = $this->getContext();
if ( $context->getRequest() !== $this->getRequest() ) {
$form->setId( 'userlogin2' );
}
- // add pre/post text
- // header used by ConfirmEdit, CondfirmAccount, Persona, WikimediaIncubator, SemanticSignup
- // should be above the error message but HTMLForm doesn't support that
- $form->addHeaderText( $fakeTemplate->get( 'header' ) );
-
- // FIXME the old form used this for error/warning messages which does not play well with
- // HTMLForm (maybe it could with a subclass?); for now only display it for signups
- // (where the JS username validation needs it) and alway empty
- if ( $this->isSignup() ) {
- // used by the mediawiki.special.userlogin.signup.js module
- $statusAreaAttribs = [ 'id' => 'mw-createacct-status-area' ];
- // $statusAreaAttribs += $msg ? [ 'class' => "{$msgType}box" ] : [ 'style' => 'display: none;' ];
- $form->addHeaderText( Html::element( 'div', $statusAreaAttribs ) );
- }
-
- // header used by MobileFrontend
- $form->addHeaderText( $fakeTemplate->get( 'formheader' ) );
-
- // blank signup footer for site customization
- if ( $this->isSignup() && $this->showExtraInformation() ) {
- // Use signupend-https for HTTPS requests if it's not blank, signupend otherwise
- $signupendMsg = $this->msg( 'signupend' );
- $signupendHttpsMsg = $this->msg( 'signupend-https' );
- if ( !$signupendMsg->isDisabled() ) {
- $signupendText = ( $usingHTTPS && !$signupendHttpsMsg->isBlank() )
- ? $signupendHttpsMsg ->parse() : $signupendMsg->parse();
- $form->addPostText( Html::rawElement( 'div', [ 'id' => 'signupend' ], $signupendText ) );
- }
- }
-
// warning header for non-standard workflows (e.g. security reauthentication)
if ( !$this->isSignup() && $this->getUser()->isLoggedIn() ) {
$reauthMessage = $this->securityLevel ? 'userlogin-reauth' : 'userlogin-loggedin';
$this->msg( $reauthMessage )->params( $this->getUser()->getName() )->parse() ) );
}
- if ( !$this->isSignup() && $this->showExtraInformation() ) {
- $passwordReset = new PasswordReset( $this->getConfig(), AuthManager::singleton() );
- if ( $passwordReset->isAllowed( $this->getUser() ) ) {
- $form->addFooterText( Html::rawElement(
- 'div',
- [ 'class' => 'mw-ui-vform-field mw-form-related-link-container' ],
- Linker::link(
- SpecialPage::getTitleFor( 'PasswordReset' ),
- $this->msg( 'userlogin-resetpassword-link' )->escaped()
- )
- ) );
- }
-
- // Don't show a "create account" link if the user can't.
- if ( $this->showCreateAccountLink() ) {
- // link to the other action
- $linkTitle = $this->getTitleFor( $this->isSignup() ? 'Userlogin' :'CreateAccount' );
- $linkq = $this->getReturnToQueryStringFragment();
- // Pass any language selection on to the mode switch link
- if ( $wgLoginLanguageSelector && $this->mLanguage ) {
- $linkq .= '&uselang=' . $this->mLanguage;
- }
-
- $loggedIn = $this->getUser()->isLoggedIn();
- $createOrLoginHtml = Html::rawElement( 'div',
- [ 'id' => 'mw-createaccount' . ( !$loggedIn ? '-cta' : '' ),
- 'class' => ( $loggedIn ? 'mw-form-related-link-container' : 'mw-ui-vform-field' ) ],
- ( $loggedIn ? '' : $this->msg( 'userlogin-noaccount' )->escaped() )
- . Html::element( 'a',
- [
- 'id' => 'mw-createaccount-join' . ( $loggedIn ? '-loggedin' : '' ),
- 'href' => $linkTitle->getLocalURL( $linkq ),
- 'class' => ( $loggedIn ? '' : 'mw-ui-button' ),
- 'tabindex' => 100,
- ],
- $this->msg(
- ( $this->getUser()->isLoggedIn() ?
- 'userlogin-createanother' :
- 'userlogin-joinproject'
- ) )->escaped()
- )
- );
- $form->addFooterText( $createOrLoginHtml );
- }
- }
-
$form->suppressDefaultSubmit();
$this->authForm = $form;
array $requests, array $fieldInfo, array &$formDescriptor, $action
) {
$coreFieldDescriptors = $this->getFieldDefinitions( $this->fakeTemplate );
- $specialFields = array_merge( [ 'extraInput', 'linkcontainer', 'entryError' ],
+ $specialFields = array_merge( [ 'extraInput' ],
array_keys( $this->fakeTemplate->getExtraInputDefinitions() ) );
// keep the ordering from getCoreFieldDescriptors() where there is no explicit weight
$formDescriptor[$fieldName] : [];
// remove everything that is not in the fieldinfo, is not marked as a supplemental field
- // to something in the fieldinfo, and is not a generic or B/C field or a submit button
+ // to something in the fieldinfo, is not B/C for the pre-AuthManager templates,
+ // and is not an info field or a submit button
if (
!isset( $fieldInfo[$fieldName] )
&& (
!isset( $coreField['baseField'] )
|| !isset( $fieldInfo[$coreField['baseField']] )
- ) && !in_array( $fieldName, $specialFields, true )
- && ( !isset( $coreField['type'] ) || $coreField['type'] !== 'submit' )
+ )
+ && !in_array( $fieldName, $specialFields, true )
+ && (
+ !isset( $coreField['type'] )
+ || !in_array( $coreField['type'], [ 'submit', 'info' ], true )
+ )
) {
$coreFieldDescriptors[$fieldName] = null;
continue;
* @return array
*/
protected function getFieldDefinitions( $template ) {
- global $wgEmailConfirmToEdit;
+ global $wgEmailConfirmToEdit, $wgLoginLanguageSelector;
$isLoggedIn = $this->getUser()->isLoggedIn();
$continuePart = $this->isContinued() ? 'continue-' : '';
$anotherPart = $isLoggedIn ? 'another-' : '';
- $expiration = $this->getRequest()->getSession()->getProvider()
- ->getRememberUserDuration();
+ $expiration = $this->getRequest()->getSession()->getProvider()->getRememberUserDuration();
$expirationDays = ceil( $expiration / ( 3600 * 24 ) );
$secureLoginLink = '';
if ( $this->mSecureLoginUrl ) {
if ( $this->isSignup() ) {
$fieldDefinitions = [
+ 'statusarea' => [
+ // used by the mediawiki.special.userlogin.signup.js module for error display
+ // FIXME merge this with HTMLForm's normal status (error) area
+ 'type' => 'info',
+ 'raw' => true,
+ 'default' => Html::element( 'div', [ 'id' => 'mw-createacct-status-area' ] ),
+ 'weight' => -105,
+ ],
'username' => [
'label-message' => 'userlogin-yourname',
// FIXME help-message does not match old formatting
],
];
}
+
$fieldDefinitions['username'] += [
'type' => 'text',
'name' => 'wpName',
// 'required' => true,
];
+ if ( $template->get( 'header' ) || $template->get( 'formheader' ) ) {
+ // B/C for old extensions that haven't been converted to AuthManager (or have been
+ // but somebody is using the old version) and still use templates via the
+ // UserCreateForm/UserLoginForm hook.
+ // 'header' used by ConfirmEdit, CondfirmAccount, Persona, WikimediaIncubator, SemanticSignup
+ // 'formheader' used by MobileFrontend
+ $fieldDefinitions['header'] = [
+ 'type' => 'info',
+ 'raw' => true,
+ 'default' => $template->get( 'header' ) ?: $template->get( 'formheader' ),
+ 'weight' => - 110,
+ ];
+ }
if ( $this->mEntryError ) {
$fieldDefinitions['entryError'] = [
'type' => 'info',
'weight' => -100,
];
}
-
if ( !$this->showExtraInformation() ) {
- unset( $fieldDefinitions['linkcontainer'] );
+ unset( $fieldDefinitions['linkcontainer'], $fieldDefinitions['signupend'] );
+ }
+ if ( $this->isSignup() && $this->showExtraInformation() ) {
+ // blank signup footer for site customization
+ // uses signupend-https for HTTPS requests if it's not blank, signupend otherwise
+ $signupendMsg = $this->msg( 'signupend' );
+ $signupendHttpsMsg = $this->msg( 'signupend-https' );
+ if ( !$signupendMsg->isDisabled() ) {
+ $usingHTTPS = $this->getRequest()->getProtocol() === 'https';
+ $signupendText = ( $usingHTTPS && !$signupendHttpsMsg->isBlank() )
+ ? $signupendHttpsMsg ->parse() : $signupendMsg->parse();
+ $fieldDefinitions['signupend'] = [
+ 'type' => 'info',
+ 'raw' => true,
+ 'default' => Html::rawElement( 'div', [ 'id' => 'signupend' ], $signupendText ),
+ 'weight' => 225,
+ ];
+ }
+ }
+ if ( !$this->isSignup() && $this->showExtraInformation() ) {
+ $passwordReset = new PasswordReset( $this->getConfig(), AuthManager::singleton() );
+ if ( $passwordReset->isAllowed( $this->getUser() ) ) {
+ $fieldDefinitions['passwordReset'] = [
+ 'type' => 'info',
+ 'raw' => true,
+ 'cssclass' => 'mw-form-related-link-container',
+ 'default' => Linker::link(
+ SpecialPage::getTitleFor( 'PasswordReset' ),
+ $this->msg( 'userlogin-resetpassword-link' )->escaped()
+ ),
+ 'weight' => 230,
+ ];
+ }
+
+ // Don't show a "create account" link if the user can't.
+ if ( $this->showCreateAccountLink() ) {
+ // link to the other action
+ $linkTitle = $this->getTitleFor( $this->isSignup() ? 'Userlogin' :'CreateAccount' );
+ $linkq = $this->getReturnToQueryStringFragment();
+ // Pass any language selection on to the mode switch link
+ if ( $wgLoginLanguageSelector && $this->mLanguage ) {
+ $linkq .= '&uselang=' . $this->mLanguage;
+ }
+ $loggedIn = $this->getUser()->isLoggedIn();
+
+ $fieldDefinitions['createOrLogin'] = [
+ 'type' => 'info',
+ 'raw' => true,
+ 'linkQuery' => $linkq,
+ 'default' => function ( $params ) use ( $loggedIn, $linkTitle ) {
+ return Html::rawElement( 'div',
+ [ 'id' => 'mw-createaccount' . ( !$loggedIn ? '-cta' : '' ),
+ 'class' => ( $loggedIn ? 'mw-form-related-link-container' : 'mw-ui-vform-field' ) ],
+ ( $loggedIn ? '' : $this->msg( 'userlogin-noaccount' )->escaped() )
+ . Html::element( 'a',
+ [
+ 'id' => 'mw-createaccount-join' . ( $loggedIn ? '-loggedin' : '' ),
+ 'href' => $linkTitle->getLocalURL( $params['linkQuery'] ),
+ 'class' => ( $loggedIn ? '' : 'mw-ui-button' ),
+ 'tabindex' => 100,
+ ],
+ $this->msg(
+ $loggedIn ? 'userlogin-createanother' : 'userlogin-joinproject'
+ )->escaped()
+ )
+ );
+ },
+ 'weight' => 235,
+ ];
+ }
}
$fieldDefinitions = $this->getBCFieldDefinitions( $fieldDefinitions, $template );
/**
* @param array $formDescriptor
*/
- protected function postProcessFormDescriptor( &$formDescriptor ) {
+ protected function postProcessFormDescriptor( &$formDescriptor, $requests ) {
// Pre-fill username (if not creating an account, T46775).
if (
isset( $formDescriptor['username'] ) &&
// don't show a submit button if there is nothing to submit (i.e. the only form content
// is other submit buttons, for redirect flows)
- if ( !$this->needsSubmitButton( $formDescriptor ) ) {
+ if ( !$this->needsSubmitButton( $requests ) ) {
unset( $formDescriptor['createaccount'], $formDescriptor['loginattempt'] );
}
}
}
-/**
- * A horrible hack to handle AuthManager's feature flag. For other special pages this is done in
- * SpecialPageFactory, but LoginForm is used directly by some extensions. Will be killed as soon
- * as AuthManager is stable.
- */
-class LoginForm extends SpecialPage {
- private $realLoginForm;
-
- public function __construct( $request = null ) {
- global $wgDisableAuthManager;
- if ( $wgDisableAuthManager ) {
- $this->realLoginForm = new LoginFormPreAuthManager( $request );
- } else {
- $this->realLoginForm = new LoginFormAuthManager( $request );
- }
- }
-
- // proxy everything
-
- public function __get( $name ) {
- return $this->realLoginForm->$name;
- }
-
- public function __set( $name, $value ) {
- $this->realLoginForm->$name = $value;
- }
-
- public function __call( $name, $args ) {
- return call_user_func_array( [ $this->realLoginForm, $name ], $args );
- }
-
- public static function __callStatic( $name, $args ) {
- global $wgDisableAuthManager;
- return call_user_func_array( [ $wgDisableAuthManager ? LoginFormPreAuthManager::class
- : LoginFormAuthManager::class, $name ], $args );
- }
-
- // all public SpecialPage methods need to be proxied explicitly
-
- public function getName() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function getRestriction() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function isListed() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function setListed( $listed ) {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function listed( $x = null ) {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function isIncludable() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function including( $x = null ) {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function getLocalName() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function isExpensive() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function isCached() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function isRestricted() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function userCanExecute( User $user ) {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function displayRestrictionError() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function checkPermissions() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function checkReadOnly() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function requireLogin(
- $reasonMsg = 'exception-nologin-text', $titleMsg = 'exception-nologin'
- ) {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function prefixSearchSubpages( $search, $limit, $offset ) {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function execute( $subPage ) {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function getDescription() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- function getTitle( $subpage = false ) {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- function getPageTitle( $subpage = false ) {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function setContext( $context ) {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function getContext() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function getRequest() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function getOutput() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function getUser() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function getSkin() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function getLanguage() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function getConfig() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function getFullTitle() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function getFinalGroupName() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
- public function doesWrites() {
- return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
- }
-
- // no way to proxy constants and static properties
-
- const SUCCESS = 0;
- const NO_NAME = 1;
- const ILLEGAL = 2;
- const WRONG_PLUGIN_PASS = 3;
- const NOT_EXISTS = 4;
- const WRONG_PASS = 5;
- const EMPTY_PASS = 6;
- const RESET_PASS = 7;
- const ABORTED = 8;
- const CREATE_BLOCKED = 9;
- const THROTTLED = 10;
- const USER_BLOCKED = 11;
- const NEED_TOKEN = 12;
- const WRONG_TOKEN = 13;
- const USER_MIGRATED = 14;
-
- public static $statusCodes = [
- self::SUCCESS => 'success',
- self::NO_NAME => 'no_name',
- self::ILLEGAL => 'illegal',
- self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
- self::NOT_EXISTS => 'not_exists',
- self::WRONG_PASS => 'wrong_pass',
- self::EMPTY_PASS => 'empty_pass',
- self::RESET_PASS => 'reset_pass',
- self::ABORTED => 'aborted',
- self::CREATE_BLOCKED => 'create_blocked',
- self::THROTTLED => 'throttled',
- self::USER_BLOCKED => 'user_blocked',
- self::NEED_TOKEN => 'need_token',
- self::WRONG_TOKEN => 'wrong_token',
- self::USER_MIGRATED => 'user_migrated',
- ];
-
- public static $validErrorMessages = [
- 'exception-nologin-text',
- 'watchlistanontext',
- 'changeemail-no-info',
- 'resetpass-no-info',
- 'confirmemail_needlogin',
- 'prefsnologintext2',
- ];
-}
-
/**
* LoginForm as a special page has been replaced by SpecialUserLogin and SpecialCreateAccount,
* but some extensions called its public methods directly, so the class is retained as a
* B/C wrapper. Anything that used it before should use AuthManager instead.
*/
-class LoginFormAuthManager extends SpecialPage {
+class LoginForm extends SpecialPage {
const SUCCESS = 0;
const NO_NAME = 1;
const ILLEGAL = 2;