Skip to content

Commit a33e9ea

Browse files
authored
feat: added controllere for TCR (#2055)
1 parent 2da9bff commit a33e9ea

File tree

4 files changed

+255
-1
lines changed

4 files changed

+255
-1
lines changed

constants/requests.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,17 @@ export const ERROR_WHILE_UPDATING_REQUEST = "Error while updating request";
3939

4040
export const REQUEST_DOES_NOT_EXIST = "Request does not exist";
4141
export const REQUEST_ALREADY_PENDING = "Request already exists please wait for approval or rejection";
42+
43+
export const TASK_REQUEST_MESSAGES = {
44+
NOT_AUTHORIZED_TO_CREATE_REQUEST: "Not authorized to create the request",
45+
USER_NOT_FOUND: "User not found",
46+
TASK_NOT_EXIST: "Task does not exist",
47+
INVALID_EXTERNAL_ISSUE_URL: "External issue url is not valid",
48+
ISSUE_NOT_EXIST: "Issue does not exist",
49+
TASK_REQUEST_EXISTS: "Task request already exists",
50+
TASK_EXISTS_FOR_GIVEN_ISSUE: "Task exists for the given issue.",
51+
TASK_ALREADY_REQUESTED: "Task was already requested",
52+
TASK_REQUEST_CREATED_SUCCESS: "Task request created successfully",
53+
ERROR_CREATING_TASK_REQUEST: "Error while creating task request",
54+
TASK_REQUEST_UPDATED_SUCCESS: "Task request updated successfully",
55+
};

controllers/requests.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import { CustomResponse } from "../typeDefinitions/global";
1111
import { ExtensionRequestRequest, ExtensionRequestResponse } from "../types/extensionRequests";
1212
import { createTaskExtensionRequest, updateTaskExtensionRequest } from "./extensionRequestsv2";
1313
import { UpdateRequest } from "../types/requests";
14+
import { TaskRequestRequest } from "../types/taskRequests";
15+
import { createTaskRequestController } from "./taskRequestsv2";
1416

1517
export const createRequestController = async (
16-
req: OooRequestCreateRequest | ExtensionRequestRequest,
18+
req: OooRequestCreateRequest | ExtensionRequestRequest | TaskRequestRequest,
1719
res: CustomResponse
1820
) => {
1921
const type = req.body.type;
@@ -22,6 +24,8 @@ export const createRequestController = async (
2224
return await createOooRequestController(req as OooRequestCreateRequest, res as OooRequestResponse);
2325
case REQUEST_TYPE.EXTENSION:
2426
return await createTaskExtensionRequest(req as ExtensionRequestRequest, res as ExtensionRequestResponse);
27+
case REQUEST_TYPE.TASK:
28+
return await createTaskRequestController(req as TaskRequestRequest, res as CustomResponse);
2529
default:
2630
return res.boom.badRequest("Invalid request type");
2731
}

controllers/taskRequestsv2.ts

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import { REQUEST_STATE, TASK_REQUEST_MESSAGES } from "../constants/requests";
2+
import { TASK_REQUEST_TYPE } from "../constants/taskRequests";
3+
import { addLog } from "../models/logs";
4+
import { createRequest, getRequestByKeyValues } from "../models/requests";
5+
import { fetchTask } from "../models/tasks";
6+
import { fetchUser } from "../models/users";
7+
import { fetchIssuesById } from "../services/githubService";
8+
import { CustomResponse } from "../typeDefinitions/global";
9+
import { userData } from "../types/global";
10+
import { TaskRequestRequest } from "../types/taskRequests";
11+
12+
export const createTaskRequestController = async (req: TaskRequestRequest, res: CustomResponse) => {
13+
const taskRequestData = req.body;
14+
const requestedBy = req?.userData?.id;
15+
16+
if (!requestedBy) {
17+
return res.boom.unauthorized();
18+
}
19+
20+
if (req.userData.id !== taskRequestData.userId && !req.userData.roles?.super_user) {
21+
return res.boom.forbidden(TASK_REQUEST_MESSAGES.NOT_AUTHORIZED_TO_CREATE_REQUEST);
22+
}
23+
24+
const userPromise: any = await fetchUser({ userId: taskRequestData.userId });
25+
const userData: userData = userPromise.user;
26+
if (!userData.id || !userData.username) {
27+
return res.boom.notFound(TASK_REQUEST_MESSAGES.USER_NOT_FOUND);
28+
}
29+
try {
30+
switch (taskRequestData.requestType) {
31+
case TASK_REQUEST_TYPE.ASSIGNMENT: {
32+
if (!req.userData.roles?.super_user) {
33+
return res.boom.unauthorized(TASK_REQUEST_MESSAGES.NOT_AUTHORIZED_TO_CREATE_REQUEST);
34+
}
35+
const { taskData } = await fetchTask(taskRequestData.taskId);
36+
if (!taskData) {
37+
return res.boom.badRequest(TASK_REQUEST_MESSAGES.TASK_NOT_EXIST);
38+
}
39+
taskRequestData.taskTitle = taskData?.title;
40+
break;
41+
}
42+
case TASK_REQUEST_TYPE.CREATION: {
43+
let issueData: any;
44+
try {
45+
const url = new URL(taskRequestData.externalIssueUrl);
46+
const issueUrlPaths = url.pathname.split("/");
47+
const repositoryName = issueUrlPaths[3];
48+
const issueNumber = issueUrlPaths[5];
49+
issueData = await fetchIssuesById(repositoryName, issueNumber);
50+
} catch (error) {
51+
return res.boom.badRequest(TASK_REQUEST_MESSAGES.INVALID_EXTERNAL_ISSUE_URL);
52+
}
53+
if (!issueData) {
54+
return res.boom.badRequest(TASK_REQUEST_MESSAGES.ISSUE_NOT_EXIST);
55+
}
56+
taskRequestData.taskTitle = issueData?.title;
57+
break;
58+
}
59+
}
60+
const existingRequest = await getRequestByKeyValues({
61+
externalIssueUrl: taskRequestData.externalIssueUrl,
62+
requestType: taskRequestData.requestType,
63+
});
64+
65+
if (
66+
existingRequest &&
67+
existingRequest.state === REQUEST_STATE.PENDING &&
68+
existingRequest.requestors.includes(requestedBy)
69+
) {
70+
return res.boom.badRequest(TASK_REQUEST_MESSAGES.TASK_REQUEST_EXISTS);
71+
} else if (
72+
existingRequest &&
73+
existingRequest.state === REQUEST_STATE.PENDING &&
74+
!existingRequest.requestors.includes(requestedBy)
75+
) {
76+
existingRequest.requestors.push(requestedBy);
77+
existingRequest.users.push({
78+
userId: userData.id,
79+
username: userData.username,
80+
proposedStartDate: taskRequestData.proposedStartDate,
81+
proposedDeadline: taskRequestData.proposedDeadline,
82+
description: taskRequestData.description,
83+
markdownEnabled: taskRequestData.markdownEnabled,
84+
firstName: userData.first_name,
85+
lastName: userData.last_name,
86+
state: REQUEST_STATE.PENDING,
87+
requestedAt: Date.now(),
88+
});
89+
const updatedRequest = await createRequest(existingRequest);
90+
const taskRequestLog = {
91+
type: "taskRequests",
92+
meta: {
93+
taskRequestId: updatedRequest.id,
94+
action: "update",
95+
createdBy: req.userData.id,
96+
createdAt: Date.now(),
97+
lastModifiedBy: req.userData.id,
98+
lastModifiedAt: Date.now(),
99+
},
100+
body: updatedRequest,
101+
};
102+
await addLog(taskRequestLog.type, taskRequestLog.meta, taskRequestLog.body);
103+
const data = {
104+
message: TASK_REQUEST_MESSAGES.TASK_REQUEST_UPDATED_SUCCESS,
105+
data: {
106+
id: updatedRequest.id,
107+
...updatedRequest,
108+
},
109+
};
110+
return res.status(200).json(data);
111+
}
112+
113+
taskRequestData.requestedBy = requestedBy;
114+
const createtaskRequestData = {
115+
externalIssueUrl: taskRequestData.externalIssueUrl,
116+
externalIssueHtmlUrl: taskRequestData.externalIssueHtmlUrl,
117+
requestType: taskRequestData.requestType,
118+
type: taskRequestData.type,
119+
state: REQUEST_STATE.PENDING,
120+
requestedBy: requestedBy,
121+
taskTitle: taskRequestData.taskTitle,
122+
users: [
123+
{
124+
userId: userData.id,
125+
username: userData.username,
126+
proposedStartDate: taskRequestData.proposedStartDate,
127+
proposedDeadline: taskRequestData.proposedDeadline,
128+
description: taskRequestData.description,
129+
markdownEnabled: taskRequestData.markdownEnabled,
130+
firstName: userData.first_name,
131+
lastName: userData.last_name,
132+
state: REQUEST_STATE.PENDING,
133+
requestedAt: Date.now(),
134+
},
135+
],
136+
137+
requestors: [requestedBy],
138+
};
139+
const newTaskRequest = await createRequest(createtaskRequestData);
140+
141+
if (newTaskRequest.isCreationRequestApproved) {
142+
return res.boom.badRequest(TASK_REQUEST_MESSAGES.TASK_EXISTS_FOR_GIVEN_ISSUE);
143+
}
144+
if (newTaskRequest.alreadyRequesting) {
145+
return res.boom.badRequest(TASK_REQUEST_MESSAGES.TASK_ALREADY_REQUESTED);
146+
}
147+
148+
const taskRequestLog = {
149+
type: "taskRequests",
150+
meta: {
151+
taskRequestId: newTaskRequest.id,
152+
action: "create",
153+
createdBy: req.userData.id,
154+
createdAt: Date.now(),
155+
lastModifiedBy: req.userData.id,
156+
lastModifiedAt: Date.now(),
157+
},
158+
body: newTaskRequest,
159+
};
160+
await addLog(taskRequestLog.type, taskRequestLog.meta, taskRequestLog.body);
161+
162+
const data = {
163+
message: TASK_REQUEST_MESSAGES.TASK_REQUEST_CREATED_SUCCESS,
164+
data: {
165+
id: newTaskRequest.id,
166+
...newTaskRequest,
167+
},
168+
};
169+
return res.status(201).json(data);
170+
} catch (err) {
171+
logger.error(`${TASK_REQUEST_MESSAGES.ERROR_CREATING_TASK_REQUEST} : ${err}`);
172+
return res.boom.serverUnavailable(TASK_REQUEST_MESSAGES.ERROR_CREATING_TASK_REQUEST);
173+
}
174+
};

test/integration/requests.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
REQUEST_ALREADY_REJECTED,
2929
} from "../../constants/requests";
3030
import { updateTask } from "../../models/tasks";
31+
import { validTaskAssignmentRequest, validTaskCreqtionRequest } from "../fixtures/taskRequests/taskRequests";
3132

3233
const userData = userDataFixture();
3334
chai.use(chaiHttp);
@@ -759,3 +760,64 @@ describe("/requests Extension", function () {
759760
});
760761

761762
});
763+
764+
765+
describe("/requests Task", function () {
766+
let userId1: string;
767+
let userJwtToken1: string;
768+
769+
beforeEach(async function () {
770+
userId1 = await addUser(userData[16]);
771+
userJwtToken1 = authService.generateAuthToken({ userId: userId1 });
772+
});
773+
774+
afterEach(async function () {
775+
await cleanDb();
776+
});
777+
778+
describe("POST /requests", function () {
779+
it("should return 401(Unauthorized) if user is not logged in", function (done) {
780+
chai
781+
.request(app)
782+
.post("/requests?dev=true")
783+
.send(validTaskCreqtionRequest)
784+
.end(function (err, res) {
785+
expect(res).to.have.status(401);
786+
done();
787+
});
788+
});
789+
790+
it("should not create a new task request if issue does not exist", function (done) {
791+
let taskRequestObj = validTaskCreqtionRequest
792+
taskRequestObj.externalIssueUrl = "https://api.github.com/repos/Real-Dev-Squad/website-my/issues/1245";
793+
taskRequestObj.userId = userId1;
794+
chai
795+
.request(app)
796+
.post("/requests?dev=true")
797+
.set("cookie", `${cookieName}=${userJwtToken1}`)
798+
.send(taskRequestObj)
799+
.end(function (err, res) {
800+
expect(res).to.have.status(400);
801+
expect(res.body).to.have.property("message");
802+
expect(res.body.message).to.equal("Issue does not exist");
803+
done();
804+
});
805+
});
806+
807+
it("should not create a new task request if task id is not present in the request body", function (done) {
808+
let taskRequestObj = validTaskAssignmentRequest
809+
delete taskRequestObj.taskId;
810+
chai
811+
.request(app)
812+
.post("/requests?dev=true")
813+
.set("cookie", `${cookieName}=${userJwtToken1}`)
814+
.send(taskRequestObj)
815+
.end(function (err, res) {
816+
expect(res).to.have.status(400);
817+
expect(res.body).to.have.property("message");
818+
expect(res.body.message).to.equal('taskId is required when requestType is ASSIGNMENT');
819+
done();
820+
});
821+
});
822+
});
823+
});

0 commit comments

Comments
 (0)