Skip to content

Commit 1383951

Browse files
committed
add page to create admin user
1 parent d68ba36 commit 1383951

File tree

9 files changed

+159
-6
lines changed

9 files changed

+159
-6
lines changed

UserService/src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import cors from "cors";
66
// import { firebaseConfig } from "./firebase/firebase.config";
77
// import { Socket, Server } from 'socket.io';
88
// import { Server as ServerHttp } from 'http';
9-
import { handleCreateUser, handleGetUser, handleUpdateUser } from "./user/user.controller";
9+
10+
import { handleCreateUser, handleGetUser, handleUpdateUser, handleCreateAdminUser } from "./user/user.controller";
1011
const app = express();
1112
const port = 3004;
1213
app.use(cors());
@@ -23,6 +24,7 @@ app.get("/", (req, res) => {
2324
// const db = getFirestore();
2425

2526
app.post("/user", handleCreateUser);
27+
app.post("/useradmin", handleCreateAdminUser);
2628
app.get("/user", handleGetUser);
2729
app.put("/user", handleUpdateUser);
2830

UserService/src/user/user.controller.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Request, Response } from "express";
2-
import { createUser, getUser, updateUser } from "./user.service";
2+
3+
import { createAdminUser, createUser, getUser, updateUser } from "./user.service";
34

45
export async function handleCreateUser(req: Request, res: Response) {
56
try {
@@ -13,6 +14,18 @@ export async function handleCreateUser(req: Request, res: Response) {
1314
}
1415
}
1516

17+
export async function handleCreateAdminUser(req: Request, res: Response) {
18+
try {
19+
const { email } = req.body;
20+
console.log(`creating admin user ${email}`);
21+
const user = await createAdminUser(email);
22+
res.status(200).send(user);
23+
} catch (error) {
24+
console.error(error);
25+
res.status(500).send(error);
26+
}
27+
}
28+
1629
export async function handleGetUser(req: Request, res: Response) {
1730
try {
1831
console.log(req.query.email);

UserService/src/user/user.service.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,29 @@ export async function createUser(email: string): Promise<User> {
3737
}
3838
}
3939

40+
export async function createAdminUser(email: string): Promise<User> {
41+
try {
42+
await setDoc(doc(db, "users", email), {
43+
email: email,
44+
name: "-",
45+
year: "-",
46+
major: "-",
47+
role: "admin",
48+
completed: 0,
49+
});
50+
return Promise.resolve({
51+
email: email,
52+
name: "-",
53+
year: "-",
54+
major: "-",
55+
role: "admin",
56+
completed: 0,
57+
});
58+
} catch (error) {
59+
return Promise.reject(error);
60+
}
61+
}
62+
4063
export async function getUser(email: string): Promise<User> {
4164
try {
4265
const data = await getDoc(doc(db, "users", email));

frontend/src/api/user/data.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import { UserModel, Values } from "./model";
55
export const createUser = (email: string) =>
66
UserHttpClient.post<UserModel>("/user", { email: email });
77

8+
export const createAdminUser = (email: string) =>
9+
UserHttpClient.post<UserModel>("/useradmin", { email: email });
10+
811
export const getUser = (email: string) =>
912
UserHttpClient.get<UserModel>("/user", { params: { email: email } });
1013

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { ReactNode } from "react";
2+
import { Navigate } from "react-router-dom";
3+
import { useAuth } from "./auth.context";
4+
5+
interface AuthGuardProps {
6+
children: ReactNode;
7+
}
8+
9+
export default function MaintainerGuard({ children }: AuthGuardProps) {
10+
const { user } = useAuth();
11+
if (!(user?.role == 'maintainer')) {
12+
return <Navigate to="/login" />;
13+
}
14+
return <>{children}</>;
15+
}

frontend/src/auth/auth.context.tsx

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ import { registerUser, signIn, signOut } from "../api/auth";
1111
import { useLocalStorage } from "./useLocalStorage";
1212
import { useNavigate } from "react-router-dom";
1313
import { AxiosError } from "axios";
14-
import { createUser, getUser, UserModel } from "../api/user";
14+
import { createAdminUser, createUser, getUser, UserModel } from "../api/user";
1515

1616
interface AuthContextData {
1717
user: UserModel | undefined;
1818
setUser: any | undefined,
1919
error: string;
2020
signUp: (email: string, password: string) => void;
21+
signUpAdmin: (email: string, password: string) => void;
2122
login: (email: string, password: string) => void;
2223
logout: () => void;
2324
}
@@ -31,6 +32,7 @@ const AuthContext = createContext<AuthContextData>({
3132
setUser: undefined,
3233
error: "",
3334
signUp: (email: string, password: string) => undefined,
35+
signUpAdmin: (email: string, password: string) => undefined,
3436
login: (email: string, password: string) => undefined,
3537
logout: () => undefined,
3638
});
@@ -64,6 +66,33 @@ export function AuthContextProvider({ children }: AuthContextProviderProps) {
6466
[setUser]
6567
);
6668

69+
const signUpAdmin = useCallback(
70+
async (email: string, password: string) => {
71+
try {
72+
const response = await registerUser({
73+
email: email,
74+
password: password,
75+
});
76+
const u: User = response.data.user;
77+
if (!u.email) {
78+
throw new Error("user returned without email");
79+
}
80+
console.log('creating admin')
81+
const fetchedUser = await createAdminUser(u.email);
82+
console.log('admin created')
83+
// setActiveUser(u)
84+
// setUser(fetchedUser.data);
85+
} catch (e) {
86+
if (e instanceof AxiosError && e.response) {
87+
setError(e.response.data.code);
88+
} else if (e instanceof Error) {
89+
setError(e.message);
90+
}
91+
}
92+
},
93+
[setUser]
94+
);
95+
6796
const login = useCallback(
6897
async (email: string, password: string) => {
6998
try {
@@ -103,8 +132,8 @@ export function AuthContextProvider({ children }: AuthContextProviderProps) {
103132
}, [setUser, navigate]);
104133

105134
const authContextProviderValue = useMemo(
106-
() => ({ user, setUser, error, signUp, login, logout }),
107-
[user, setUser, error, signUp, login, logout]
135+
() => ({ user, setUser, error, signUp, signUpAdmin, login, logout }),
136+
[user, setUser, error, signUp, signUpAdmin, login, logout]
108137
);
109138

110139
return (

frontend/src/components/Navbar.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,16 @@ export default function Navbar() {
5151
setAnchorElUser(null);
5252
};
5353

54-
const settings = [
54+
var settings = [
5555
{ name: "Profile", onclick: () => navigate("/profile", { replace: true }) },
5656
{ name: "Account", onclick: handleCloseUserMenu },
5757
{ name: "Dashboard", onclick: handleCloseUserMenu },
5858
{ name: "Logout", onclick: logout },
5959
];
60+
if (user?.role == 'maintainer') {
61+
// settings = settings.concat({name: "Create", onclick: test})
62+
settings = settings.concat({name: "Create Admin", onclick: () => navigate("/createadmin", { replace: true })})
63+
}
6064

6165
return (
6266
<AppBar position="static">

frontend/src/index.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import ProblemSolver from "./pages/ProblemSolver";
1313

1414
import Landing from "./pages/landing";
1515
import Profile from "./pages/profile";
16+
import CreateAdmin from "./pages/createAdmin";
17+
import MaintainerGuard from "./auth/MaintainerGuard";
1618

1719
const root = ReactDOM.createRoot(
1820
document.getElementById("root") as HTMLElement
@@ -65,6 +67,14 @@ root.render(
6567
</AuthGuard>
6668
}
6769
/>
70+
<Route
71+
path="/createadmin"
72+
element={
73+
<MaintainerGuard>
74+
<CreateAdmin />
75+
</MaintainerGuard>
76+
}
77+
/>
6878
</Routes>
6979
</DataContextProvider>
7080
</AuthContextProvider>

frontend/src/pages/createAdmin.tsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { useState } from "react";
2+
import {
3+
Box,
4+
Button,
5+
CssBaseline,
6+
Link,
7+
TextField,
8+
Typography,
9+
} from "@mui/material";
10+
import CenteredContainer from "../components/CenteredContainer";
11+
import Navbar from "../components/Navbar";
12+
import PasswordField from "../components/PasswordField";
13+
import { useAuth } from "../auth/auth.context";
14+
15+
export default function CreateAdmin() {
16+
const { user, error, signUpAdmin } = useAuth();
17+
const [email, setEmail] = useState("");
18+
const [password, setPassword] = useState("");
19+
const [creation, setCreation] = useState(false);
20+
21+
22+
const handleClickSignUp = async () => {
23+
await signUpAdmin(email, password);
24+
setCreation(true);
25+
}
26+
return (
27+
<Box height="100vh">
28+
<CssBaseline />
29+
<Navbar />
30+
<CenteredContainer>
31+
<Typography variant="h4" align="center" paddingBottom={5}>
32+
Create Admin User
33+
</Typography>
34+
<TextField
35+
sx={{ width: "25ch" }}
36+
label="email"
37+
variant="outlined"
38+
value={email}
39+
onChange={(e) => setEmail(e.currentTarget.value)}
40+
/>
41+
<PasswordField password={password} setPassword={setPassword} />
42+
<Button variant="contained" onClick={handleClickSignUp}>
43+
Create
44+
</Button>
45+
{error && <Typography>{error}</Typography>}
46+
{creation && (
47+
<Typography>
48+
Admin account created!
49+
</Typography>
50+
)}
51+
</CenteredContainer>
52+
</Box>
53+
);
54+
}

0 commit comments

Comments
 (0)