Add change password feature
This commit is contained in:
@@ -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 }) => {
|
||||
|
||||
@@ -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,
|
||||
}));
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user