Skip to content

Commit 622d15c

Browse files
committed
Update user service to typescript
1 parent 6c33cda commit 622d15c

File tree

16 files changed

+923
-158
lines changed

16 files changed

+923
-158
lines changed

backend/user-service/.env.sample

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
DB_CLOUD_URI=<CONNECTION_STRING>
2-
DB_LOCAL_URI=mongodb://127.0.0.1:27017/peerprepUserServiceDB
32
PORT=3001
43

5-
# Will use cloud MongoDB Atlas database
6-
ENV=PROD
7-
84
# Secret for creating JWT signature
95
JWT_SECRET=you-can-replace-this-with-your-own-secret
Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import express from "express";
1+
import express, { Request, Response, NextFunction } from "express";
22
import cors from "cors";
33

44
import userRoutes from "./routes/user-routes.js";
@@ -12,12 +12,12 @@ app.use(cors()); // config cors so that front-end can use
1212
app.options("*", cors());
1313

1414
// To handle CORS Errors
15-
app.use((req, res, next) => {
15+
app.use((req: Request, res: Response, next: NextFunction) => {
1616
res.header("Access-Control-Allow-Origin", "*"); // "*" -> Allow all links to access
1717

1818
res.header(
1919
"Access-Control-Allow-Headers",
20-
"Origin, X-Requested-With, Content-Type, Accept, Authorization",
20+
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
2121
);
2222

2323
// Browsers usually send this before PUT or POST Requests
@@ -33,27 +33,11 @@ app.use((req, res, next) => {
3333
app.use("/users", userRoutes);
3434
app.use("/auth", authRoutes);
3535

36-
app.get("/", (req, res, next) => {
36+
app.get("/", (req: Request, res: Response, next: NextFunction) => {
3737
console.log("Sending Greetings!");
3838
res.json({
3939
message: "Hello World from user-service",
4040
});
4141
});
4242

43-
// Handle When No Route Match Is Found
44-
app.use((req, res, next) => {
45-
const error = new Error("Route Not Found");
46-
error.status = 404;
47-
next(error);
48-
});
49-
50-
app.use((error, req, res, next) => {
51-
res.status(error.status || 500);
52-
res.json({
53-
error: {
54-
message: error.message,
55-
},
56-
});
57-
});
58-
5943
export default app;
Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import { Response } from "express";
12
import bcrypt from "bcrypt";
23
import jwt from "jsonwebtoken";
34
import { findUserByEmail as _findUserByEmail } from "../model/repository.js";
45
import { formatUserResponse } from "./user-controller.js";
6+
import { AuthenticatedRequest } from "../types/request.js";
57

6-
export async function handleLogin(req, res) {
8+
export async function handleLogin(req: AuthenticatedRequest, res: Response): Promise<Response> {
79
const { email, password } = req.body;
810
if (email && password) {
911
try {
@@ -17,25 +19,34 @@ export async function handleLogin(req, res) {
1719
return res.status(401).json({ message: "Wrong email and/or password" });
1820
}
1921

20-
const accessToken = jwt.sign({
21-
id: user.id,
22-
}, process.env.JWT_SECRET, {
23-
expiresIn: "1d",
24-
});
25-
return res.status(200).json({ message: "User logged in", data: { accessToken, ...formatUserResponse(user) } });
22+
const accessToken = jwt.sign(
23+
{
24+
id: user.id,
25+
},
26+
process.env.JWT_SECRET as string,
27+
{
28+
expiresIn: "1d",
29+
}
30+
);
31+
return res
32+
.status(200)
33+
.json({ message: "User logged in", data: { accessToken, ...formatUserResponse(user) } });
2634
} catch (err) {
27-
return res.status(500).json({ message: err.message });
35+
return res.status(500).json({ message: "Server error", err });
2836
}
2937
} else {
3038
return res.status(400).json({ message: "Missing email and/or password" });
3139
}
3240
}
3341

34-
export async function handleVerifyToken(req, res) {
42+
export async function handleVerifyToken(
43+
req: AuthenticatedRequest,
44+
res: Response
45+
): Promise<Response> {
3546
try {
3647
const verifiedUser = req.user;
3748
return res.status(200).json({ message: "Token verified", data: verifiedUser });
3849
} catch (err) {
39-
return res.status(500).json({ message: err.message });
50+
return res.status(500).json({ message: "Server error", err });
4051
}
4152
}

backend/user-service/controller/user-controller.js renamed to backend/user-service/controller/user-controller.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Request, Response } from "express";
12
import bcrypt from "bcrypt";
23
import { isValidObjectId } from "mongoose";
34
import {
@@ -10,9 +11,10 @@ import {
1011
findUserByUsernameOrEmail as _findUserByUsernameOrEmail,
1112
updateUserById as _updateUserById,
1213
updateUserPrivilegeById as _updateUserPrivilegeById,
13-
} from "../model/repository.js";
14+
} from "../model/repository";
15+
import { IUser } from "../model/user-model";
1416

15-
export async function createUser(req, res) {
17+
export async function createUser(req: Request, res: Response): Promise<Response> {
1618
try {
1719
const { username, email, password } = req.body;
1820
if (username && email && password) {
@@ -37,7 +39,7 @@ export async function createUser(req, res) {
3739
}
3840
}
3941

40-
export async function getUser(req, res) {
42+
export async function getUser(req: Request, res: Response): Promise<Response> {
4143
try {
4244
const userId = req.params.id;
4345
if (!isValidObjectId(userId)) {
@@ -56,7 +58,7 @@ export async function getUser(req, res) {
5658
}
5759
}
5860

59-
export async function getAllUsers(req, res) {
61+
export async function getAllUsers(req: Request, res: Response): Promise<Response> {
6062
try {
6163
const users = await _findAllUsers();
6264

@@ -67,7 +69,7 @@ export async function getAllUsers(req, res) {
6769
}
6870
}
6971

70-
export async function updateUser(req, res) {
72+
export async function updateUser(req: Request, res: Response): Promise<Response> {
7173
try {
7274
const { username, email, password } = req.body;
7375
if (username || email || password) {
@@ -90,30 +92,33 @@ export async function updateUser(req, res) {
9092
}
9193
}
9294

93-
let hashedPassword;
95+
let hashedPassword: string = "";
9496
if (password) {
9597
const salt = bcrypt.genSaltSync(10);
9698
hashedPassword = bcrypt.hashSync(password, salt);
9799
}
98100
const updatedUser = await _updateUserById(userId, username, email, hashedPassword);
99101
return res.status(200).json({
100102
message: `Updated data for user ${userId}`,
101-
data: formatUserResponse(updatedUser),
103+
data: formatUserResponse(updatedUser as IUser),
102104
});
103105
} else {
104-
return res.status(400).json({ message: "No field to update: username and email and password are all missing!" });
106+
return res
107+
.status(400)
108+
.json({ message: "No field to update: username and email and password are all missing!" });
105109
}
106110
} catch (err) {
107111
console.error(err);
108112
return res.status(500).json({ message: "Unknown error when updating user!" });
109113
}
110114
}
111115

112-
export async function updateUserPrivilege(req, res) {
116+
export async function updateUserPrivilege(req: Request, res: Response): Promise<Response> {
113117
try {
114118
const { isAdmin } = req.body;
115119

116-
if (isAdmin !== undefined) { // isAdmin can have boolean value true or false
120+
if (isAdmin !== undefined) {
121+
// isAdmin can have boolean value true or false
117122
const userId = req.params.id;
118123
if (!isValidObjectId(userId)) {
119124
return res.status(404).json({ message: `User ${userId} not found` });
@@ -126,7 +131,7 @@ export async function updateUserPrivilege(req, res) {
126131
const updatedUser = await _updateUserPrivilegeById(userId, isAdmin === true);
127132
return res.status(200).json({
128133
message: `Updated privilege for user ${userId}`,
129-
data: formatUserResponse(updatedUser),
134+
data: formatUserResponse(updatedUser as IUser),
130135
});
131136
} else {
132137
return res.status(400).json({ message: "isAdmin is missing!" });
@@ -137,7 +142,7 @@ export async function updateUserPrivilege(req, res) {
137142
}
138143
}
139144

140-
export async function deleteUser(req, res) {
145+
export async function deleteUser(req: Request, res: Response): Promise<Response> {
141146
try {
142147
const userId = req.params.id;
143148
if (!isValidObjectId(userId)) {
@@ -156,7 +161,7 @@ export async function deleteUser(req, res) {
156161
}
157162
}
158163

159-
export function formatUserResponse(user) {
164+
export function formatUserResponse(user: IUser) {
160165
return {
161166
id: user.id,
162167
username: user.username,

backend/user-service/middleware/basic-access-control.js renamed to backend/user-service/middleware/basic-access-control.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1+
import { NextFunction, Response } from "express";
12
import jwt from "jsonwebtoken";
2-
import { findUserById as _findUserById } from "../model/repository.js";
3+
import { findUserById as _findUserById } from "../model/repository";
4+
import { AuthenticatedRequest } from "../types/request";
35

4-
export function verifyAccessToken(req, res, next) {
6+
export function verifyAccessToken(req: AuthenticatedRequest, res: Response, next: NextFunction) {
57
const authHeader = req.headers["authorization"];
68
if (!authHeader) {
79
return res.status(401).json({ message: "Authentication failed" });
810
}
911

1012
// request auth header: `Authorization: Bearer + <access_token>`
1113
const token = authHeader.split(" ")[1];
12-
jwt.verify(token, process.env.JWT_SECRET, async (err, user) => {
13-
if (err) {
14+
jwt.verify(token, process.env.JWT_SECRET as string, async (err, user) => {
15+
if (err || !user || typeof user === "string") {
1416
return res.status(401).json({ message: "Authentication failed" });
1517
}
1618

@@ -20,26 +22,32 @@ export function verifyAccessToken(req, res, next) {
2022
return res.status(401).json({ message: "Authentication failed" });
2123
}
2224

23-
req.user = { id: dbUser.id, username: dbUser.username, email: dbUser.email, isAdmin: dbUser.isAdmin };
25+
req.user = {
26+
id: dbUser.id,
27+
username: dbUser.username,
28+
email: dbUser.email,
29+
isAdmin: dbUser.isAdmin,
30+
};
2431
next();
2532
});
2633
}
2734

28-
export function verifyIsAdmin(req, res, next) {
29-
if (req.user.isAdmin) {
35+
export function verifyIsAdmin(req: AuthenticatedRequest, res: Response, next: NextFunction) {
36+
if (req.user?.isAdmin) {
3037
next();
3138
} else {
3239
return res.status(403).json({ message: "Not authorized to access this resource" });
3340
}
3441
}
3542

36-
export function verifyIsOwnerOrAdmin(req, res, next) {
37-
if (req.user.isAdmin) {
43+
export function verifyIsOwnerOrAdmin(req: AuthenticatedRequest, res: Response, next: NextFunction) {
44+
if (req.user?.isAdmin) {
3845
return next();
3946
}
4047

4148
const userIdFromReqParams = req.params.id;
42-
const userIdFromToken = req.user.id;
49+
const userIdFromToken = req.user?.id;
50+
4351
if (userIdFromReqParams === userIdFromToken) {
4452
return next();
4553
}

backend/user-service/model/repository.js

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

0 commit comments

Comments
 (0)