Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Do pre-submit availability check on username during registration #6978

Merged
merged 4 commits into from
Nov 4, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion src/components/views/auth/RegistrationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import Field from '../elements/Field';
import RegistrationEmailPromptDialog from '../dialogs/RegistrationEmailPromptDialog';
import { replaceableComponent } from "../../../utils/replaceableComponent";
import CountryDropdown from "./CountryDropdown";
import { MatrixClientPeg } from "../../../MatrixClientPeg";

import { logger } from "matrix-js-sdk/src/logger";

Expand Down Expand Up @@ -367,7 +368,11 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
};

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,
rules: [
{
Expand All @@ -380,6 +385,24 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
test: ({ value }) => !value || SAFE_LOCALPART_REGEX.test(value),
invalid: () => _t("Some characters not allowed"),
},
{
key: "available",
final: true,
test: async ({ value }) => {
if (!value) {
return true;
}

try {
await MatrixClientPeg.get().isUsernameAvailable(value);
return true;
} catch (err) {
return false;
}
},
invalid: () => _t("That username already exists, please try another. " +
"If it belongs to you then click 'Sign in here' below"),
},
],
});

Expand Down
14 changes: 10 additions & 4 deletions src/components/views/elements/Validation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ import classNames from "classnames";

type Data = Pick<IFieldState, "value" | "allowEmpty">;

interface IResult {
key: string;
valid: boolean;
text: string;
}

interface IRule<T, D = void> {
key: string;
final?: boolean;
Expand All @@ -32,7 +38,7 @@ interface IRule<T, D = void> {

interface IArgs<T, D = void> {
rules: IRule<T, D>[];
description?(this: T, derivedData: D): React.ReactChild;
description?(this: T, derivedData: D, results: IResult[]): React.ReactChild;
hideDescriptionIfValid?: boolean;
deriveData?(data: Data): Promise<D>;
}
Expand Down Expand Up @@ -88,7 +94,7 @@ export default function withValidation<T = undefined, D = void>({
const data = { value, allowEmpty };
const derivedData = deriveData ? await deriveData(data) : undefined;

const results = [];
const results: IResult[] = [];
let valid = true;
if (rules && rules.length) {
for (const rule of rules) {
Expand Down Expand Up @@ -164,8 +170,8 @@ export default function withValidation<T = undefined, D = void>({
if (description && (details || !hideDescriptionIfValid)) {
// We're setting `this` to whichever component holds the validation
// function. That allows rules to access the state of the component.
const content = description.call(this, derivedData);
summary = <div className="mx_Validation_description">{ content }</div>;
const content = description.call(this, derivedData, results);
summary = content ? <div className="mx_Validation_description">{ content }</div> : undefined;
}

let feedback;
Expand Down
1 change: 1 addition & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2768,6 +2768,7 @@
"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)",
"Use lowercase letters, numbers, dashes and underscores only": "Use lowercase letters, numbers, dashes and underscores only",
"That username already exists, please try another. If it belongs to you then click 'Sign in here' below": "That username already exists, please try another. If it belongs to you then click 'Sign in here' below",
"Phone (optional)": "Phone (optional)",
"Register": "Register",
"Add an email to be able to reset your password.": "Add an email to be able to reset your password.",
Expand Down