added function to change user password with the admin panel

This commit is contained in:
2025-09-03 14:10:42 +02:00
parent 423075e746
commit b8f13a37fd
5 changed files with 163 additions and 8 deletions

View File

@@ -0,0 +1,95 @@
import React from "react";
import { Button, Card, Field, Input, Stack } from "@chakra-ui/react";
import { changePW } from "@/utils/userActions";
type ChangePWformProps = {
onClose: () => void;
alert: (
status: "success" | "error",
message: string,
description: string
) => void;
username: string;
};
const ChangePWform: React.FC<ChangePWformProps> = ({
onClose,
alert,
username,
}) => {
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4">
<Card.Root maxW="sm">
<Card.Header>
<Card.Title>Passwort ändern</Card.Title>
<Card.Description>
Füllen Sie das folgende Formular aus, um das Passwort zu ändern.
</Card.Description>
</Card.Header>
<Card.Body>
<Stack gap="4" w="full">
<Field.Root>
<Field.Label>Neues Passwort</Field.Label>
<Input
id="new_password"
type="password"
placeholder="Neues Passwort"
/>
</Field.Root>
<Field.Root>
<Field.Label>Neues Passwort widerholen</Field.Label>
<Input
id="confirm_new_password"
type="password"
placeholder="Wiederholen Sie das neue Passwort"
/>
</Field.Root>
</Stack>
</Card.Body>
<Card.Footer justifyContent="flex-end" gap="2">
<Button variant="outline" onClick={onClose}>
Abbrechen
</Button>
<Button
variant="solid"
onClick={async () => {
const newPassword =
(
document.getElementById("new_password") as HTMLInputElement
)?.value.trim() || "";
const confirmNewPassword =
(
document.getElementById(
"confirm_new_password"
) as HTMLInputElement
)?.value.trim() || "";
if (!newPassword || newPassword !== confirmNewPassword) return;
const res = await changePW(newPassword, username);
if (res.success) {
alert(
"success",
"Passwort geändert",
"Das Passwort wurde erfolgreich geändert."
);
onClose();
} else {
alert(
"error",
"Fehler",
"Das Passwort konnte nicht geändert werden."
);
onClose();
}
}}
>
Ändern
</Button>
</Card.Footer>
</Card.Root>
</div>
);
};
export default ChangePWform;

View File

@@ -18,6 +18,7 @@ import { handleDelete, handleEdit } from "@/utils/userActions";
import MyAlert from "./myChakra/MyAlert"; import MyAlert from "./myChakra/MyAlert";
import AddForm from "./AddForm"; import AddForm from "./AddForm";
import { formatDateTime } from "@/utils/userFuncs"; import { formatDateTime } from "@/utils/userFuncs";
import ChangePWform from "./ChangePWform";
type User = { type User = {
id: number; id: number;
@@ -36,6 +37,8 @@ const UserTable: React.FC = () => {
const [errorDsc, setErrorDsc] = useState(""); const [errorDsc, setErrorDsc] = useState("");
const [reload, setReload] = useState(false); const [reload, setReload] = useState(false);
const [addForm, setAddForm] = useState(false); const [addForm, setAddForm] = useState(false);
const [changePWform, setChangePWform] = useState(false);
const [changeUsr, setChangeUsr] = useState("");
const setError = ( const setError = (
status: "error" | "success", status: "error" | "success",
@@ -57,6 +60,11 @@ const UserTable: React.FC = () => {
); );
}; };
const handlePasswordChange = (username: string) => {
setChangeUsr(username);
setChangePWform(true);
};
useEffect(() => { useEffect(() => {
const fetchUsers = async () => { const fetchUsers = async () => {
setIsLoading(true); setIsLoading(true);
@@ -139,6 +147,16 @@ const UserTable: React.FC = () => {
<Heading marginBottom={4} size="md"> <Heading marginBottom={4} size="md">
Benutzer Benutzer
</Heading> </Heading>
{changePWform && (
<ChangePWform
onClose={() => {
setChangePWform(false);
setReload(!reload);
}}
alert={setError}
username={changeUsr}
/>
)}
{isError && ( {isError && (
<MyAlert <MyAlert
status={errorStatus} status={errorStatus}
@@ -172,7 +190,7 @@ const UserTable: React.FC = () => {
<strong>Benutzername</strong> <strong>Benutzername</strong>
</Table.ColumnHeader> </Table.ColumnHeader>
<Table.ColumnHeader> <Table.ColumnHeader>
<strong>Passwort</strong> <strong>Passwort ändern</strong>
</Table.ColumnHeader> </Table.ColumnHeader>
<Table.ColumnHeader> <Table.ColumnHeader>
<strong>Rolle</strong> <strong>Rolle</strong>
@@ -198,12 +216,9 @@ const UserTable: React.FC = () => {
/> />
</Table.Cell> </Table.Cell>
<Table.Cell> <Table.Cell>
<Input <Button onClick={() => handlePasswordChange(user.username)}>
onChange={(e) => Passwort ändern
handleInputChange(user.id, "password", e.target.value) </Button>
}
value={user.password}
/>
</Table.Cell> </Table.Cell>
<Table.Cell> <Table.Cell>
<Input <Input

View File

@@ -73,6 +73,26 @@ export const createUser = async (
} }
}; };
export const changePW = async (newPassword: string, username: string) => {
try {
const response = await fetch(`http://localhost:8002/api/changePWadmin`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${Cookies.get("token")}`,
},
body: JSON.stringify({ newPassword, username }),
});
if (!response.ok) {
throw new Error("Failed to change password");
}
return { success: true };
} catch (error) {
console.error("Error changing password:", error);
return { success: false };
}
};
export const deleteLoan = async (loanId: number) => { export const deleteLoan = async (loanId: number) => {
try { try {
const response = await fetch( const response = await fetch(

View File

@@ -18,6 +18,7 @@ import {
getAllItems, getAllItems,
deleteItemID, deleteItemID,
createItem, createItem,
changeUserPassword,
} from "../services/database.js"; } from "../services/database.js";
import { authenticate, generateToken } from "../services/tokenService.js"; import { authenticate, generateToken } from "../services/tokenService.js";
const router = express.Router(); const router = express.Router();
@@ -276,4 +277,17 @@ router.post("/createItem", authenticate, async (req, res) => {
return res.status(500).json({ message: "Failed to create item" }); return res.status(500).json({ message: "Failed to create item" });
}); });
router.post("/changePWadmin", authenticate, async (req, res) => {
const newPassword = req.body.newPassword;
if (!newPassword) {
return res.status(400).json({ message: "New password is required" });
}
const result = await changeUserPassword(req.body.username, newPassword);
if (result.success) {
return res.status(200).json({ message: "Password changed successfully" });
}
return res.status(500).json({ message: "Failed to change password" });
});
export default router; export default router;

View File

@@ -327,7 +327,9 @@ export const loginAdmin = async (username, password) => {
}; };
export const getAllUsers = async () => { export const getAllUsers = async () => {
const [result] = await pool.query("SELECT * FROM users"); const [result] = await pool.query(
"SELECT id, username, role, entry_created_at FROM users"
);
if (result.length > 0) return { success: true, data: result }; if (result.length > 0) return { success: true, data: result };
return { success: false }; return { success: false };
}; };
@@ -382,3 +384,12 @@ export const createItem = async (item_name, can_borrow_role) => {
if (result.affectedRows > 0) return { success: true }; if (result.affectedRows > 0) return { success: true };
return { success: false }; return { success: false };
}; };
export const changeUserPassword = async (username, newPassword) => {
const [result] = await pool.query(
"UPDATE users SET password = ? WHERE username = ?",
[newPassword, username]
);
if (result.affectedRows > 0) return { success: true };
return { success: false };
};