Skip to content

Commit

Permalink
Update db schema (#41)
Browse files Browse the repository at this point in the history
* Update schema to allow for null values since it is empty in the start

* Changed contrains for User schema email does not need to be unique

* Update schema username does not have to be unique either

* Update new db schema to link with other database tested with postman
Add input validation

* Add more data validation

* Remove line that cause error in frontend index.tsx
  • Loading branch information
Kang-Quan authored Oct 13, 2023
1 parent 6db52ee commit ca44749
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 104 deletions.
117 changes: 59 additions & 58 deletions front-end/peer-prep/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,84 +1,85 @@
import ReactDOM from 'react-dom/client';
import reportWebVitals from './reportWebVitals';
import ReactDOM from "react-dom/client";
import reportWebVitals from "./reportWebVitals";

import { auth } from "./components/Auth/Firebase";
import { useAuthState } from "react-firebase-hooks/auth";

// import Redux components here
import {Provider} from "react-redux";
import store from "./components/redux/store/store"
import { Provider } from "react-redux";
import store from "./components/redux/store/store";

// import React Routing components here
import {
BrowserRouter,
BrowserRouter,
Routes,
Route,
Outlet,
Navigate,
Outlet,
Navigate,
} from "react-router-dom";

// import app components here
import QuestionsPage from './components/QuestionsPage';
import UserPage from './components/UserPage';
import QuestionsPage from "./components/QuestionsPage";
import UserPage from "./components/UserPage";

// import styles
import { appStyle } from './styles';
import ErrorPage from './components/ErrorPage';
import SignInPage from './components/Auth/SignInPage';
import Navbar from './components/Navbar';
import GoodbyePage from './components/Auth/GoodbyePage';
import { appStyle } from "./styles";
import ErrorPage from "./components/ErrorPage";
import SignInPage from "./components/Auth/SignInPage";
import Navbar from "./components/Navbar";
import GoodbyePage from "./components/Auth/GoodbyePage";

const ProtectedRoute = () => {
const [user, loading, error] = useAuthState(auth);
debugger;
const [user, loading, error] = useAuthState(auth);
debugger;
if (loading) {
// the user object will be null if firebase is loading
// handle loading next time
return <></>
}
if (error) {
return <Navigate to="*"/>;
}
if (!user) {
debugger;
// User is not authenticated, navigate to SignIn page
return <Navigate to="/signin" replace />;
}
return <Outlet/>
// the user object will be null if firebase is loading
// handle loading next time
return <></>;
}
if (error) {
return <Navigate to="*" />;
}
if (!user) {
debugger;
// User is not authenticated, navigate to SignIn page
return <Navigate to="/signin" replace />;
}
return <Outlet />;
};


const RootApp = () => {
return (
<Provider store={store}>
<div id="app" style={appStyle}>
<BrowserRouter>
<Routes>
{/* All protected routes are written here */}
<Route element={
<>
<Navbar/>
<ProtectedRoute/>
</>
}>
<Route path="home" element={<QuestionsPage/>}/>
<Route path="user" element={<UserPage/>}/>
</Route>
{/* All non-protected routes are written here */}
<Route path="/" element={<SignInPage/>} />
<Route path="/signin" element={<SignInPage/>} />
<Route path="*" element={<ErrorPage/>}/>
<Route path="/goodbye" element={<GoodbyePage/>}/>
</Routes>
</BrowserRouter>
</div>
</Provider>
)
}
return (
<Provider store={store}>
<div id="app" style={appStyle}>
<BrowserRouter>
<Routes>
{/* All protected routes are written here */}
<Route
element={
<>
<Navbar />
<ProtectedRoute />
</>
}
>
<Route path="home" element={<QuestionsPage />} />
<Route path="user" element={<UserPage />} />
</Route>
{/* All non-protected routes are written here */}
<Route path="/" element={<SignInPage />} />
<Route path="/signin" element={<SignInPage />} />
<Route path="*" element={<ErrorPage />} />
<Route path="/goodbye" element={<GoodbyePage />} />
</Routes>
</BrowserRouter>
</div>
</Provider>
);
};
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
document.getElementById("root") as HTMLElement
);
root.render(<RootApp/>);
root.render(<RootApp />);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
Expand Down
102 changes: 67 additions & 35 deletions services/profile-service/src/controller/user-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,96 @@ import { ResponseUtil } from "../utils/Response";
import { User } from "../entity/User";
import { AppDataSource } from "../data-source";

interface iUserData {
uid: string;
username: string;
email: string;
firstName: string;
lastName: string;
age: number;
}

const ERR_MSG_NO_USER = "User not found";
const ERR_MSG_BAD_REQUEST =
"Bad Request - Request body is empty or fields missing";
const ERR_MSG_AGE_NEGATIVE = "Invalid age: Age cannot be negative.";
const ERR_MSG_DUPLICATE =
"Update a resource that already exists or has conflicting information";

//helper function to validate data
async function validateData(userData: iUserData): Promise<string | null> {
// Array of required fields
const requiredFields = [
"uid",
"username",
"email",
"firstName",
"lastName",
"age",
];

for (const field of requiredFields) {
if (!userData[field]) {
return ERR_MSG_BAD_REQUEST;
}
}
if (userData.age < 0) {
return ERR_MSG_AGE_NEGATIVE;
}
return null;
}

export class UserController {
async getUser(req: Request, res: Response): Promise<Response> {
const { username } = req.params;
const { uid } = req.params;
const user = await AppDataSource.getRepository(User).findOneBy({
username: username,
uid: uid,
});
if (!user) {
return ResponseUtil.sendError(res, "User not found", 404);
return ResponseUtil.sendError(res, ERR_MSG_NO_USER, 404);
}
return ResponseUtil.sendResponse(res, user, 200);
}

async createUser(req: Request, res: Response, next): Promise<Response> {
const userData = req.body;
const repo = AppDataSource.getRepository(User);

//check for duplicate username
const checkUserName = await AppDataSource.getRepository(User).findOneBy(
{
username: userData.username,
}
);

if (checkUserName) {
return ResponseUtil.sendError(res, "Username already used", 409);
const validationError = await validateData(userData);
if (validationError) {
return ResponseUtil.sendError(res, validationError, 400);
}

//check for duplicate email
const checkEmail = await AppDataSource.getRepository(User).findOneBy({
email: userData.email,
const repo = AppDataSource.getRepository(User);
const userInDB = await AppDataSource.getRepository(User).findOneBy({
uid: userData.uid,
});

if (checkEmail) {
return ResponseUtil.sendError(res, "Email already used", 409);
if (userInDB) {
return ResponseUtil.sendError(res, ERR_MSG_DUPLICATE, 409);
}

const user = repo.create(userData);
await repo.save(user);
return ResponseUtil.sendResponse(res, user, 201);
}

async updateUser(req: Request, res: Response): Promise<Response> {
const { username } = req.params;
const { uid } = req.params;
const userData = req.body;

const validationError = await validateData(userData);
if (validationError) {
return ResponseUtil.sendError(res, validationError, 400);
}

if (uid !== userData.uid) {
return ResponseUtil.sendError(res, ERR_MSG_DUPLICATE, 409);
}

const repo = AppDataSource.getRepository(User);
const user = await repo.findOneBy({
username: username,
uid: uid,
});
if (!user) {
return ResponseUtil.sendError(res, "user not found", 404);
}

//check for duplicate email
const checkEmail = await AppDataSource.getRepository(User).findOneBy({
email: userData.email,
});
if (checkEmail) {
return ResponseUtil.sendError(res, "Email already used", 409);
return ResponseUtil.sendError(res, ERR_MSG_NO_USER, 404);
}

repo.merge(user, userData);
Expand All @@ -69,15 +101,15 @@ export class UserController {
}

async deleteUser(req: Request, res: Response): Promise<Response> {
const { username } = req.params;
const { uid } = req.params;
const repo = AppDataSource.getRepository(User);
const user = await repo.findOneBy({
username: username,
uid: uid,
});
if (!user) {
return ResponseUtil.sendError(res, "user not found", 404);
return ResponseUtil.sendError(res, ERR_MSG_NO_USER, 404);
}
await repo.remove(user);
return ResponseUtil.sendResponse(res, null);
return ResponseUtil.sendResponse(res, null, 204);
}
}
13 changes: 5 additions & 8 deletions services/profile-service/src/entity/User.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
import { Entity, Column, PrimaryColumn } from "typeorm";

@Entity()
export class User {
@PrimaryGeneratedColumn()
user_id: number;
@PrimaryColumn()
uid: string;

@Column({ unique: true })
@Column()
username: string;

@Column({ unique: true })
email: string;

@Column()
password: string;
email: string;

@Column()
firstName: string;
Expand Down
6 changes: 3 additions & 3 deletions services/profile-service/src/router/user-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ const userController = new UserController();

const router = express.Router();

router.get("/:username", userController.getUser);
router.get("/:uid", userController.getUser);
router.post("/", userController.createUser);
router.put("/:username", userController.updateUser);
router.delete("/:username", userController.deleteUser);
router.put("/:uid", userController.updateUser);
router.delete("/:uid", userController.deleteUser);

export default router;

0 comments on commit ca44749

Please sign in to comment.