Add change password feature
This commit is contained in:
@@ -158,6 +158,45 @@ const app = new Elysia()
|
|||||||
.execute();
|
.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 -------------------------------------------
|
// --- MARK: USER MANAGEMENT -------------------------------------------
|
||||||
|
|
||||||
.get("/user/:userId", async ({ db, params: { userId }, user }) => {
|
.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({
|
export const userCache = Effect.runSync(Cache.make({
|
||||||
capacity: Infinity,
|
capacity: Infinity,
|
||||||
timeToLive: Duration.infinity,
|
timeToLive: Duration.days(1),
|
||||||
lookup: userLookup,
|
lookup: userLookup,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const pieceCache = Effect.runSync(Cache.make({
|
export const pieceCache = Effect.runSync(Cache.make({
|
||||||
capacity: Infinity,
|
capacity: Infinity,
|
||||||
timeToLive: Infinity,
|
timeToLive: Duration.days(1),
|
||||||
lookup: pieceLookup,
|
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() {
|
export function Settings() {
|
||||||
return (
|
return (
|
||||||
<div className="p-4 overflow-y-auto grow flex flex-col items-center justify-center gap-4">
|
<div className="p-4 overflow-y-auto grow flex flex-wrap items-start gap-4">
|
||||||
<div>Tutaj by były ustawienia, gdyby były.</div>
|
<PasswordChangeCard />
|
||||||
</div>
|
</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