fix display name minimum and maximum length
This commit is contained in:
parent
52faf16837
commit
5c95051ddf
3 changed files with 57 additions and 9 deletions
|
|
@ -8,6 +8,18 @@ import { MAX_FILE_SIZE } from '$lib/data/constants';
|
||||||
import { isNameAppropriate } from '$lib/server/moderation';
|
import { isNameAppropriate } from '$lib/server/moderation';
|
||||||
|
|
||||||
async function validateInputs(name: string, bio: string, username: string, avatarFile: File | null) {
|
async function validateInputs(name: string, bio: string, username: string, avatarFile: File | null) {
|
||||||
|
if (!name || !name.trim()) {
|
||||||
|
throw error(400, 'Display name is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name.trim().length < 2) {
|
||||||
|
throw error(400, 'Display name must be at least 2 characters');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name.trim().length > 50) {
|
||||||
|
throw error(400, 'Display name must be 50 characters or less');
|
||||||
|
}
|
||||||
|
|
||||||
if (name && !(await isNameAppropriate(name.trim()))) {
|
if (name && !(await isNameAppropriate(name.trim()))) {
|
||||||
throw error(400, 'Name contains inappropriate content');
|
throw error(400, 'Name contains inappropriate content');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,13 @@ import { isNameAppropriate } from '$lib/server/moderation';
|
||||||
export async function GET({ url }) {
|
export async function GET({ url }) {
|
||||||
let username = url.searchParams.get('username')?.toLowerCase().trim();
|
let username = url.searchParams.get('username')?.toLowerCase().trim();
|
||||||
if (!username) {
|
if (!username) {
|
||||||
return json({ available: false });
|
return json({ available: false, reason: 'Username is required.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
username = username.trim().replace(/\s+/g, ' ');
|
|
||||||
|
|
||||||
if (username.length < 3 || username.length > 30) {
|
if (username.length < 3 || username.length > 30) {
|
||||||
return json({
|
return json({
|
||||||
available: false,
|
available: false,
|
||||||
reason: 'Username must be between 3 and 30 characters'
|
reason: 'Username must be 3-30 characters.'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,17 +21,29 @@ export async function GET({ url }) {
|
||||||
if (!alphanumericRegex.test(username)) {
|
if (!alphanumericRegex.test(username)) {
|
||||||
return json({
|
return json({
|
||||||
available: false,
|
available: false,
|
||||||
reason: 'Username must contain only lowercase letters, numbers, and underscores'
|
reason: 'Username can only contain lowercase letters, numbers, and underscores.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const purelyNumericRegex = /^\d+$/;
|
||||||
|
if (purelyNumericRegex.test(username)) {
|
||||||
|
return json({
|
||||||
|
available: false,
|
||||||
|
reason: 'Username cannot be purely numeric.'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await isNameAppropriate(username))) {
|
if (!(await isNameAppropriate(username))) {
|
||||||
return json({ available: false, reason: 'Inappropriate content' });
|
return json({ available: false, reason: 'Username contains inappropriate content.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const exists = await db.query.user.findFirst({
|
const exists = await db.query.user.findFirst({
|
||||||
where: eq(user.username, username)
|
where: eq(user.username, username)
|
||||||
});
|
});
|
||||||
|
|
||||||
return json({ available: !exists });
|
if (exists) {
|
||||||
|
return json({ available: false, reason: 'Username is already taken.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
return json({ available: true });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@
|
||||||
let previewUrl: string | null = $state(null);
|
let previewUrl: string | null = $state(null);
|
||||||
let currentAvatarUrl = $derived(previewUrl || getPublicUrl($USER_DATA?.image ?? null));
|
let currentAvatarUrl = $derived(previewUrl || getPublicUrl($USER_DATA?.image ?? null));
|
||||||
|
|
||||||
|
let nameError = $state('');
|
||||||
|
|
||||||
let isDirty = $derived(
|
let isDirty = $derived(
|
||||||
name !== ($USER_DATA?.name || '') ||
|
name !== ($USER_DATA?.name || '') ||
|
||||||
bio !== ($USER_DATA?.bio ?? '') ||
|
bio !== ($USER_DATA?.bio ?? '') ||
|
||||||
|
|
@ -101,6 +103,22 @@
|
||||||
if (username !== initialUsername) checkUsername(username);
|
if (username !== initialUsername) checkUsername(username);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
validateName();
|
||||||
|
});
|
||||||
|
|
||||||
|
function validateName() {
|
||||||
|
if (!name.trim()) {
|
||||||
|
nameError = 'Display name is required.';
|
||||||
|
} else if (name.trim().length < 2) {
|
||||||
|
nameError = 'Display name must be at least 2 characters.';
|
||||||
|
} else if (name.trim().length > 50) {
|
||||||
|
nameError = 'Display name must be 50 characters or less.';
|
||||||
|
} else {
|
||||||
|
nameError = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSubmit(e: Event) {
|
async function handleSubmit(e: Event) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
loading = true;
|
loading = true;
|
||||||
|
|
@ -317,7 +335,15 @@
|
||||||
<form onsubmit={handleSubmit} class="space-y-4">
|
<form onsubmit={handleSubmit} class="space-y-4">
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<Label for="name">Display Name</Label>
|
<Label for="name">Display Name</Label>
|
||||||
<Input id="name" bind:value={name} required />
|
<Input
|
||||||
|
id="name"
|
||||||
|
bind:value={name}
|
||||||
|
required
|
||||||
|
class={nameError ? 'border-destructive' : ''}
|
||||||
|
/>
|
||||||
|
{#if nameError}
|
||||||
|
<p class="text-destructive text-sm">{nameError}</p>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
|
|
@ -355,7 +381,7 @@
|
||||||
<Textarea id="bio" bind:value={bio} rows={4} placeholder="Tell us about yourself" />
|
<Textarea id="bio" bind:value={bio} rows={4} placeholder="Tell us about yourself" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button type="submit" disabled={loading || !isDirty}>
|
<Button type="submit" disabled={loading || !isDirty || !!nameError}>
|
||||||
{loading ? 'Saving…' : 'Save Changes'}
|
{loading ? 'Saving…' : 'Save Changes'}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
Reference in a new issue