Skip to content

Commit 27442b3

Browse files
authored
Merge pull request #11 from CS3219-AY2425S1/PEER-204-Endpoint-For-Registration
PEER-204 Endpoint for Registration
2 parents 26c2f35 + 77a435a commit 27442b3

File tree

6 files changed

+131
-33
lines changed

6 files changed

+131
-33
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import type { Request, Response } from 'express';
2+
import { StatusCodes } from 'http-status-codes';
3+
import { loginService } from '@/services/auth/auth-logic';
4+
import type { ILoginPayload } from '@/services/auth/types';
5+
import { registerService } from '@/services/registration/register-logic';
6+
import type { IRegisterPayload } from '@/services/registration/register-inputs';
7+
8+
export async function login(req: Request, res: Response) {
9+
const { username, password }: Partial<ILoginPayload> = req.body;
10+
if (!username || !password) {
11+
return res.status(StatusCodes.UNPROCESSABLE_ENTITY).json('Malformed Request');
12+
}
13+
const { code, data, error } = await loginService({ username, password });
14+
if (error || code !== StatusCodes.OK || !data) {
15+
const sanitizedErr = error?.message ?? 'An error occurred.';
16+
return res.status(code).json(sanitizedErr);
17+
}
18+
return res
19+
.status(StatusCodes.OK)
20+
.cookie('jwtToken', data.cookie, { httpOnly: true })
21+
.json(data.user);
22+
}
23+
24+
export async function logout(_req: Request, res: Response) {
25+
return res
26+
.clearCookie('jwtToken', {
27+
secure: true,
28+
sameSite: 'none',
29+
})
30+
.status(StatusCodes.OK)
31+
.json('User has been logged out.');
32+
}
33+
34+
export async function register(req: Request, res: Response) {
35+
//Extract the registration data from the request body
36+
const { email, username, password, firstName, lastName }: Partial<IRegisterPayload> = req.body;
37+
38+
//Validate input
39+
if (!username || !password || !email || !firstName || !lastName) {
40+
return res.status(StatusCodes.UNPROCESSABLE_ENTITY).json('Malformed Request');
41+
}
42+
43+
//Call the registration service
44+
const { code, data, error } = await registerService({
45+
email,
46+
username,
47+
firstName,
48+
lastName,
49+
password,
50+
});
51+
52+
//Handle errors
53+
if (error || code !== StatusCodes.CREATED || !data) {
54+
const sanitizedErr = error?.message ?? 'An error occurred during registration.';
55+
return res.status(code).json(sanitizedErr);
56+
}
57+
58+
return res.status(StatusCodes.CREATED).json({
59+
message: 'User registered successfully',
60+
user: data.user, // Return user data if needed
61+
});
62+
}

backend/user/src/controllers/auth/index.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

backend/user/src/routes/auth.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import express from 'express';
22

3-
import { login, logout } from '@/controllers/auth';
3+
import { login, logout } from '@/controllers/auth/auth-controller';
44
import { limiter } from '@/lib/ratelimit';
5+
import { register } from '@/controllers/auth/auth-controller';
56

67
const router = express.Router();
78

89
router.post('/login', login);
910
router.post('/logout', logout);
10-
11+
router.post('/register', register);
1112
router.use(limiter);
1213

1314
export default router;
File renamed without changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export type IRegisterPayload = {
2+
email: string;
3+
username: string;
4+
firstName: string;
5+
lastName: string;
6+
password: string;
7+
};
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { or, eq, getTableColumns } from 'drizzle-orm';
2+
import { StatusCodes } from 'http-status-codes';
3+
import bcrypt from 'bcrypt';
4+
import { db, users } from '@/lib/db';
5+
import type { IRegisterPayload } from './register-inputs';
6+
7+
const _getSchema = () => {
8+
const { id, email, username, firstName, lastName } = getTableColumns(users);
9+
return {
10+
id,
11+
email,
12+
username,
13+
firstName,
14+
lastName,
15+
};
16+
};
17+
18+
export const registerService = async (payload: IRegisterPayload) => {
19+
const { email, username, firstName, lastName, password } = payload;
20+
21+
//check if user already exists (by username or email)
22+
const existingUsers = await db
23+
.select(_getSchema())
24+
.from(users)
25+
.where(or(eq(users.username, username), eq(users.email, email)))
26+
.limit(1);
27+
28+
if (existingUsers.length > 0) {
29+
return {
30+
code: StatusCodes.CONFLICT,
31+
error: {
32+
message: 'User with this username or email already exists',
33+
},
34+
};
35+
}
36+
37+
//hash the password
38+
const hashedPassword = bcrypt.hashSync(password, 10); // Use bcrypt to hash the password
39+
40+
//insert new user into the database
41+
const [newUser] = await db
42+
.insert(users)
43+
.values({
44+
email,
45+
username,
46+
firstName,
47+
lastName,
48+
password: hashedPassword, //store the hashed password
49+
})
50+
.returning(_getSchema());
51+
52+
// return success response with the JWT token
53+
return {
54+
code: StatusCodes.CREATED,
55+
data: {
56+
user: newUser,
57+
},
58+
};
59+
};

0 commit comments

Comments
 (0)