forked from mirrors/pronouns.cc
feat(frontend): validate username and member name client-side too
This commit is contained in:
parent
6532393578
commit
5be0b168c5
3 changed files with 37 additions and 13 deletions
|
@ -75,7 +75,7 @@ func (s *Server) createMember(w http.ResponseWriter, r *http.Request) (err error
|
|||
if !db.MemberNameValid(cmr.Name) {
|
||||
return server.APIError{
|
||||
Code: server.ErrBadRequest,
|
||||
Details: "Member name cannot contain any of the following: @, \\, ?, !, #, /, \\, [, ], \", ', $, %, &, (, ), +, <, =, >, ^, |, ~, `, ,",
|
||||
Details: "Member name cannot contain any of the following: @, ?, !, #, /, \\, [, ], \", ', $, %, &, (, ), +, <, =, >, ^, |, ~, `, ,",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,10 +58,13 @@
|
|||
memberPage = memberPage + 1;
|
||||
};
|
||||
|
||||
const memberNameRegex = /^[^@\\?!#\/\\\\[\]\"'$%&()+<=>^|~`,]{1,100}$/;
|
||||
let modalOpen = false;
|
||||
let toggleModal = () => (modalOpen = !modalOpen);
|
||||
let newMemberName = "";
|
||||
let newMemberError: APIError | null = null;
|
||||
let memberNameValid = true;
|
||||
$: memberNameValid = memberNameRegex.test(newMemberName);
|
||||
|
||||
const createMember = async () => {
|
||||
try {
|
||||
|
@ -210,10 +213,8 @@
|
|||
<p>
|
||||
You don't have any members yet.
|
||||
<br />
|
||||
Members are sub-profiles that can have their own avatar,
|
||||
names, pronouns, and preferred terms. <span class="text-muted"
|
||||
>(only you can see this)</span
|
||||
>
|
||||
Members are sub-profiles that can have their own avatar, names, pronouns, and preferred terms.
|
||||
<span class="text-muted">(only you can see this)</span>
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -221,12 +222,20 @@
|
|||
<Modal header="Create member" isOpen={modalOpen} toggle={toggleModal}>
|
||||
<ModalBody>
|
||||
<Input bind:value={newMemberName} />
|
||||
<p class="text-muted my-2">
|
||||
<Icon name="info-circle-fill" aria-label="Info" /> Your members must have distinct names. Member
|
||||
names must be 100 characters long at most, and cannot contain the following characters: @ ?
|
||||
! # / \ [ ] " ' $ % & ( ) + < = > ^ | ~ ` and ,
|
||||
</p>
|
||||
{#if newMemberError}
|
||||
<ErrorAlert error={newMemberError} />
|
||||
{/if}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="primary" on:click={createMember} disabled={newMemberName.length === 0}
|
||||
{#if !memberNameValid && newMemberName.length > 0}
|
||||
<span class="text-danger-emphasis mb-2">That member name is not valid.</span>
|
||||
{/if}
|
||||
<Button color="primary" on:click={createMember} disabled={!memberNameValid}
|
||||
>Create member</Button
|
||||
>
|
||||
<Button color="secondary" on:click={toggleModal}>Cancel</Button>
|
||||
|
|
|
@ -43,7 +43,11 @@
|
|||
let deleteCancelled: boolean;
|
||||
let deleteError: APIError | null;
|
||||
|
||||
const usernameRegex = /^[\w-.]{2,40}$/;
|
||||
let username: string;
|
||||
let usernameValid = true;
|
||||
$: usernameValid = usernameRegex.test(username);
|
||||
|
||||
let inviteCode: string;
|
||||
let forceDeleteName = "";
|
||||
let forceDeleteModalOpen = false;
|
||||
|
@ -88,10 +92,10 @@
|
|||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Log in with the {authType} - pronouns.cc</title>
|
||||
<title>Log in with {authType} - pronouns.cc</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1>Log in with the {authType}</h1>
|
||||
<h1>Log in with {authType}</h1>
|
||||
|
||||
{#if error}
|
||||
<ErrorAlert {error} />
|
||||
|
@ -122,23 +126,34 @@
|
|||
<FormGroup floating label="Username">
|
||||
<Input id="username" name="username" bind:value={username} />
|
||||
</FormGroup>
|
||||
<div id="username-help" class="text-muted">
|
||||
<Icon name="info-circle-fill" aria-label="Info" /> Your username must be unique, be at most 40
|
||||
characters long, and only contain letters from the basic English alphabet, dashes, underscores,
|
||||
and periods. Your username is used as part of your profile link, you can set a separate display
|
||||
name.
|
||||
</div>
|
||||
</div>
|
||||
{#if requireInvite}
|
||||
<div>
|
||||
<FormGroup floating label="Invite code">
|
||||
<Input id="invite" name="invite" aria-describedby="invite-help" bind:value={inviteCode} />
|
||||
</FormGroup>
|
||||
<div id="invite-help" class="form-text">
|
||||
<Icon name="info-circle-fill" /> You currently need an invite code to sign up. You can get
|
||||
one from an existing user.
|
||||
<div id="invite-help" class="text-muted">
|
||||
<Icon name="info-circle-fill" aria-label="Info" /> You currently need an invite code to sign
|
||||
up. You can get one from an existing user.
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="form-text mb-1">
|
||||
<div class="text-muted my-1">
|
||||
By signing up, you agree to the <a href="/page/terms">terms of service</a> and the
|
||||
<a href="/page/privacy">privacy policy</a>.
|
||||
</div>
|
||||
<Button type="submit" color="primary">Sign up</Button>
|
||||
<p>
|
||||
<Button type="submit" color="primary" disabled={!usernameValid}>Sign up</Button>
|
||||
{#if !usernameValid && username.length > 0}
|
||||
<span class="text-danger-emphasis mb-2">That username is not valid.</span>
|
||||
{/if}
|
||||
</p>
|
||||
</form>
|
||||
{:else if isDeleted && token && selfDelete && deletedAt}
|
||||
<p>
|
||||
|
|
Loading…
Reference in a new issue