login complete (fr)

This commit is contained in:
2026-01-15 01:35:44 +00:00
parent 6746925a05
commit 1a7e3bb02c
6 changed files with 102 additions and 25 deletions

View File

@@ -15,11 +15,26 @@ const props = defineProps({
type: Boolean, type: Boolean,
required: false, required: false,
default: true default: true
},
logged_in: {
type: Boolean,
required: false,
default: false
} }
}) })
function logout() {
return fetch("/logout").then(
(response) => {
if (response.ok) {
window.location.reload;
}
}
)
}
</script> </script>
@@ -33,10 +48,10 @@ const props = defineProps({
<!----<UDropdownMenu :items="ui_colors_dropdown"> <!----<UDropdownMenu :items="ui_colors_dropdown">
<UButton icon="lucide:palette" variant="ghost" color="neutral" /> <UButton icon="lucide:palette" variant="ghost" color="neutral" />
</UDropdownMenu>--> </UDropdownMenu>-->
<UButton icon="lucide:settings" variant="ghost" color="neutral" :to="props.settings_link ? '/settings/general' : undefined" v-if="loggedIn" /> <UButton icon="lucide:settings" variant="ghost" color="neutral" :to="props.settings_link ? '/settings/general' : undefined" v-if="props.logged_in" />
<UModal :ui="{ overlay: 'bg-black opacity-75', content: 'bg-zinc-950 py-3'}" v-model:open="logout_prompt"> <UModal :ui="{ overlay: 'bg-black opacity-75', content: 'bg-zinc-950 py-3'}" v-model:open="logout_prompt">
<UButton icon="lucide:log-out" variant="ghost" color="error" class="hover:cursor-pointer" v-if="loggedIn" /> <UButton icon="lucide:log-out" variant="ghost" color="error" class="hover:cursor-pointer" v-if="props.logged_in" />
<template #content> <template #content>
<div class="p-4 text-center"> <div class="p-4 text-center">
@@ -46,13 +61,13 @@ const props = defineProps({
</p> </p>
<div class="flex gap-4 flex-col justify-end"> <div class="flex gap-4 flex-col justify-end">
<UButton class="w-full hover:cursor-pointer dark:bg-zinc-900 hover:dark:bg-zinc-800 active:dark:bg-black" variant="soft" color="neutral" @click="logout_prompt = false">No</UButton> <UButton class="w-full hover:cursor-pointer dark:bg-zinc-900 hover:dark:bg-zinc-800 active:dark:bg-black" variant="soft" color="neutral" @click="logout_prompt = false">No</UButton>
<UButton class="w-full" variant="soft" color="error" to="/logout">Yes</UButton> <UButton class="w-full" variant="soft" color="error" loading-auto @click="logout()">Yes</UButton>
</div> </div>
</div> </div>
</template> </template>
</UModal> </UModal>
<UButton icon="lucide:log-in" variant="soft" color="success" v-if="!loggedIn" to="/login">Login</UButton> <UButton icon="lucide:log-in" variant="soft" color="success" v-if="!props.logged_in" to="/login">Login</UButton>
</template> </template>
</UHeader> </UHeader>
</template> </template>

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
const { loggedIn } = useUserSession()
const video = ref(0); const video = ref(0);
const url = ref(""); const url = ref("");
const in_url = ref(""); const in_url = ref("");
@@ -29,7 +31,7 @@
</script> </script>
<template> <template>
<MainHeader/> <MainHeader :logged_in="loggedIn"/>
<div class="justify-center flex flex-col max-sm:mt-5 max-md:mt-7 max-lg:mt-10 lg:mt-15 mb-4 w-full"> <div class="justify-center flex flex-col max-sm:mt-5 max-md:mt-7 max-lg:mt-10 lg:mt-15 mb-4 w-full">
<h1 class="inter font-bold text-center mt-3 mb-3 text-white white-glow max-sm:text-5xl sm:text-6xl md:text-7xl xl:text-8xl rgb-text">Youtube to MP3</h1> <h1 class="inter font-bold text-center mt-3 mb-3 text-white white-glow max-sm:text-5xl sm:text-6xl md:text-7xl xl:text-8xl rgb-text">Youtube to MP3</h1>

View File

@@ -35,7 +35,24 @@ const schema = z.object({
type Schema = z.output<typeof schema> type Schema = z.output<typeof schema>
function onSubmit(payload: FormSubmitEvent<Schema>) { function onSubmit(payload: FormSubmitEvent<Schema>) {
console.log('Submitted', payload) return fetch("/login", {
method: "POST",
headers: {
"Content-Type" : "application/json"
},
body: JSON.stringify({
email: payload.data.email,
password: payload.data.password
})
}).then((response) => {
if (response.ok)
window.location.href = "/";
else if (response.status == 401) {
wrong_login.value = true;
// show for 5 seconds
setTimeout(() => wrong_login.value = false, 5000);
}
})
} }
</script> </script>
@@ -50,16 +67,21 @@ function onSubmit(payload: FormSubmitEvent<Schema>) {
:submit="{ :submit="{
label: 'Login', label: 'Login',
class: 'rounded-full', class: 'rounded-full',
variant: 'soft' variant: 'soft',
loadingAuto: true
}" }"
@submit="onSubmit"
> >
<template #validation v-if="wrong_login"> <template #validation>
<UAlert color="error" <Transition name="slide-fade">
<UAlert v-if="wrong_login"
color="error"
icon="lucide:circle-x" icon="lucide:circle-x"
variant="soft" variant="soft"
:ui="{ icon: 'self-center' }" :ui="{ icon: 'self-center' }"
title="Incorrect Login" title="Incorrect Login"
description="Either your e-mail or your password are wrong."/> description="Either your e-mail or your password are wrong."/>
</Transition>
</template> </template>
</UAuthForm> </UAuthForm>
</UPageCard> </UPageCard>
@@ -68,3 +90,19 @@ function onSubmit(payload: FormSubmitEvent<Schema>) {
</template> </template>
<style>
.slide-fade-enter-from {
opacity: 0;
transform: translateY(-10px);
}
.slide-fade-enter-active {
transition: opacity 0.3s, transform 0.3s;
}
.slide-fade-leave-to {
opacity: 0;
transform: translateY(-10px);
}
.slide-fade-leave-active {
transition: opacity 0.3s, transform 0.3s;
}
</style>

View File

@@ -8,6 +8,10 @@ import aiomysql
import bcrypt import bcrypt
#import asyncio #import asyncio
# In this FastAPI example, we skip BaseModel verification cause NuxtJS does that for us
# In other words, this backend only recieves requests from nuxt js backend
# So we can trust it
class db: class db:
pool = None pool = None
@@ -49,7 +53,7 @@ class register_model(BaseModel):
async def create_user(req: Request): async def create_user(req: Request):
body = await req.json() body = await req.json()
body = register_model(**body) #body = register_model(**body)
# Auto exceptions give more verbose to Nuxt. # Auto exceptions give more verbose to Nuxt.
#try: #try:
@@ -57,7 +61,7 @@ async def create_user(req: Request):
#except ValidationError: #except ValidationError:
# raise HTTPException(status_code=400, detail="Missing / invalid arguments") # raise HTTPException(status_code=400, detail="Missing / invalid arguments")
body.password = bcrypt.hashpw(body.password.encode(), bcrypt.gensalt()).decode() body["password"] = bcrypt.hashpw(body["password"].encode(), bcrypt.gensalt()).decode()
async with db.pool.acquire() as conn: async with db.pool.acquire() as conn:
async with conn.cursor() as cur: async with conn.cursor() as cur:
await cur.execute("INSERT INTO users (`first_name`,`last_name`,`email`,`password`) VALUES (%s,%s,%s,%s)", (body.first_name, body.last_name, body.email, body.password)) await cur.execute("INSERT INTO users (`first_name`,`last_name`,`email`,`password`) VALUES (%s,%s,%s,%s)", (body.first_name, body.last_name, body.email, body.password))
@@ -71,12 +75,13 @@ class login_data(BaseModel):
async def login_endpoint(req: Request): async def login_endpoint(req: Request):
body = await req.json() body = await req.json()
#print(body)
try: try:
login = login_data(**body) #login = login_data(**body)
# ensure it's only email and password # ensure it's only email and password
user_data = await fetch_user_info(body["email"]) user_data = await fetch_user_info(body["email"])
if (user_data is None): if (user_data is None):
raise HTTPException(status_code=401) raise HTTPException(status_code=401, detail="User doesn't exist")
else: else:
pwd = user_data.get("password") pwd = user_data.get("password")
if (bcrypt.checkpw(body["password"].encode(), user_data.get("password").encode())): if (bcrypt.checkpw(body["password"].encode(), user_data.get("password").encode())):

View File

@@ -5,7 +5,7 @@ export default defineEventHandler(async (event) => {
if ( !body.email || !body.password ) if ( !body.email || !body.password )
throw createError({ statusCode: 400, message: "Bad form. Use e-mail and password" }) throw createError({ statusCode: 400, message: "Bad form. Use e-mail and password" })
console.log(body)
const req = await fetch(conf.fastapi_url + "/login", const req = await fetch(conf.fastapi_url + "/login",
{ {
method: "POST", method: "POST",
@@ -13,11 +13,27 @@ export default defineEventHandler(async (event) => {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ body: JSON.stringify({
email: body.email!, email: body.email,
pwd: body.password!, password: body.password,
}) })
} }
) )
if (!req.ok) throw createError({ statusCode: req.status }) if (!req.ok) throw createError({ statusCode: req.status })
else {
const body = await req.json();
await setUserSession(event,{
user: {
name: body.first_name,
surname: body.last_name,
email: body.email
},
private: {
user_id: body.id
}
})
return;
}
}) })

View File

@@ -1,3 +1,4 @@
export default defineEventHandler((async) => { export default defineEventHandler(async (event) => {
// log them out
await clearUserSession(event);
}) })