Skip to content

Commit

Permalink
admin add account
Browse files Browse the repository at this point in the history
  • Loading branch information
squi-ddy committed Oct 25, 2024
1 parent 0127b9d commit 5c23e43
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 6 deletions.
39 changes: 39 additions & 0 deletions backend/src/api/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { TransactionTable } from "types/transaction"
import { UserTable, UserType } from "types/user"
import Archiver from "archiver"
import { objectsToCsv } from "utils"
import { getRandom } from "getRandom"

const router = Router()
router.use((req, res, next) => {
Expand Down Expand Up @@ -166,4 +167,42 @@ router.get("/dump", async (_, res) => {
.finalize()
})

router.post("/addUser", async (req, res) => {
const name: unknown = req.body.name
const username: unknown = req.body.username
const password: unknown = req.body.email

if (!name) {
return res.status(400).json({ message: "Name is required" })
}

if (typeof name !== "string") {
return res.status(400).json({ message: "Name must be a string" })
}

if (!username) {
return res.status(400).json({ message: "Username is required" })
}

if (typeof username !== "string") {
return res.status(400).json({ message: "Username must be a string" })
}

if (!password) {
return res.status(400).json({ message: "Password is required" })
}

if (typeof password !== "string") {
return res.status(400).json({ message: "Password must be a string" })
}

// add user
await sql`
INSERT INTO Users (uid, name, username, password, is_admin, is_booth, balance)
VALUES (${getRandom()}, ${name}, ${username}, ${password}, FALSE, TRUE, 0)
`

res.json({ message: "User added" })
})

export default router
13 changes: 13 additions & 0 deletions frontend/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,16 @@ export async function getTopupHistory(): Promise<TopupHistoryDetails[] | null> {
return null;
}
}

export async function addUser(
name: string,
username: string,
password: string,
): Promise<boolean> {
try {
const resp = await fetcher.post("/admin/addUser");
return true;
} catch (error) {
return false;
}
}
5 changes: 5 additions & 0 deletions frontend/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import AdminPage from "./routes/admin_view";
import UserProvider from "./UserProvider";
import StudentTransactionHistoryPage from "./routes/student_transactions_view";
import StudentTopupHistoryPage from "./routes/student_topups_view";
import AdminAddPage from "./routes/admin_add_account";

const router = createBrowserRouter([
{
Expand Down Expand Up @@ -70,6 +71,10 @@ const router = createBrowserRouter([
path: "/admin",
element: <AdminPage />,
},
{
path: "/admin/add",
element: <AdminAddPage />,
},
],
},
]);
Expand Down
107 changes: 107 additions & 0 deletions frontend/src/routes/admin_add_account.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { Button, Container, Stack, Typography, TextField } from "@mui/material";
import Header from "../components/header";
import { useContext, useEffect, useRef } from "react";
import { useNavigate } from "react-router-dom";
import { addUser } from "../api";
import { UserType } from "../types/user";
import { UserContext } from "../UserProvider";

export default function AdminAddPage() {
const accountUsername = useRef("");
const accountName = useRef("");
const accountPassword = useRef("");

const navigate = useNavigate();

const { user } = useContext(UserContext);

useEffect(() => {
if (user === undefined) {
return;
} else if (user === null) {
return navigate("/");
} else if (user.type === UserType.STUDENT) {
navigate("/student");
} else if (user.type === UserType.ADMIN) {
return;
} else if (user.type === UserType.BOOTH) {
navigate("/booth");
}
}, [user]);

return (
<Container maxWidth="sm">
<Header />
<Stack
direction="column"
spacing={2}
sx={{
justifyContent: "center",
alignItems: "center",
}}
>
<Typography variant="body1">Add Booth Account</Typography>
<TextField
id="admin-add-acct-username"
label="Account Username"
variant="filled"
onChange={(e) => {
accountUsername.current = e.target.value;
}}
/>
<TextField
id="admin-add-acct-password"
label="Account Password"
variant="filled"
type="password"
onChange={(e) => {
accountPassword.current = e.target.value;
}}
/>
<TextField
id="admin-add-acct-name"
label="Account Name"
variant="filled"
onChange={(e) => {
accountName.current = e.target.value;
}}
/>
<Button
variant="contained"
size="large"
onClick={async () => {
if (
accountUsername.current === "" ||
accountPassword.current === "" ||
accountName.current === ""
) {
alert("Please fill in all fields.");
return;
}
const resp = await addUser(
accountName.current,
accountUsername.current,
accountPassword.current,
);
if (!resp) {
alert("Failed to add account.");
} else {
alert("Account added successfully.");
}
}}
>
Submit
</Button>
<Button
variant="outlined"
color="white"
onClick={() => {
navigate("/admin");
}}
>
Back
</Button>
</Stack>
</Container>
);
}
9 changes: 9 additions & 0 deletions frontend/src/routes/admin_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ export default function AdminPage() {
>
Database Dump
</Button>
<Button
variant="contained"
size="large"
onClick={() => {
navigate("/admin/add");
}}
>
Add Account
</Button>
<Button
variant="contained"
size="large"
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/routes/student_main_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export default function StudentMainPage() {
return;
}
navigate("/student/payment", {
state: { amount: amt.toFixed(2) },
state: { amount: amt.toFixed(2), time: new Date() },
});
}}
>
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/routes/student_payment_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,18 @@ export default function StudentPaymentPage() {
const { user } = useContext(UserContext);
const [token, setToken] = useState<TransactionToken | null>(null);
const amount: string | undefined = location.state.amount;
const time: Date | undefined = location.state.time;

useEffect(() => {
if (!amount) {
navigate("/student");
return;
}
if (!time || new Date().getTime() - time.getTime() > 10000) {
// invalid
navigate("/student");
return;
}
if (user === undefined) {
return;
} else if (user === null) {
Expand Down
15 changes: 13 additions & 2 deletions frontend/src/routes/student_topups_view.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Container, Stack, Typography, Card, CardContent, Button } from "@mui/material";
import {
Container,
Stack,
Typography,
Card,
CardContent,
Button,
} from "@mui/material";
import { useNavigate } from "react-router-dom";
import Header from "../components/header";
import { useContext, useEffect, useState } from "react";
Expand Down Expand Up @@ -57,7 +64,11 @@ export default function StudentTopupHistoryPage() {
<Typography variant="body1">Topup History</Typography>
{topupDetails.length > 0 ? (
topupDetails.map((topup, idx) => (
<Card variant="outlined" key={idx} sx={{ width: "100%", borderColor: "#ffffff" }}>
<Card
variant="outlined"
key={idx}
sx={{ width: "100%", borderColor: "#ffffff" }}
>
<CardContent>
<Typography variant="h5">
${new Decimal(topup.amount).toFixed(2)}
Expand Down
15 changes: 13 additions & 2 deletions frontend/src/routes/student_transactions_view.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Container, Stack, Typography, Card, CardContent, Button } from "@mui/material";
import {
Container,
Stack,
Typography,
Card,
CardContent,
Button,
} from "@mui/material";
import { useNavigate } from "react-router-dom";
import Header from "../components/header";
import { useContext, useEffect, useState } from "react";
Expand Down Expand Up @@ -57,7 +64,11 @@ export default function StudentTransactionHistoryPage() {
<Typography variant="body1">Transaction History</Typography>
{transactionDetails.length > 0 ? (
transactionDetails.map((transaction, idx) => (
<Card variant="outlined" key={idx} sx={{ width: "100%", borderColor: "#ffffff" }}>
<Card
variant="outlined"
key={idx}
sx={{ width: "100%", borderColor: "#ffffff" }}
>
<CardContent>
<Typography variant="h5">
${new Decimal(transaction.amount).toFixed(2)}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/theme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ declare module "@mui/material/Button" {
}
}

declare module '@mui/material/Typography' {
declare module "@mui/material/Typography" {
interface TypographyPropsVariantOverrides {
italic1: true;
}
Expand Down

0 comments on commit 5c23e43

Please sign in to comment.