Add change password feature

This commit is contained in:
Szymon Nowakowski
2024-12-25 20:51:44 +01:00
parent 46763a95c1
commit 8ef3572e79
3 changed files with 136 additions and 4 deletions

View File

@@ -158,6 +158,45 @@ const app = new Elysia()
.execute();
})
.post("/change-password", async ({ db, body: { username, currentPassword, newPassword }, set }) => {
const user = await db
.selectFrom("User")
.selectAll()
.where("username", "=", username)
.executeTakeFirst();
if (user === undefined) {
return error("Unauthorized", "Invalid username or password");
}
const valid = await Bun.password.verify(currentPassword, user.password);
if (!valid) {
return error("Unauthorized", "Invalid username or password");
}
const password = await Bun.password.hash(newPassword);
const res = await db
.updateTable("User")
.set({ password })
.where("username", "=", username)
.returningAll()
.execute();
if (res.length === 0) {
return error("Unauthorized", "Invalid username or password");
}
set.status = "No Content";
}, {
body: t.Object({
username: t.String({ minLength: 1 }),
currentPassword: t.String({ minLength: 1 }),
newPassword: t.String({ minLength: 1 }),
}),
})
// --- MARK: USER MANAGEMENT -------------------------------------------
.get("/user/:userId", async ({ db, params: { userId }, user }) => {

View File

@@ -105,12 +105,12 @@ export const pieceLookup = (pieceId: PieceId) => pipe(
export const userCache = Effect.runSync(Cache.make({
capacity: Infinity,
timeToLive: Duration.infinity,
timeToLive: Duration.days(1),
lookup: userLookup,
}));
export const pieceCache = Effect.runSync(Cache.make({
capacity: Infinity,
timeToLive: Infinity,
timeToLive: Duration.days(1),
lookup: pieceLookup,
}));

View File

@@ -1,7 +1,100 @@
import { client } from "@/client";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { useStore } from "@/hooks/useStore";
import { Label } from "@radix-ui/react-label";
import { Loader2 } from "lucide-react";
import { FormEventHandler, useId, useState } from "react";
export function Settings() {
return (
<div className="p-4 overflow-y-auto grow flex flex-col items-center justify-center gap-4">
<div>Tutaj by były ustawienia, gdyby były.</div>
<div className="p-4 overflow-y-auto grow flex flex-wrap items-start gap-4">
<PasswordChangeCard />
</div>
);
}
function PasswordChangeCard() {
const [currentPassword, setCurrentPassword] = useState("");
const [newPassword1, setNewPassword1] = useState("");
const [newPassword2, setNewPassword2] = useState("");
const currentPasswordId = useId();
const newPassword1Id = useId();
const newPassword2Id = useId();
const [isLoading, setIsLoading] = useState(false);
const user = useStore(store => store.user);
const onSubmit: FormEventHandler<HTMLFormElement> = async (e) => {
e.preventDefault();
try {
setIsLoading(true);
const { error } = await client["change-password"].post({
username: user!.username,
currentPassword,
newPassword: newPassword1,
});
if (error !== null) {
console.error(error.value);
return;
}
} finally {
setIsLoading(false);
}
};
return (
<form onSubmit={onSubmit}>
<Card>
<CardHeader>
<CardTitle>Zmiana hasła</CardTitle>
</CardHeader>
<CardContent>
<Label htmlFor={currentPasswordId}>Obecne hasło</Label>
<Input
id={currentPasswordId}
className="w-[32ch]"
type="password"
autoComplete="current-password"
value={currentPassword}
required
onChange={(e) => setCurrentPassword(e.target.value)}
/>
<Label htmlFor={currentPasswordId}>Nowe hasło</Label>
<Input
id={newPassword1Id}
className="w-[32ch]"
type="password"
autoComplete="new-password"
value={newPassword1}
required
onChange={(e) => setNewPassword1(e.target.value)}
/>
<Label htmlFor={currentPasswordId}>Potwierdź hasło</Label>
<Input
id={newPassword2Id}
className="w-[32ch]"
type="password"
autoComplete="new-password"
value={newPassword2}
required
onChange={(e) => setNewPassword2(e.target.value)}
/>
</CardContent>
<CardFooter className="flex-row justify-end">
<Button type="submit" disabled={isLoading || newPassword1 !== newPassword2}>
{isLoading && <Loader2 className="animate-spin" />}
Zmień hasło
</Button>
</CardFooter>
</Card>
</form>
);
}