Skip to content

Commit 8d32bd3

Browse files
committed
Merge branch 'development' into qnservice_docker
2 parents be2c58d + 3614ed9 commit 8d32bd3

File tree

9 files changed

+740
-52
lines changed

9 files changed

+740
-52
lines changed

.github/workflows/ci.yml

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@ on:
44
push:
55
branches:
66
- "*"
7-
pull_request:
8-
branches:
9-
- "*"
107

118
env:
129
NODE_VERSION: 20
10+
FIREBASE_PROJECT_ID: ${{ secrets.FIREBASE_PROJECT_ID }}
11+
FIREBASE_PRIVATE_KEY: ${{ secrets.FIREBASE_PRIVATE_KEY }}
12+
FIREBASE_CLIENT_EMAIL: ${{ secrets.FIREBASE_CLIENT_EMAIL }}
13+
FIREBASE_STORAGE_BUCKET: ${{ secrets.FIREBASE_STORAGE_BUCKET }}
14+
JWT_SECRET: ${{ secrets.JWT_SECRET }}
15+
16+
permissions:
17+
contents: read
1318

1419
jobs:
1520
ci:
@@ -30,6 +35,16 @@ jobs:
3035
- name: Linting
3136
working-directory: ${{ matrix.service }}
3237
run: npm run lint
33-
# - name: Tests
34-
# working-directory: ${{ matrix.service }}
35-
# run: npm test
38+
- name: Set .env variables
39+
working-directory: ${{ matrix.service }}
40+
run: |
41+
touch .env
42+
echo "FIREBASE_PROJECT_ID=${{ env.FIREBASE_PROJECT_ID }}" >> .env
43+
echo "FIREBASE_PRIVATE_KEY=${{ env.FIREBASE_PRIVATE_KEY }}" >> .env
44+
echo "FIREBASE_CLIENT_EMAIL=${{ env.FIREBASE_CLIENT_EMAIL }}" >> .env
45+
echo "FIREBASE_CLIENT_EMAIL=${{ env.FIREBASE_CLIENT_EMAIL }}" >> .env
46+
echo "FIREBASE_STORAGE_BUCKET=${{ env.FIREBASE_STORAGE_BUCKET }}" >> .env
47+
echo "JWT_SECRET=${{ env.JWT_SECRET }}" >> .env
48+
- name: Tests
49+
working-directory: ${{ matrix.service }}
50+
run: npm test

backend/user-service/.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
.env
3+
tests

backend/user-service/Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM node:20-alpine
2+
3+
WORKDIR /user-service
4+
5+
COPY package*.json ./
6+
7+
RUN npm ci
8+
9+
EXPOSE 3001
10+
11+
CMD ["npm", "start"]

backend/user-service/controller/user-controller.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export async function createUser(
7373
lastName,
7474
username,
7575
email,
76-
hashedPassword,
76+
hashedPassword
7777
);
7878
return res.status(201).json({
7979
message: `Created new user ${username} successfully`,
@@ -85,8 +85,7 @@ export async function createUser(
8585
"At least one of first name, last name, username, email and password are missing",
8686
});
8787
}
88-
} catch (err) {
89-
console.error(err);
88+
} catch {
9089
return res
9190
.status(500)
9291
.json({ message: "Unknown error when creating new user!" });
@@ -108,8 +107,7 @@ export async function getUser(req: Request, res: Response): Promise<Response> {
108107
.status(200)
109108
.json({ message: `Found user`, data: formatUserResponse(user) });
110109
}
111-
} catch (err) {
112-
console.error(err);
110+
} catch {
113111
return res
114112
.status(500)
115113
.json({ message: "Unknown error when getting user!" });
@@ -126,8 +124,7 @@ export async function getAllUsers(
126124
return res
127125
.status(200)
128126
.json({ message: `Found users`, data: users.map(formatUserResponse) });
129-
} catch (err) {
130-
console.error(err);
127+
} catch {
131128
return res
132129
.status(500)
133130
.json({ message: "Unknown error when getting all users!" });
@@ -226,8 +223,7 @@ export async function updateUser(
226223
"No field to update. Update one of the following fields: username, email, password, profilePictureUrl, firstName, lastName, biography",
227224
});
228225
}
229-
} catch (err) {
230-
console.error(err);
226+
} catch {
231227
return res
232228
.status(500)
233229
.json({ message: "Unknown error when updating user!" });
@@ -263,8 +259,7 @@ export async function updateUserPrivilege(
263259
} else {
264260
return res.status(400).json({ message: "isAdmin is missing!" });
265261
}
266-
} catch (err) {
267-
console.error(err);
262+
} catch {
268263
return res
269264
.status(500)
270265
.json({ message: "Unknown error when updating user privilege!" });
@@ -289,8 +284,7 @@ export async function deleteUser(
289284
return res
290285
.status(200)
291286
.json({ message: `Deleted user ${userId} successfully` });
292-
} catch (err) {
293-
console.error(err);
287+
} catch {
294288
return res
295289
.status(500)
296290
.json({ message: "Unknown error when deleting user!" });

backend/user-service/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"start": "tsx server.ts",
1010
"dev": "tsx watch server.ts",
1111
"lint": "eslint .",
12-
"test": "export NODE_ENV=test && jest",
12+
"test": "set NODE_ENV=test && jest",
1313
"test:watch": "export NODE_ENV=test && jest --watch"
1414
},
1515
"keywords": [],

backend/user-service/tests/authRoutes.spec.ts

Lines changed: 139 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,158 @@ const AUTH_BASE_URL = "/api/auth";
1010

1111
faker.seed(0);
1212

13-
const insertUser = async () => {
14-
const username = faker.internet.userName();
15-
const firstName = faker.person.firstName();
16-
const lastName = faker.person.lastName();
17-
const email = faker.internet.email();
18-
const password = "strongPassword@123";
19-
const hashedPassword = bcrypt.hashSync(password, bcrypt.genSaltSync(10));
13+
const username = faker.internet.userName();
14+
const firstName = faker.person.firstName();
15+
const lastName = faker.person.lastName();
16+
const email = faker.internet.email();
17+
const password = "strongPassword@123";
18+
const hashedPassword = bcrypt.hashSync(password, bcrypt.genSaltSync(10));
19+
20+
const insertAdminUser = async () => {
21+
await new UserModel({
22+
username,
23+
firstName,
24+
lastName,
25+
email,
26+
password: hashedPassword,
27+
isAdmin: true,
28+
}).save();
29+
30+
return { email, password };
31+
};
32+
33+
const insertNonAdminUser = async () => {
2034
await new UserModel({
2135
username,
2236
firstName,
2337
lastName,
2438
email,
2539
password: hashedPassword,
2640
}).save();
41+
2742
return { email, password };
2843
};
2944

3045
describe("Auth routes", () => {
3146
it("Login", async () => {
32-
const credentials = await insertUser();
47+
const credentials = await insertNonAdminUser();
48+
3349
const res = await request.post(`${AUTH_BASE_URL}/login`).send(credentials);
50+
3451
expect(res.status).toBe(200);
3552
});
53+
54+
it("Login with invalid password", async () => {
55+
const { email } = await insertNonAdminUser();
56+
57+
const res = await request
58+
.post(`${AUTH_BASE_URL}/login`)
59+
.send({ email, password: "blahblah" });
60+
61+
expect(res.status).toBe(401);
62+
});
63+
64+
it("Login with invalid email", async () => {
65+
const { password } = await insertNonAdminUser();
66+
67+
const res = await request
68+
.post(`${AUTH_BASE_URL}/login`)
69+
.send({ email: "blahblah", password });
70+
71+
expect(res.status).toBe(401);
72+
});
73+
74+
it("Login with missing email and/or password", async () => {
75+
const res = await request.post(`${AUTH_BASE_URL}/login`).send({});
76+
77+
expect(res.status).toBe(400);
78+
});
79+
80+
it("Catch server error when login", async () => {
81+
const loginSpy = jest.spyOn(UserModel, "findOne").mockImplementation(() => {
82+
throw new Error();
83+
});
84+
85+
const res = await request
86+
.post(`${AUTH_BASE_URL}/login`)
87+
.send({ email, password });
88+
89+
expect(res.status).toBe(500);
90+
91+
loginSpy.mockRestore();
92+
});
93+
94+
it("Verify token with missing token", async () => {
95+
const res = await request.get(`${AUTH_BASE_URL}/verify-token`);
96+
97+
expect(res.status).toBe(401);
98+
});
99+
100+
it("Verify token but users not found", async () => {
101+
// TODO
102+
});
103+
104+
it("Verify token", async () => {
105+
const { email, password } = await insertNonAdminUser();
106+
107+
const loginRes = await request
108+
.post(`${AUTH_BASE_URL}/login`)
109+
.send({ email, password });
110+
111+
const token = loginRes.body.data.accessToken;
112+
113+
const res = await request
114+
.get(`${AUTH_BASE_URL}/verify-token`)
115+
.set("Authorization", `Bearer ${token}`);
116+
117+
expect(res.status).toBe(200);
118+
expect(res.body.data.email).toBe(email);
119+
expect(res.body.data.isAdmin).toBe(false);
120+
});
121+
122+
it("Verify invalid token", async () => {
123+
const res = await request
124+
.get(`${AUTH_BASE_URL}/verify-token`)
125+
.set("Authorization", `Bearer blahblah`);
126+
127+
expect(res.status).toBe(401);
128+
});
129+
130+
it("Verify admin token", async () => {
131+
const { email, password } = await insertAdminUser();
132+
133+
const loginRes = await request
134+
.post(`${AUTH_BASE_URL}/login`)
135+
.send({ email, password });
136+
137+
const token = loginRes.body.data.accessToken;
138+
139+
const res = await request
140+
.get(`${AUTH_BASE_URL}/verify-admin-token`)
141+
.set("Authorization", `Bearer ${token}`);
142+
143+
expect(res.status).toBe(200);
144+
expect(res.body.data.email).toBe(email);
145+
expect(res.body.data.isAdmin).toBe(true);
146+
});
147+
148+
it("Verify admin token with non-admin user", async () => {
149+
const { email, password } = await insertNonAdminUser();
150+
151+
const loginRes = await request
152+
.post(`${AUTH_BASE_URL}/login`)
153+
.send({ email, password });
154+
155+
const token = loginRes.body.data.accessToken;
156+
157+
const res = await request
158+
.get(`${AUTH_BASE_URL}/verify-admin-token`)
159+
.set("Authorization", `Bearer ${token}`);
160+
161+
expect(res.status).toBe(403);
162+
});
163+
164+
it("Verify if user is owner or admin", async () => {
165+
// TODO
166+
});
36167
});

0 commit comments

Comments
 (0)