Finished registration + working on own useAuth composable
This commit is contained in:
parent
1d2a89e001
commit
f2600a3012
|
|
@ -138,9 +138,6 @@ html.light-mode .light-block {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.align-baseline {
|
.align-baseline {
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
}
|
}
|
||||||
|
|
@ -150,11 +147,26 @@ html.light-mode .light-block {
|
||||||
.align-stretch {
|
.align-stretch {
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
.justify-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.justify-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.justify-evenly {
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
.justify-around {
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 750px) {
|
@media screen and (max-width: 750px) {
|
||||||
.mobile-bigger {
|
.mobile-bigger {
|
||||||
flex: 3 1 0 !important;
|
flex: 3 1 0 !important;
|
||||||
}
|
}
|
||||||
|
.mobile-smaller {
|
||||||
|
flex: 1 3 0 !important;
|
||||||
|
}
|
||||||
.mobile-hidden {
|
.mobile-hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
@ -163,10 +175,82 @@ html.light-mode .light-block {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media screen and (min-width: 750px) {
|
@media screen and (min-width: 750px) {
|
||||||
|
.desktop-bigger {
|
||||||
|
flex: 3 1 0 !important;
|
||||||
|
}
|
||||||
|
.desktop-smaller {
|
||||||
|
flex: 1 3 0 !important;
|
||||||
|
}
|
||||||
.desktop-hidden {
|
.desktop-hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
.desktop-block {
|
.desktop-block {
|
||||||
display: inherit !important;
|
display: inherit !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.input-form.input-form-wide {
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-form {
|
||||||
|
width: 400px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0 2em 2em 2em;
|
||||||
|
border: 1px solid var(--background-modifier-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-form h1 {
|
||||||
|
font-size: x-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-form button {
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group .input-label {
|
||||||
|
padding: 4px 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group .input-error {
|
||||||
|
padding: .5em 1em 4px;
|
||||||
|
color: var(--text-error);
|
||||||
|
user-select: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group .input-input.input-has-error {
|
||||||
|
border-color: var(--text-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-validation-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: .5em 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-validation-title {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: small;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-validation-item {
|
||||||
|
font-size: small;
|
||||||
|
padding-left: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-validation-item pre {
|
||||||
|
user-select: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-validation-item.validation-error {
|
||||||
|
color: var(--text-error);
|
||||||
}
|
}
|
||||||
|
|
@ -2266,13 +2266,6 @@ button.mod-destructive {
|
||||||
color: var(--text-on-accent);
|
color: var(--text-on-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-label {
|
|
||||||
display: inline-block;
|
|
||||||
width: 150px;
|
|
||||||
text-align: right;
|
|
||||||
margin-right: var(--size-4-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-button {
|
.input-button {
|
||||||
padding: 6px 14px;
|
padding: 6px 14px;
|
||||||
margin-left: 14px;
|
margin-left: 14px;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
interface Prop
|
||||||
|
{
|
||||||
|
error?: string | boolean;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
const props = defineProps<Prop>();
|
||||||
|
const model = defineModel<string>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="input-group">
|
||||||
|
<label v-if="title" class="input-label">{{ title }}</label>
|
||||||
|
<input class="input-input" :class="{'input-has-error': !!error}" v-model="model" v-bind="$attrs" />
|
||||||
|
<span v-if="error && typeof error === 'string'" class="input-error">{{ error }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
export enum AuthStatus
|
||||||
|
{
|
||||||
|
disconnected, loading, connected
|
||||||
|
};
|
||||||
|
export interface Auth
|
||||||
|
{
|
||||||
|
id: Ref<number>;
|
||||||
|
data: Ref<Record<string, any>>;
|
||||||
|
token: Ref<string>;
|
||||||
|
session_id: Ref<number>;
|
||||||
|
status: Ref<AuthStatus>;
|
||||||
|
|
||||||
|
lastRefresh: Ref<Date>;
|
||||||
|
|
||||||
|
register: (username: string, email: string, password: string, data?: Record<string, any>) => AuthStatus;
|
||||||
|
login: (usernameOrEmail: string, password: string) => AuthStatus;
|
||||||
|
logout: () => AuthStatus;
|
||||||
|
|
||||||
|
refresh: () => AuthStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = useState<number>("auth:id", () => 0);
|
||||||
|
const data = useState<any>("auth:data", () => {});
|
||||||
|
const token = useState<string>("auth:token", () => '');
|
||||||
|
const session_id = useState<number>("auth:session_id", () => 0);
|
||||||
|
const status = useState<AuthStatus>("auth:status", () => 0);
|
||||||
|
|
||||||
|
const lastRefresh = useState<Date>("auth:date", () => new Date());
|
||||||
|
|
||||||
|
function register(username: string, email: string, password: string, data?: Record<string, any>): AuthStatus
|
||||||
|
{
|
||||||
|
|
||||||
|
return AuthStatus.disconnected;
|
||||||
|
}
|
||||||
|
function login(usernameOrEmail: string, password: string): AuthStatus
|
||||||
|
{
|
||||||
|
return AuthStatus.disconnected;
|
||||||
|
}
|
||||||
|
function logout(): AuthStatus
|
||||||
|
{
|
||||||
|
return AuthStatus.disconnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
function refresh(): AuthStatus
|
||||||
|
{
|
||||||
|
return AuthStatus.disconnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useAuth(): Auth {
|
||||||
|
return {
|
||||||
|
id, data, token, session_id, status, lastRefresh,
|
||||||
|
register, login, logout, refresh
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Database } from "bun:sqlite";
|
||||||
|
|
||||||
|
let instance: Database | undefined;
|
||||||
|
|
||||||
|
export default function useDatabase(): Database {
|
||||||
|
if(instance === undefined)
|
||||||
|
instance = getDatabase();
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDatabase(): Database
|
||||||
|
{
|
||||||
|
const { dbFile } = useRuntimeConfig();
|
||||||
|
|
||||||
|
const db = new Database(dbFile);
|
||||||
|
|
||||||
|
db.exec("PRAGMA journal_mode = WAL;");
|
||||||
|
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
export default defineNuxtRouteMiddleware((to) => {
|
||||||
|
const meta = to.meta.auth;
|
||||||
|
|
||||||
|
//to.
|
||||||
|
})
|
||||||
|
|
@ -2,45 +2,17 @@
|
||||||
import CanvasModule from './transformer/canvas/module'
|
import CanvasModule from './transformer/canvas/module'
|
||||||
|
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
modules: [CanvasModule, "@nuxt/content", "@nuxtjs/color-mode", '@sidebase/nuxt-auth'],
|
modules: [CanvasModule, "@nuxt/content", "@nuxtjs/color-mode"],
|
||||||
|
css: ['~/assets/common.css', '~/assets/global.css'],
|
||||||
|
runtimeConfig: {
|
||||||
|
dbFile: ''
|
||||||
|
},
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
path: '~/components',
|
path: '~/components',
|
||||||
pathPrefix: false,
|
pathPrefix: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
router: {
|
|
||||||
options: {
|
|
||||||
scrollBehaviorType: 'smooth'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
auth: {
|
|
||||||
baseURL: '/api/auth',
|
|
||||||
provider: {
|
|
||||||
type: 'local',
|
|
||||||
//type: 'refresh',
|
|
||||||
endpoints: {
|
|
||||||
signIn: { path: '/login', method: 'post' },
|
|
||||||
signOut: { path: '/logout', method: 'post' },
|
|
||||||
signUp: { path: '/register', method: 'post' },
|
|
||||||
getSession: { path: '/session', method: 'get' },
|
|
||||||
//refresh: { path: '/refresh', method: 'post' }
|
|
||||||
},
|
|
||||||
session: {
|
|
||||||
dataType: {
|
|
||||||
id: 'string',
|
|
||||||
username: 'string',
|
|
||||||
email: 'string',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
css: ['~/assets/common.css', '~/assets/global.css'],
|
|
||||||
|
|
||||||
content: {
|
content: {
|
||||||
ignores: [
|
ignores: [
|
||||||
'98.Privé'
|
'98.Privé'
|
||||||
|
|
@ -78,12 +50,5 @@ export default defineNuxtConfig({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
vite: {
|
|
||||||
vue: {
|
|
||||||
customElement: ['Line', 'Circle', 'Path']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
compatibilityDate: '2024-07-25'
|
compatibilityDate: '2024-07-25'
|
||||||
})
|
})
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt/content": "^2.13.2",
|
"@nuxt/content": "^2.13.2",
|
||||||
"@nuxtjs/color-mode": "^3.4.2",
|
"@nuxtjs/color-mode": "^3.4.2",
|
||||||
"@sidebase/nuxt-auth": "^0.8.1",
|
"@types/bun": "^1.1.6",
|
||||||
"nuxt": "^3.12.4",
|
"nuxt": "^3.12.4",
|
||||||
"vue": "^3.4.34",
|
"vue": "^3.4.34",
|
||||||
"vue-router": "^4.4.0"
|
"vue-router": "^4.4.0"
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hast-util-to-html": "^9.0.1",
|
"hast-util-to-html": "^9.0.1",
|
||||||
"remark-breaks": "^4.0.0",
|
"remark-breaks": "^4.0.0",
|
||||||
"remark-ofm": "link:remark-ofm"
|
"remark-ofm": "link:remark-ofm",
|
||||||
|
"zod": "^3.23.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
title: '',
|
|
||||||
auth: {
|
auth: {
|
||||||
unauthenticatedOnly: true,
|
unauthenticatedOnly: true,
|
||||||
navigateAuthenticatedTo: '/user/profile'
|
navigateAuthenticatedTo: '/user/profile'
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
auth: {
|
auth: {
|
||||||
unauthenticatedOnly: false,
|
unauthenticatedOnly: false,
|
||||||
navigateAuthenticatedTo: '/user/login'
|
navigateUnauthenticatedTo: '/user/login'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { schema, type Registration } from '~/schemas/registration';
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
auth: {
|
||||||
|
unauthenticatedOnly: true,
|
||||||
|
navigateAuthenticatedTo: '/user/profile'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const state = reactive<Registration>({
|
||||||
|
username: '',
|
||||||
|
email: '',
|
||||||
|
password: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const confirmPassword = ref("");
|
||||||
|
|
||||||
|
const { status, signUp } = useAuth();
|
||||||
|
|
||||||
|
const checkedLength = computed(() => state.password.length >= 8 && state.password.length <= 128);
|
||||||
|
const checkedLowerUpper = computed(() => state.password.toLowerCase() !== state.password && state.password.toUpperCase() !== state.password);
|
||||||
|
const checkedDigit = computed(() => /[0-9]/.test(state.password));
|
||||||
|
const checkedSymbol = computed(() => " !\"#$%&'()*+,-./:;<=>?@[]^_`{|}~".split("").some(e => state.password.includes(e)));
|
||||||
|
|
||||||
|
const usernameError = ref("");
|
||||||
|
const emailError = ref("");
|
||||||
|
|
||||||
|
function register(): void
|
||||||
|
{
|
||||||
|
const data = schema.safeParse(state);
|
||||||
|
|
||||||
|
if(data.success && state.password !== "" && confirmPassword.value === state.password)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
signUp({ ...data.data }, { redirect: true, callbackUrl: '/' });
|
||||||
|
} catch(e) {
|
||||||
|
usernameError.value = e?.data?.find(e => e.path.includes("username"))?.message ?? "";
|
||||||
|
emailError.value = e?.data?.find(e => e.path.includes("email"))?.message ?? "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
usernameError.value = data.error?.issues.find(e => e.path.includes("username"))?.message ?? "";
|
||||||
|
emailError.value = data.error?.issues.find(e => e.path.includes("email"))?.message ?? "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Head>
|
||||||
|
<Title>S'inscrire</Title>
|
||||||
|
</Head>
|
||||||
|
<div class="site-body-center-column">
|
||||||
|
<div class="render-container flex align-center justify-center">
|
||||||
|
<form v-if="status === 'unauthenticated'" @submit.prevent="register" class="input-form input-form-wide">
|
||||||
|
<h1>Inscription</h1>
|
||||||
|
<Input type="text" v-model="state.username" placeholder="Entrez un nom d'utiliateur" title="Nom d'utilisateur" :error="usernameError"/>
|
||||||
|
<Input type="text" v-model="state.email" placeholder="Entrez une addresse mail" title="Adresse mail" :error="emailError"/>
|
||||||
|
<Input type="password" v-model="state.password" placeholder="Entrez un mot de passe" title="Mot de passe" :error="!(checkedLength && checkedLowerUpper && checkedDigit && checkedSymbol)"/>
|
||||||
|
<div class="password-validation-group">
|
||||||
|
<span class="password-validation-title">Votre mot de passe doit respecter les critères suivants :</span>
|
||||||
|
<span class="password-validation-item" :class="{'validation-error': !checkedLength}">Entre 8 et 128 caractères</span>
|
||||||
|
<span class="password-validation-item" :class="{'validation-error': !checkedLowerUpper}">Au moins une minuscule et une majuscule</span>
|
||||||
|
<span class="password-validation-item" :class="{'validation-error': !checkedDigit}">Au moins un chiffre</span>
|
||||||
|
<span class="password-validation-item" :class="{'validation-error': !checkedSymbol}">Au moins un caractère spécial parmis la liste suivante: <pre>! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~</pre></span>
|
||||||
|
</div>
|
||||||
|
<Input type="password" v-model="confirmPassword" placeholder="Confirmer le mot de passe" title="Confirmer le mot de passe" :error="confirmPassword === '' || confirmPassword === state.password ? '' : 'Les mots de passe saisies ne sont pas identique'"/>
|
||||||
|
<button>Valider</button>
|
||||||
|
</form>
|
||||||
|
<div v-else-if="status === 'loading'"></div>
|
||||||
|
<div v-else class="not-found-container">
|
||||||
|
<div class="not-found-title">👀 Vous n'avez rien à faire ici. 👀</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
definePageMeta({
|
|
||||||
title: '',
|
|
||||||
auth: {
|
|
||||||
unauthenticatedOnly: true,
|
|
||||||
navigateAuthenticatedTo: '/user/profile'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const username = ref<string>(), email = ref<string>(), password = ref<string>();
|
|
||||||
|
|
||||||
const { status, signUp } = useAuth();
|
|
||||||
|
|
||||||
function connect() {
|
|
||||||
signUp({ username, password, email }, { redirect: true, callbackUrl: '/' });
|
|
||||||
|
|
||||||
console.log(status.value);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Head>
|
|
||||||
<Title>S'inscrire</Title>
|
|
||||||
</Head>
|
|
||||||
<!--<div class="site-body-center-column">
|
|
||||||
<div class="render-container">
|
|
||||||
<div v-if="status === 'unauthenticated'" class="not-found-container">
|
|
||||||
<form @submit.prevent="connect" class="column gapy-1">
|
|
||||||
<input type="text" :value="username" placeholder="Entrez un nom d'utiliateur">
|
|
||||||
<input type="text" :value="email" placeholder="Entrez une addresse mail">
|
|
||||||
<input type="password" :value="password" placeholder="Entrez un mot de passe">
|
|
||||||
<button>Valider</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="status === 'loading'"></div>
|
|
||||||
<div v-else class="not-found-container">
|
|
||||||
<div class="not-found-title">👀 Vous n'avez rien à faire ici. 👀</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>-->
|
|
||||||
</template>
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
function securePassword(password: string, ctx: z.RefinementCtx): void {
|
||||||
|
const lowercase = password.toLowerCase();
|
||||||
|
const uppercase = password.toUpperCase();
|
||||||
|
|
||||||
|
if(lowercase === password)
|
||||||
|
{
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
message: "Votre mot de passe doit contenir au moins une majuscule",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(uppercase === password)
|
||||||
|
{
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
message: "Votre mot de passe doit contenir au moins une minuscule",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(!/[0-9]/.test(password))
|
||||||
|
{
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
message: "Votre mot de passe doit contenir au moins un chiffre",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(!" !\"#$%&'()*+,-./:;<=>?@[]^_`{|}~".split("").some(e => password.includes(e)))
|
||||||
|
{
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
message: "Votre mot de passe doit contenir au moins un symbole",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const schema = z.object({
|
||||||
|
username: z.string({ required_error: "Nom d'utilisateur obligatoire" }).min(3, "Votre nom d'utilisateur doit contenir au moins 3 caractères").max(32, "Votre nom d'utilisateur doit contenir au plus 32 caractères"),
|
||||||
|
email: z.string({ required_error: "Email obligatoire" }).email("Adresse mail invalide"),
|
||||||
|
password: z.string({ required_error: "Mot de passe obligatoire" }).min(8, "Votre mot de passe doit contenir au moins 8 caractères").max(128, "Votre mot de passe doit contenir au moins 8 caractères").superRefine(securePassword),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Registration = z.infer<typeof schema>;
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export default defineEventHandler(async (e) => {
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export default defineEventHandler(async (e) => {
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import useDatabase from '~/composables/useDatabase';
|
||||||
|
import { schema } from '~/schemas/registration';
|
||||||
|
|
||||||
|
export default defineEventHandler(async (e) => {
|
||||||
|
const body = await readValidatedBody(e, schema.safeParse);
|
||||||
|
|
||||||
|
if(!body.success)
|
||||||
|
return body.error;
|
||||||
|
|
||||||
|
const db = useDatabase();
|
||||||
|
|
||||||
|
const usernameQuery = db.query(`SELECT COUNT(*) as count FROM users WHERE username = ?1`);
|
||||||
|
const checkUsername = usernameQuery.get(body.data.username);
|
||||||
|
|
||||||
|
const emailQuery = db.query(`SELECT COUNT(*) as count FROM users WHERE email = ?1`);
|
||||||
|
const checkEmail = emailQuery.get(body.data.email);
|
||||||
|
|
||||||
|
const errors = [];
|
||||||
|
if(checkUsername.count !== 0)
|
||||||
|
errors.push({ path: ['username'], message: "Ce nom d'utilisateur est déjà utilisé" });
|
||||||
|
if(checkEmail.count !== 0)
|
||||||
|
errors.push({ path: ['email'], message: "Cette adresse mail est déjà utilisée" });
|
||||||
|
|
||||||
|
if(errors.length > 0)
|
||||||
|
throw createError({ status: 406, message: "duplicates", data: errors });
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const hash = await Bun.password.hash(body.data.password);
|
||||||
|
const registration = db.query(`INSERT INTO users(username, email, hash) VALUES(?1, ?2, ?3)`);
|
||||||
|
const result = registration.get(body.data.username, body.data.email, hash);
|
||||||
|
|
||||||
|
setResponseStatus(e, 201, "Created");
|
||||||
|
return { success: true };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export default defineEventHandler(async (e) => {
|
||||||
|
});
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export default defineEventHandler(() => 'Hello World!');
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export default defineEventHandler(() => 'Hello World!');
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export default defineEventHandler((...args) => console.log(...args));
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export default defineEventHandler(() => 'Hello World!');
|
|
||||||
Loading…
Reference in New Issue