Login System + API
This commit is contained in:
34
src/pages/api/login.ts
Normal file
34
src/pages/api/login.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { success, MissingPropertyError, MissingEntityError, ActionFailedError, InvalidDataError, error } from "../../lib/APIResponse";
|
||||
import { validatePassword } from "../../lib/Password";
|
||||
import { User } from "../../lib/User";
|
||||
import moment from "moment";
|
||||
import { encodeToken } from "../../lib/JsonWebToken";
|
||||
|
||||
/**
|
||||
* Ruft einen Nutzer anhand seiner uid aus der Datenbank ab.
|
||||
* @param param0 Die Request mit dem request body. Dieser enthält entweder eine uid mit der der Benutzer identifiziert werden kann.
|
||||
*/
|
||||
export const post: APIRoute = async ({ request }) => {
|
||||
const body = await request.json();
|
||||
|
||||
if (!body.hasOwnProperty("username") || !body.hasOwnProperty("password")) {
|
||||
return MissingPropertyError(["username", "password"]);
|
||||
}
|
||||
|
||||
const user = await User.fromUsername(body.username);
|
||||
|
||||
if (!user) {
|
||||
return error(["Invalid username or password."]);
|
||||
}
|
||||
|
||||
// Validate Password
|
||||
if (!validatePassword(user.password, body.password)) {
|
||||
return error(["Invalid username or password."]);
|
||||
}
|
||||
|
||||
const expiry = moment().add(2, "days").unix();
|
||||
const token = encodeToken({ id: user.id, uid: user.uid, exp: expiry })
|
||||
|
||||
return success({ token, expires: expiry });
|
||||
}
|
||||
43
src/pages/api/user.ts
Normal file
43
src/pages/api/user.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { success, MissingPropertyError, MissingEntityError, ActionFailedError, InvalidDataError } from "../../lib/APIResponse";
|
||||
import { User } from "../../lib/User";
|
||||
import { UserRegisterValidator, UserType, UserTypeValidator } from "../../lib/User/type";
|
||||
|
||||
/**
|
||||
* Ruft einen Nutzer anhand seiner uid aus der Datenbank ab.
|
||||
* @param param0 Die Request mit dem request body. Dieser enthält entweder eine uid mit der der Benutzer identifiziert werden kann.
|
||||
*/
|
||||
export const get: APIRoute = async ({ request }) => {
|
||||
const body = await request.json();
|
||||
|
||||
if (!body.hasOwnProperty("uid")) {
|
||||
return MissingPropertyError(["uid"]);
|
||||
}
|
||||
|
||||
const user = User.fromPublicId(body.uid);
|
||||
|
||||
if (!user) {
|
||||
return MissingEntityError("user");
|
||||
}
|
||||
|
||||
return success(user);
|
||||
}
|
||||
|
||||
export const put: APIRoute = async ({ request }) => {
|
||||
const body = await request.json();
|
||||
|
||||
const validate = UserRegisterValidator.safeParse(body);
|
||||
|
||||
if (validate.success == false) {
|
||||
return InvalidDataError(validate.error);
|
||||
}
|
||||
|
||||
const result = await User.create(body as UserType);
|
||||
|
||||
if (!result) {
|
||||
return ActionFailedError();
|
||||
}
|
||||
|
||||
return success({ uid: result.uid, id: result.id });
|
||||
}
|
||||
|
||||
17
src/pages/login.astro
Normal file
17
src/pages/login.astro
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
import moment from "moment";
|
||||
import LoginView from "../components/LoginView.svelte";
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
|
||||
const token = Astro.cookies.get("token").value;
|
||||
const expires = Astro.cookies.get("expires").number();
|
||||
|
||||
const now = moment().unix();
|
||||
if (token && now < expires) {
|
||||
return Astro.redirect("/user");
|
||||
}
|
||||
---
|
||||
|
||||
<Layout title="Login">
|
||||
<LoginView client:only></LoginView>
|
||||
</Layout>
|
||||
17
src/pages/signup.astro
Normal file
17
src/pages/signup.astro
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
import moment from "moment";
|
||||
import RegisterView from "../components/RegisterView.svelte";
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
|
||||
const token = Astro.cookies.get("token").value;
|
||||
const expires = Astro.cookies.get("expires").number();
|
||||
|
||||
const now = moment().unix();
|
||||
if (token && now < expires) {
|
||||
return Astro.redirect("/user");
|
||||
}
|
||||
---
|
||||
|
||||
<Layout title="Login">
|
||||
<RegisterView client:only></RegisterView>
|
||||
</Layout>
|
||||
63
src/pages/user/index.astro
Normal file
63
src/pages/user/index.astro
Normal file
@@ -0,0 +1,63 @@
|
||||
---
|
||||
import moment from "moment";
|
||||
import Layout from "../../layouts/Layout.astro"
|
||||
import { decodeToken } from "../../lib/JsonWebToken";
|
||||
import { User } from "../../lib/User";
|
||||
|
||||
const token = Astro.cookies.get("token").value;
|
||||
const expires = Astro.cookies.get("expires").number();
|
||||
|
||||
const now = moment().unix();
|
||||
if (!token || now > expires) {
|
||||
Astro.cookies.delete("token");
|
||||
Astro.cookies.delete("expires");
|
||||
return Astro.redirect("/login");
|
||||
}
|
||||
|
||||
const parsed = decodeToken(token);
|
||||
const user = await User.fromPublicId(parsed.uid);
|
||||
|
||||
if (!user) {
|
||||
return Astro.redirect("/login");
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
<Layout title="Dashboard">
|
||||
<div class="profile_container">
|
||||
<div><h1>Willkommen zurück <b>{user.username}</b></h1>
|
||||
<div id="searchBoxContainer" class="flex-row" style="gap: 5px; margin: 10px 0;"></div>
|
||||
</div>
|
||||
<div class="flex-column" style="gap: 10px;">
|
||||
<a href="/user/settings" class="weiterbutton">Account Details Ändern</a>
|
||||
<a href="/logout" class="weiterbutton">Ausloggen</a>
|
||||
</div>
|
||||
<div class="flex-row filter-bar" style="grid-area: 2/1/2/3; min-height: 0; gap: 20px;">
|
||||
<div class="flex-row" style="width: 100%;">
|
||||
<a onclick="addSort()" class='weiterbutton'>Filter Hinzufügen</a>
|
||||
<a onclick="window.Offset > 0 ? (() => {
|
||||
GetData(window.Offset - 1)
|
||||
})() : null" class='weiterbutton'>Vorherige Seite</a>
|
||||
<a onclick="window.Offset >= 0 ? (() => {
|
||||
GetData(window.Offset + 1)
|
||||
})() : null" class='weiterbutton'>Nächste Seite</a>
|
||||
<a onclick="window.Offset > 0 ? (() => {
|
||||
GetData(0)
|
||||
})() : null" class='weiterbutton'>Erste Seite</a>
|
||||
</div>
|
||||
<div class="flex-row" style="width: 100%;">
|
||||
<select onchange="window.GetLength = parseInt(this.value); GetData(0);">
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
<option value="75">75</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
<select onchange="window.orderDirection = this.value; GetData(0);">
|
||||
<option value="DESC">Absteigend</option>
|
||||
<option value="ASC">Aufsteigend</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class='login-container' id="items-container"></div>
|
||||
</div>
|
||||
</Layout>
|
||||
Reference in New Issue
Block a user