Add: User Logging in

This commit is contained in:
Donatas Kirda 2024-05-16 13:28:24 +03:00
parent a34ed38800
commit eea87823d9
Signed by: bloodwiing
GPG Key ID: 63020D8D3F4A164F
9 changed files with 212 additions and 49 deletions

View File

@ -0,0 +1,45 @@
<script>
/**
* @type {string}
*/
export let name;
/**
* @type {string}
*/
export let labelName;
/**
* @type {'text' | 'password'}
*/
export let type;
/**
* @type {'username' | 'new-password' | 'current-password'}
*/
export let autocomplete;
/**
* @type {string | null}
*/
export let value = null;
/** @type {import("svelte/elements").FormEventHandler<HTMLInputElement>} */
function onInput(e) {
value = e.target && 'value' in e.target && e.target?.value ? String(e.target?.value) : null;
}
</script>
<style lang="scss">
.pair {
display: flex;
flex-flow: column nowrap;
gap: 4px;
width: 100%;
}
</style>
<div class="pair">
<label class="noSelect" for="field-{name}">{labelName}</label>
<input {type} {name} id="field-{name}" {autocomplete} required on:input={onInput}>
</div>

View File

@ -0,0 +1,73 @@
<script>
import Glowfx from "$comp/fx/glowfx.svelte";
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
/**
* @type {string}
*/
export let action;
/**
* @type {'post'}
*/
export let method = 'post';
/**
* @type {string}
*/
export let formName;
/**
* @type {string}
*/
export let submitText;
</script>
<style lang="scss">
h1 {
font-size: 2.5rem;
}
.name {
display: flex;
flex-flow: column nowrap;
gap: 8px;
width: 100%;
align-items: center;
}
.items {
display: flex;
flex-flow: column nowrap;
width: 100%;
gap: 32px;
}
button {
font-size: 1.1rem;
letter-spacing: 0em;
transition: letter-spacing 0.2s cubic-bezier(.18,.89,.32,1.28);
&:hover {
letter-spacing: 0.1em;
}
}
</style>
<form class="entryForm" {action} {method} on:submit={(e) => {dispatch('submit', e);}} {...$$restProps}>
<div class="name">
<h1 class="typeHead noSelect">{formName}</h1>
<slot name="belowName" />
</div>
<div class="items">
<slot />
</div>
<Glowfx borderRadius={4}>
<button class="button typeTitle noSelect" type="submit">{submitText}</button>
</Glowfx>
</form>

View File

@ -131,7 +131,7 @@ export async function getPost(post_id, opts = {}) {
}
}();
const category_guess = await getCategoryCached(sql, post['category_id']);
const category_guess = await getCategoryCached(post['category_id']);
if (Object.hasOwn(category_guess, 'error')) {
return {
error: true,

View File

@ -134,3 +134,47 @@ export async function createUser(username, password) {
success: true,
};
}
/**
* @param {string} username
* @param {string} password
* @returns {Promise<import('$types/status').Success | import('$types/status').Error>}
*/
export async function createUserSession(username, password) {
const select = sql`
SELECT password, id
FROM doki8902.user
WHERE username = ${ username };`;
const result = await select;
if (result.length == 0) {
return {
error: true,
msg: 'Username or password is incorrect',
};
}
const hashedPassword = result[0]['password'];
const isMatch = await verify(hashedPassword, password);
if (!isMatch) {
return {
error: true,
msg: 'Username or password is incorrect',
};
}
const insert = sql`
INSERT INTO doki8902.user_session (user_id)
VALUES (${ result[0]['id'] })
RETURNING token;`;
const token = await insert;
return {
success: true,
result: token[0]['token'],
};
}

View File

@ -0,0 +1,25 @@
import { createUserSession } from "$lib/server/db/user";
/** @type {import("@sveltejs/kit").Action} */
async function POST({ request, cookies }) {
if (request.method !== 'POST') {
return;
}
const data = await request.formData();
const username = data.get('username')?.toString();
const password = data.get('password')?.toString();
if (!username || !password) {
return;
}
const result = await createUserSession(username, password);
console.log(result);
}
/** @type {import("@sveltejs/kit").Actions} */
export let actions = {
default: POST
};

View File

@ -0,0 +1,11 @@
<script>
import Entryfield from "$comp/entry/entryfield.svelte";
import Entryform from "$comp/entry/entryform.svelte";
</script>
<Entryform action="/login" formName="Login" submitText="enter">
<a href="/register" slot="belowName">New here?</a>
<Entryfield name="username" labelName="Username" type="text" autocomplete="username"></Entryfield>
<Entryfield name="password" labelName="Password" type="password" autocomplete="current-password"></Entryfield>
</Entryform>

View File

@ -11,6 +11,10 @@ export function load({ cookies }) {
/** @type {import('./$types').Action} */
async function POST({ request }) {
if (request.method !== 'POST') {
return;
}
const data = await request.formData();
const username = data.get('username')?.toString();
const password = data.get('password')?.toString();

View File

@ -1,5 +1,6 @@
<script>
import Glowfx from "$comp/fx/glowfx.svelte";
import Entryfield from "$comp/entry/entryfield.svelte";
import Entryform from "$comp/entry/entryform.svelte";
/** @type {string} */
let password;
@ -14,51 +15,10 @@
}
</script>
<style>
h1 {
font-size: 2.5rem;
}
<Entryform action="/register" formName="Register" submitText="go!" on:submit={(e) => {submitForm(e.detail);}}>
<a href="/login" slot="belowName">Already a member?</a>
.items {
display: flex;
flex-flow: column nowrap;
width: 100%;
gap: 32px;
}
.pair {
display: flex;
flex-flow: column nowrap;
gap: 4px;
width: 100%;
}
button {
font-size: 1.3rem;
letter-spacing: 0.2em;
}
</style>
<form class="entryForm" action="/register" method="post" on:submit={submitForm}>
<h1 class="typeHead noSelect">Register</h1>
<div class="items">
<div class="pair">
<label class="noSelect" for="username">Username</label>
<input type="text" name="username" id="username" autocomplete="username" required>
</div>
<div class="pair">
<label class="noSelect" for="password">Password</label>
<input type="password" name="password" id="password" autocomplete="new-password" required bind:value={password}>
</div>
<div class="pair">
<label class="noSelect" for="repeatPassword">Repeat Password</label>
<input type="password" id="repeatPassword" autocomplete="new-password" required bind:value={repeatPassword}>
</div>
</div>
<Glowfx borderRadius={4}>
<button class="button typeTitle noSelect" type="submit">GO!</button>
</Glowfx>
</form>
<Entryfield name="username" labelName="Username" type="text" autocomplete="username"></Entryfield>
<Entryfield name="password" labelName="Password" type="password" autocomplete="new-password" bind:value={password}></Entryfield>
<Entryfield name="repeatPassword" labelName="Confirm Password" type="password" autocomplete="new-password" bind:value={repeatPassword}></Entryfield>
</Entryform>

View File

@ -5,4 +5,5 @@ export type Error = {
export type Success = {
success: boolean,
result?: object,
};