Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions controllers/applications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ const updateApplication = async (req: CustomRequest, res: CustomResponse) => {
return res.boom.notFound(APPLICATION_ERROR_MESSAGES.APPLICATION_NOT_FOUND);
case APPLICATION_STATUS.unauthorized:
return res.boom.unauthorized(APPLICATION_ERROR_MESSAGES.APPLICATION_EDIT_UNAUTHORIZED);
case APPLICATION_STATUS.notPending:
return res.boom.conflict(APPLICATION_ERROR_MESSAGES.APPLICATION_ALREADY_REVIEWED);
case APPLICATION_STATUS.tooSoon:
return res.boom.conflict(APPLICATION_ERROR_MESSAGES.EDIT_TOO_SOON);
case APPLICATION_STATUS.success:
Expand Down
9 changes: 9 additions & 0 deletions models/applications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ const updateApplication = async (

const application = applicationDoc.data();

const isEditableApplicationStatus =
application.status === APPLICATION_STATUS_TYPES.PENDING ||
application.status === APPLICATION_STATUS_TYPES.CHANGES_REQUESTED;

if (!isEditableApplicationStatus) {
return { status: APPLICATION_STATUS.notPending };
}

if (application.userId !== userId) {
return { status: APPLICATION_STATUS.unauthorized };
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
Expand All @@ -167,6 +175,7 @@ const updateApplication = async (
const requestBody = {
...dataToUpdate,
lastEditAt: new Date(currentTime).toISOString(),
status: APPLICATION_STATUS_TYPES.PENDING,
};
transaction.update(applicationRef, requestBody);

Expand Down
50 changes: 49 additions & 1 deletion test/integration/application.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ const applicationModel = require("../../models/applications");

const applicationsData = require("../fixtures/applications/applications")();
const cookieName = config.get("userToken.cookieName");
const { APPLICATION_ERROR_MESSAGES, API_RESPONSE_MESSAGES, APPLICATION_SCORE } = require("../../constants/application");
const {
APPLICATION_ERROR_MESSAGES,
API_RESPONSE_MESSAGES,
APPLICATION_SCORE,
APPLICATION_STATUS_TYPES,
} = require("../../constants/application");
const imageService = require("../../services/imageService");
const { Buffer } = require("node:buffer");

Expand Down Expand Up @@ -378,6 +383,34 @@ describe("Application", function () {
});
});

it("should set application status to pending after a successful edit from changes_requested", async function () {
const applicationData = {
...applicationsData[1],
userId,
status: APPLICATION_STATUS_TYPES.CHANGES_REQUESTED,
};
const editableApplicationId = await applicationModel.addApplication(applicationData);

expect(applicationData.status).to.equal(APPLICATION_STATUS_TYPES.CHANGES_REQUESTED);

const patchRes = await chai
.request(app)
.patch(`/applications/${editableApplicationId}`)
.set("cookie", `${cookieName}=${jwt}`)
.send({ introduction: "Updated introduction text" });

expect(patchRes).to.have.status(200);
expect(patchRes.body.message).to.be.equal("Application updated successfully");

const getRes = await chai
.request(app)
.get(`/applications/${editableApplicationId}`)
.set("cookie", `${cookieName}=${superUserJwt}`);

expect(getRes).to.have.status(200);
expect(getRes.body.application.status).to.be.equal("pending");
});

it("should return 400 when request body is empty", function (done) {
chai
.request(app)
Expand Down Expand Up @@ -506,6 +539,21 @@ describe("Application", function () {
expect(secondRes.body.message).to.be.equal(APPLICATION_ERROR_MESSAGES.EDIT_TOO_SOON);
});

it("should return 409 when trying to edit an application that has already been reviewed", async function () {
const reviewedApplicationData = { ...applicationsData[1], userId };
const reviewedApplicationId = await applicationModel.addApplication(reviewedApplicationData);

const res = await chai
.request(app)
.patch(`/applications/${reviewedApplicationId}`)
.set("cookie", `${cookieName}=${jwt}`)
.send({ introduction: "Attempt edit after review" });

expect(res).to.have.status(409);
expect(res.body.error).to.be.equal("Conflict");
expect(res.body.message).to.be.equal(APPLICATION_ERROR_MESSAGES.APPLICATION_ALREADY_REVIEWED);
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.

it("should return 200 when updating city, state, and country", async function () {
const applicationData = { ...applicationsData[0], userId };
const testApplicationId = await applicationModel.addApplication(applicationData);
Expand Down
10 changes: 10 additions & 0 deletions test/unit/controllers/applications.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,16 @@ describe("updateApplication", () => {
expect(jsonSpy.called).to.be.false;
});

it("should return 409 when application status is not editable", async () => {
updateApplicationStub.resolves({ status: APPLICATION_STATUS.notPending });

await applicationsController.updateApplication(req as CustomRequest, res as CustomResponse);

expect(boomConflict.calledOnce).to.be.true;
expect(boomConflict.firstCall.args[0]).to.equal(APPLICATION_ERROR_MESSAGES.APPLICATION_ALREADY_REVIEWED);
expect(jsonSpy.called).to.be.false;
});

it("should return 500 when model returns unexpected status", async () => {
updateApplicationStub.resolves({ status: "unknown" });

Expand Down
Loading