Skip to content

Commit cb8df45

Browse files
Merge pull request #639 from SELab-2/development
Deployment
2 parents 29bbb73 + b3be288 commit cb8df45

File tree

237 files changed

+23100
-21375
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

237 files changed

+23100
-21375
lines changed

backend/api/openapi.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2555,6 +2555,7 @@ components:
25552555
required:
25562556
- email
25572557
- password
2558+
- userType
25582559
additionalProperties: false
25592560
properties:
25602561
email:
@@ -2564,6 +2565,11 @@ components:
25642565
password:
25652566
type: string
25662567
description: User's password.
2568+
userType:
2569+
type: string
2570+
enum: [student, teacher]
2571+
default: student
2572+
description: User's type in the system.
25672573

25682574
RegisterResponse:
25692575
type: object

backend/extra/seedDatabase.ts

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export async function seedDatabase(): Promise<void> {
8080
const teacherInput: Teacher = new Teacher(
8181
email,
8282
firstName,
83-
lastName,
83+
'T. '+lastName,
8484
passwordHash,
8585
schoolName,
8686
)
@@ -113,7 +113,7 @@ export async function seedDatabase(): Promise<void> {
113113
const studentInput: Student = new Student(
114114
email,
115115
firstName,
116-
lastName,
116+
'S. '+lastName,
117117
passwordHash,
118118
schoolName,
119119
)
@@ -231,12 +231,11 @@ export async function seedDatabase(): Promise<void> {
231231
const visibilityOptions = [
232232
VisibilityType.PRIVATE,
233233
VisibilityType.GROUP,
234-
VisibilityType.PUBLIC
235234
];
236235

237236
for (const { id: assignmentId, classId } of assignments) {
238-
const students = await userRep.getByClassId(classId);
239-
const teachers = await userRep.getByClassId(classId);
237+
const students = await userRep.getStudentsByClassId(classId);
238+
const teachers = await userRep.getTeachersByClassId(classId);
240239
const teacherIds = teachers.map(t => t.id);
241240

242241
// Select 5–6 students for threads
@@ -258,7 +257,6 @@ export async function seedDatabase(): Promise<void> {
258257

259258
const visibility = faker.helpers.arrayElement(visibilityOptions);
260259

261-
262260
const thread = new QuestionThread(
263261
student.id!,
264262
assignmentId,
@@ -288,27 +286,6 @@ export async function seedDatabase(): Promise<void> {
288286
await messageRep.create(teacherMessage);
289287
}
290288
}
291-
292-
// Bonus: Add 2 public/global threads for this assignment
293-
for (let k = 0; k < 2; k++) {
294-
const globalThread = new QuestionThread(
295-
faker.helpers.arrayElement(students).id!,
296-
assignmentId,
297-
`step-${faker.number.int({ min: 1, max: 5 })}`,
298-
false,
299-
VisibilityType.PUBLIC,
300-
[]
301-
);
302-
const savedThread = await threadRep.create(globalThread) as { id: string };
303-
304-
const msg = new Message(
305-
faker.helpers.arrayElement(teacherIds)!,
306-
new Date(),
307-
savedThread.id!,
308-
faker.lorem.sentence()
309-
);
310-
await messageRep.create(msg);
311-
}
312289
}
313290
} catch (err) {
314291
console.error('Error during DB seeding:', err);

backend/src/application/auth.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import bcrypt from "bcryptjs";
22
import jwt from "jsonwebtoken";
33
import { AuthenticationTokenPayload, TokenResponse } from "./types";
4-
import { User } from "../core/entities/user";
4+
import { User, UserType } from "../core/entities/user";
55
import { GetUser, GetUserInput } from "../core/services/user";
66

77
// TODO - Consider allowing only one active token per user (probably not)
@@ -33,7 +33,12 @@ export class AuthenticationManager {
3333
this.refreshExpiresIn = refreshExpiresIn;
3434
}
3535

36-
async authenticate(email: string, password: string, refreshToken?: string): Promise<TokenResponse | null> {
36+
async authenticate(
37+
email: string,
38+
password: string,
39+
userType?: UserType,
40+
refreshToken?: string,
41+
): Promise<TokenResponse | null> {
3742
if (refreshToken) {
3843
const refreshResult = this.refreshAccessToken(refreshToken);
3944
if (refreshResult) {
@@ -43,14 +48,13 @@ export class AuthenticationManager {
4348
const input: GetUserInput = { email: email };
4449
let user = undefined;
4550
try {
46-
user = (await this.getUserService.execute(input)) as User;
51+
user = (await this.getUserService.execute("", input)) as User;
4752
} catch (e) {
4853
return null;
4954
}
50-
if (user && (await bcrypt.compare(password, user.passwordHash))) {
55+
if (user && userType && user.userType === userType && (await bcrypt.compare(password, user.passwordHash))) {
5156
return this.generateTokens(user.id!);
5257
}
53-
console.log("not supposed to be here");
5458
return null;
5559
}
5660

backend/src/application/controller.ts

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createErrorHandler, defaultResponder, ResponderFunction } from "./helpersExpress";
2-
import { ApiError, Request, Response, ErrorCode } from "./types";
2+
import { ApiError, Request, Response, ErrorCode, AuthenticatedRequestBody } from "./types";
33
import { logger } from "../config/logger";
44
import { Service, Services } from "../config/service";
55

@@ -60,6 +60,7 @@ export abstract class Controller {
6060
data: T,
6161
statusCode: number,
6262
operationName: string,
63+
userId: string,
6364
): Promise<Response> {
6465
if (!service) {
6566
this.logger.warn(`${operationName} operation not implemented`);
@@ -69,7 +70,7 @@ export abstract class Controller {
6970
});
7071
}
7172
this.logger.info(`Executing service: ${operationName}`, { statusCode });
72-
const body = await service.execute(data);
73+
const body = await service.execute(userId, data);
7374
return this.respond(statusCode, body);
7475
}
7576

@@ -80,7 +81,13 @@ export abstract class Controller {
8081
* @returns Response with status 200 and entity data
8182
*/
8283
public async getOne<T>(req: Request, data: T): Promise<Response> {
83-
return this._executeService(this.services.get, data, 200, "Get");
84+
return this._executeService(
85+
this.services.get,
86+
data,
87+
200,
88+
"Get",
89+
(req.body as AuthenticatedRequestBody).authenticatedUserId,
90+
);
8491
}
8592

8693
/**
@@ -90,7 +97,13 @@ export abstract class Controller {
9097
* @returns Response with status 200 and list of entities
9198
*/
9299
public async getAll<T>(req: Request, data: T): Promise<Response> {
93-
return this._executeService(this.services.getAll, data, 200, "GetAll");
100+
return this._executeService(
101+
this.services.getAll,
102+
data,
103+
200,
104+
"GetAll",
105+
(req.body as AuthenticatedRequestBody).authenticatedUserId,
106+
);
94107
}
95108

96109
/**
@@ -101,7 +114,13 @@ export abstract class Controller {
101114
* @returns Response with status 200 and list of child entities
102115
*/
103116
public async getChildren<T>(req: Request, data: T, service: Service<T>): Promise<Response> {
104-
return this._executeService(service, data, 200, "GetChildren");
117+
return this._executeService(
118+
service,
119+
data,
120+
200,
121+
"GetChildren",
122+
(req.body as AuthenticatedRequestBody).authenticatedUserId,
123+
);
105124
}
106125

107126
/**
@@ -112,7 +131,13 @@ export abstract class Controller {
112131
* @returns Response with status 201 and created child entity data
113132
*/
114133
public async addChild<T>(req: Request, data: T, service: Service<T>): Promise<Response> {
115-
return this._executeService(service, data, 201, "AddChild");
134+
return this._executeService(
135+
service,
136+
data,
137+
201,
138+
"AddChild",
139+
(req.body as AuthenticatedRequestBody).authenticatedUserId,
140+
);
116141
}
117142

118143
/**
@@ -123,7 +148,13 @@ export abstract class Controller {
123148
* @returns Response with status 204 (No Content)
124149
*/
125150
public async removeChild<T>(req: Request, data: T, service: Service<T>): Promise<Response> {
126-
return this._executeService(service, data, 204, "RemoveChild");
151+
return this._executeService(
152+
service,
153+
data,
154+
204,
155+
"RemoveChild",
156+
(req.body as AuthenticatedRequestBody).authenticatedUserId,
157+
);
127158
}
128159

129160
/**
@@ -133,7 +164,13 @@ export abstract class Controller {
133164
* @returns Response with status 200 and updated entity data
134165
*/
135166
public async update<T>(req: Request, data: T): Promise<Response> {
136-
return this._executeService(this.services.update, data, 204, "Update");
167+
return this._executeService(
168+
this.services.update,
169+
data,
170+
204,
171+
"Update",
172+
(req.body as AuthenticatedRequestBody).authenticatedUserId,
173+
);
137174
}
138175

139176
/**
@@ -143,7 +180,13 @@ export abstract class Controller {
143180
* @returns Response with status 204 (No Content)
144181
*/
145182
public async delete<T>(req: Request, data: T): Promise<Response> {
146-
return this._executeService(this.services.remove, data, 204, "Delete");
183+
return this._executeService(
184+
this.services.remove,
185+
data,
186+
204,
187+
"Delete",
188+
(req.body as AuthenticatedRequestBody).authenticatedUserId,
189+
);
147190
}
148191

149192
/**
@@ -153,6 +196,12 @@ export abstract class Controller {
153196
* @returns Response with status 201 and created entity data
154197
*/
155198
public async create<T>(req: Request, data: T): Promise<Response> {
156-
return this._executeService(this.services.create, data, 201, "Create");
199+
return this._executeService(
200+
this.services.create,
201+
data,
202+
201,
203+
"Create",
204+
(req.body as AuthenticatedRequestBody).authenticatedUserId,
205+
);
157206
}
158207
}

backend/src/application/middleware/loginMiddleware.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Request as ExpressRequest, Response as ExpressResponse } from "express";
2+
import { UserType } from "../../core/entities/user";
23
import { AuthenticationManager } from "../auth";
34
import { defaultErrorHandler, defaultResponder, responseToExpress } from "../helpersExpress";
45
import { ErrorCode } from "../types";
@@ -21,18 +22,23 @@ export function loginMiddleware(
2122
return;
2223
}
2324

24-
const { email, password, refreshToken } = req.body || {};
25-
if (!((email && password) || (!email && !password && refreshToken))) {
25+
const { email, password, userType, refreshToken } = req.body || {};
26+
if (!((email && password && userType) || (!email && !password && !userType && refreshToken))) {
2627
const response = defaultErrorHandler({
2728
code: ErrorCode.BAD_REQUEST,
28-
message: "Email and password or refresh token are required",
29+
message: "Email, password and userType or refresh token are required",
2930
});
3031
responseToExpress(response, res);
3132
return;
3233
}
3334

3435
try {
35-
const tokens = await authManager.authenticate(email || "", password || "", refreshToken);
36+
const tokens = await authManager.authenticate(
37+
email || "",
38+
password || "",
39+
userType as UserType,
40+
refreshToken,
41+
);
3642
if (!tokens) {
3743
const response = defaultErrorHandler({
3844
code: ErrorCode.UNAUTHORIZED,

backend/src/application/resources/taskResource.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ export function taskRoutes(
7979
controller,
8080
extractor: extractors.getTask,
8181
handler: (req, data) => controller.getOne(req, data),
82+
middleware,
8283
},
8384
{
8485
app,
@@ -87,6 +88,7 @@ export function taskRoutes(
8788
controller,
8889
extractor: extractors.getTask,
8990
handler: (req, data) => controller.delete(req, data),
91+
middleware,
9092
},
9193
{
9294
app,

backend/src/application/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ export interface TokenResponse {
8484
refreshToken: string;
8585
}
8686

87+
export interface AuthenticatedRequestBody {
88+
authenticatedUserId: string;
89+
[key: string]: string;
90+
}
91+
8792
/* ************* Path/Routing Types ************* */
8893

8994
/**

backend/src/config/service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//TODO if application layer always asks for an object in return to we need to specify ReturnType?
22
export interface Service<T> {
3-
execute: (input: T) => Promise<object>;
3+
execute: (userId: string, input: T) => Promise<object>;
44
}
55

66
//TODO can we abstract the params type in services to for a Params as abstracted class or interface?

0 commit comments

Comments
 (0)