Do pre-submit availability check on username during registration (#6978)
This commit is contained in:
parent
e31b126daa
commit
e26abbba72
4 changed files with 38 additions and 7 deletions
|
@ -304,7 +304,7 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
errorText = _t('This server does not support authentication with a phone number.');
|
errorText = _t('This server does not support authentication with a phone number.');
|
||||||
}
|
}
|
||||||
} else if (response.errcode === "M_USER_IN_USE") {
|
} else if (response.errcode === "M_USER_IN_USE") {
|
||||||
errorText = _t("That username already exists, please try another.");
|
errorText = _t("Someone already has that username, please try another.");
|
||||||
} else if (response.errcode === "M_THREEPID_IN_USE") {
|
} else if (response.errcode === "M_THREEPID_IN_USE") {
|
||||||
errorText = _t("That e-mail address is already in use.");
|
errorText = _t("That e-mail address is already in use.");
|
||||||
}
|
}
|
||||||
|
@ -510,6 +510,7 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
flows={this.state.flows}
|
flows={this.state.flows}
|
||||||
serverConfig={this.props.serverConfig}
|
serverConfig={this.props.serverConfig}
|
||||||
canSubmit={!this.state.serverErrorIsFatal}
|
canSubmit={!this.state.serverErrorIsFatal}
|
||||||
|
matrixClient={this.state.matrixClient}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||||
|
|
||||||
import * as Email from '../../../email';
|
import * as Email from '../../../email';
|
||||||
import { looksValid as phoneNumberLooksValid } from '../../../phonenumber';
|
import { looksValid as phoneNumberLooksValid } from '../../../phonenumber';
|
||||||
|
@ -57,6 +58,7 @@ interface IProps {
|
||||||
}[];
|
}[];
|
||||||
serverConfig: ValidatedServerConfig;
|
serverConfig: ValidatedServerConfig;
|
||||||
canSubmit?: boolean;
|
canSubmit?: boolean;
|
||||||
|
matrixClient: MatrixClient;
|
||||||
|
|
||||||
onRegisterClick(params: {
|
onRegisterClick(params: {
|
||||||
username: string;
|
username: string;
|
||||||
|
@ -366,7 +368,11 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||||
};
|
};
|
||||||
|
|
||||||
private validateUsernameRules = withValidation({
|
private validateUsernameRules = withValidation({
|
||||||
description: () => _t("Use lowercase letters, numbers, dashes and underscores only"),
|
description: (_, results) => {
|
||||||
|
// omit the description if the only failing result is the `available` one as it makes no sense for it.
|
||||||
|
if (results.every(({ key, valid }) => key === "available" || valid)) return;
|
||||||
|
return _t("Use lowercase letters, numbers, dashes and underscores only");
|
||||||
|
},
|
||||||
hideDescriptionIfValid: true,
|
hideDescriptionIfValid: true,
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
|
@ -379,6 +385,23 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||||
test: ({ value }) => !value || SAFE_LOCALPART_REGEX.test(value),
|
test: ({ value }) => !value || SAFE_LOCALPART_REGEX.test(value),
|
||||||
invalid: () => _t("Some characters not allowed"),
|
invalid: () => _t("Some characters not allowed"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "available",
|
||||||
|
final: true,
|
||||||
|
test: async ({ value }) => {
|
||||||
|
if (!value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.props.matrixClient.isUsernameAvailable(value);
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
invalid: () => _t("Someone already has that username. Try another or if it is you, sign in below."),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,12 @@ import classNames from "classnames";
|
||||||
|
|
||||||
type Data = Pick<IFieldState, "value" | "allowEmpty">;
|
type Data = Pick<IFieldState, "value" | "allowEmpty">;
|
||||||
|
|
||||||
|
interface IResult {
|
||||||
|
key: string;
|
||||||
|
valid: boolean;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface IRule<T, D = void> {
|
interface IRule<T, D = void> {
|
||||||
key: string;
|
key: string;
|
||||||
final?: boolean;
|
final?: boolean;
|
||||||
|
@ -32,7 +38,7 @@ interface IRule<T, D = void> {
|
||||||
|
|
||||||
interface IArgs<T, D = void> {
|
interface IArgs<T, D = void> {
|
||||||
rules: IRule<T, D>[];
|
rules: IRule<T, D>[];
|
||||||
description?(this: T, derivedData: D): React.ReactChild;
|
description?(this: T, derivedData: D, results: IResult[]): React.ReactChild;
|
||||||
hideDescriptionIfValid?: boolean;
|
hideDescriptionIfValid?: boolean;
|
||||||
deriveData?(data: Data): Promise<D>;
|
deriveData?(data: Data): Promise<D>;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +94,7 @@ export default function withValidation<T = undefined, D = void>({
|
||||||
const data = { value, allowEmpty };
|
const data = { value, allowEmpty };
|
||||||
const derivedData = deriveData ? await deriveData(data) : undefined;
|
const derivedData = deriveData ? await deriveData(data) : undefined;
|
||||||
|
|
||||||
const results = [];
|
const results: IResult[] = [];
|
||||||
let valid = true;
|
let valid = true;
|
||||||
if (rules && rules.length) {
|
if (rules && rules.length) {
|
||||||
for (const rule of rules) {
|
for (const rule of rules) {
|
||||||
|
@ -164,8 +170,8 @@ export default function withValidation<T = undefined, D = void>({
|
||||||
if (description && (details || !hideDescriptionIfValid)) {
|
if (description && (details || !hideDescriptionIfValid)) {
|
||||||
// We're setting `this` to whichever component holds the validation
|
// We're setting `this` to whichever component holds the validation
|
||||||
// function. That allows rules to access the state of the component.
|
// function. That allows rules to access the state of the component.
|
||||||
const content = description.call(this, derivedData);
|
const content = description.call(this, derivedData, results);
|
||||||
summary = <div className="mx_Validation_description">{ content }</div>;
|
summary = content ? <div className="mx_Validation_description">{ content }</div> : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
let feedback;
|
let feedback;
|
||||||
|
|
|
@ -2792,6 +2792,7 @@
|
||||||
"Other users can invite you to rooms using your contact details": "Other users can invite you to rooms using your contact details",
|
"Other users can invite you to rooms using your contact details": "Other users can invite you to rooms using your contact details",
|
||||||
"Enter phone number (required on this homeserver)": "Enter phone number (required on this homeserver)",
|
"Enter phone number (required on this homeserver)": "Enter phone number (required on this homeserver)",
|
||||||
"Use lowercase letters, numbers, dashes and underscores only": "Use lowercase letters, numbers, dashes and underscores only",
|
"Use lowercase letters, numbers, dashes and underscores only": "Use lowercase letters, numbers, dashes and underscores only",
|
||||||
|
"Someone already has that username. Try another or if it is you, sign in below.": "Someone already has that username. Try another or if it is you, sign in below.",
|
||||||
"Phone (optional)": "Phone (optional)",
|
"Phone (optional)": "Phone (optional)",
|
||||||
"Register": "Register",
|
"Register": "Register",
|
||||||
"Add an email to be able to reset your password.": "Add an email to be able to reset your password.",
|
"Add an email to be able to reset your password.": "Add an email to be able to reset your password.",
|
||||||
|
@ -3079,7 +3080,7 @@
|
||||||
"Unable to query for supported registration methods.": "Unable to query for supported registration methods.",
|
"Unable to query for supported registration methods.": "Unable to query for supported registration methods.",
|
||||||
"Registration has been disabled on this homeserver.": "Registration has been disabled on this homeserver.",
|
"Registration has been disabled on this homeserver.": "Registration has been disabled on this homeserver.",
|
||||||
"This server does not support authentication with a phone number.": "This server does not support authentication with a phone number.",
|
"This server does not support authentication with a phone number.": "This server does not support authentication with a phone number.",
|
||||||
"That username already exists, please try another.": "That username already exists, please try another.",
|
"Someone already has that username, please try another.": "Someone already has that username, please try another.",
|
||||||
"That e-mail address is already in use.": "That e-mail address is already in use.",
|
"That e-mail address is already in use.": "That e-mail address is already in use.",
|
||||||
"Continue with %(ssoButtons)s": "Continue with %(ssoButtons)s",
|
"Continue with %(ssoButtons)s": "Continue with %(ssoButtons)s",
|
||||||
"%(ssoButtons)s Or %(usernamePassword)s": "%(ssoButtons)s Or %(usernamePassword)s",
|
"%(ssoButtons)s Or %(usernamePassword)s": "%(ssoButtons)s Or %(usernamePassword)s",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue