Skip to content

Commit 19367cb

Browse files
authored
Merge pull request #3098 from processing/fix/updates-address-outage
Updates to earlier fixes to address outage logs
2 parents a65572b + d1be6eb commit 19367cb

File tree

6 files changed

+143
-189
lines changed

6 files changed

+143
-189
lines changed

server/config/passport.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ function generateUniqueUsername(username) {
2222
}
2323

2424
passport.serializeUser((user, done) => {
25-
done(null, user.id);
25+
if (user) {
26+
done(null, user.id);
27+
} else {
28+
done(new Error('User is not available for serialization.'));
29+
}
2630
});
2731

2832
passport.deserializeUser((id, done) => {

server/controllers/aws.controller.js

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,37 +39,40 @@ export function getObjectKey(url) {
3939
}
4040
return objectKey;
4141
}
42-
42+
// TODO: callback should be removed
4343
export async function deleteObjectsFromS3(keyList, callback) {
4444
const objectsToDelete = keyList?.map((key) => ({ Key: key }));
4545

46-
if (objectsToDelete.length > 0) {
47-
const params = {
48-
Bucket: process.env.S3_BUCKET,
49-
Delete: { Objects: objectsToDelete }
50-
};
46+
if (!objectsToDelete.length) {
47+
callback?.();
48+
return;
49+
}
5150

52-
try {
53-
await s3Client.send(new DeleteObjectsCommand(params));
54-
if (callback) {
55-
callback();
56-
}
57-
} catch (error) {
58-
console.error('Error deleting objects from S3: ', error);
59-
if (callback) {
60-
callback(error);
61-
}
62-
}
63-
} else if (callback) {
64-
callback();
51+
const params = {
52+
Bucket: process.env.S3_BUCKET,
53+
Delete: { Objects: objectsToDelete }
54+
};
55+
56+
try {
57+
const deleteResult = await s3Client.send(new DeleteObjectsCommand(params));
58+
callback?.(null, deleteResult);
59+
} catch (error) {
60+
callback?.(error);
6561
}
6662
}
6763

6864
export function deleteObjectFromS3(req, res) {
6965
const { objectKey, userId } = req.params;
7066
const fullObjectKey = userId ? `${userId}/${objectKey}` : objectKey;
71-
deleteObjectsFromS3([fullObjectKey], () => {
72-
res.json({ success: true });
67+
68+
deleteObjectsFromS3([fullObjectKey], (error, result) => {
69+
if (error) {
70+
return res
71+
.status(500)
72+
.json({ error: 'Failed to delete object from s3.' });
73+
}
74+
75+
return res.json({ success: true, message: 'Object deleted successfully.' });
7376
});
7477
}
7578

server/controllers/project.controller/__test__/deleteProject.test.js

Lines changed: 48 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,112 +3,79 @@
33
*/
44
import { Request, Response } from 'jest-express';
55

6-
import Project, {
7-
createMock,
8-
createInstanceMock
9-
} from '../../../models/project';
6+
import Project from '../../../models/project';
107
import User from '../../../models/user';
118
import deleteProject from '../../project.controller/deleteProject';
129
import { deleteObjectsFromS3 } from '../../aws.controller';
1310

1411
jest.mock('../../../models/project');
1512
jest.mock('../../aws.controller');
1613

17-
describe('project.controller', () => {
18-
describe('deleteProject()', () => {
19-
let ProjectMock;
20-
let ProjectInstanceMock;
21-
22-
beforeEach(() => {
23-
ProjectMock = createMock();
24-
ProjectInstanceMock = createInstanceMock();
25-
});
26-
27-
afterEach(() => {
28-
ProjectMock.restore();
29-
ProjectInstanceMock.restore();
30-
});
14+
// TODO: incomplete test, 500 response status needs to be added
3115

32-
it('returns 403 if project is not owned by authenticated user', (done) => {
33-
const user = new User();
34-
const project = new Project();
35-
project.user = user;
16+
describe('project.controller', () => {
17+
let request;
18+
let response;
3619

37-
const request = new Request();
38-
request.setParams({ project_id: project._id });
39-
request.user = { _id: 'abc123' };
20+
beforeEach(() => {
21+
request = new Request();
22+
response = new Response();
23+
Project.findById = jest.fn();
24+
});
4025

41-
const response = new Response();
26+
afterEach(() => {
27+
request.resetMocked();
28+
response.resetMocked();
29+
});
4230

43-
ProjectMock.expects('findById').resolves(project);
31+
it('returns 403 if project is not owned by authenticated user', async () => {
32+
const user = new User();
33+
const project = new Project();
34+
project.user = user;
4435

45-
const promise = deleteProject(request, response);
36+
request.setParams({ project_id: project._id });
37+
request.user = { _id: 'abc123' };
4638

47-
function expectations() {
48-
expect(response.status).toHaveBeenCalledWith(403);
49-
expect(response.json).toHaveBeenCalledWith({
50-
message: 'Authenticated user does not match owner of project'
51-
});
39+
Project.findById.mockResolvedValue(project);
5240

53-
done();
54-
}
41+
await deleteProject(request, response);
5542

56-
promise.then(expectations, expectations).catch(expectations);
43+
expect(response.status).toHaveBeenCalledWith(403);
44+
expect(response.json).toHaveBeenCalledWith({
45+
message: 'Authenticated user does not match owner of project'
5746
});
47+
});
5848

59-
it('returns 404 if project does not exist', (done) => {
60-
const user = new User();
61-
const project = new Project();
62-
project.user = user;
63-
64-
const request = new Request();
65-
request.setParams({ project_id: project._id });
66-
request.user = { _id: 'abc123' };
67-
68-
const response = new Response();
69-
70-
ProjectMock.expects('findById').resolves(null);
71-
72-
const promise = deleteProject(request, response);
49+
it('returns 404 if project does not exist', async () => {
50+
request.setParams({ project_id: 'random_id' });
51+
request.user = { _id: 'abc123' };
7352

74-
function expectations() {
75-
expect(response.status).toHaveBeenCalledWith(404);
76-
expect(response.json).toHaveBeenCalledWith({
77-
message: 'Project with that id does not exist'
78-
});
53+
Project.findById.mockResolvedValue(null);
7954

80-
done();
81-
}
55+
await deleteProject(request, response);
8256

83-
promise.then(expectations, expectations).catch(expectations);
57+
expect(response.status).toHaveBeenCalledWith(404);
58+
expect(response.json).toHaveBeenCalledWith({
59+
message: 'Project with that id does not exist'
8460
});
61+
});
8562

86-
it('deletes project and dependent files from S3 ', (done) => {
87-
const user = new User();
88-
const project = new Project();
89-
project.user = user;
90-
91-
const request = new Request();
92-
request.setParams({ project_id: project._id });
93-
request.user = { _id: user._id };
94-
95-
const response = new Response();
96-
97-
ProjectMock.expects('findById').resolves(project);
98-
99-
ProjectInstanceMock.expects('remove').yields();
63+
it('delete project and dependent files from S3', async () => {
64+
const user = new User();
65+
const project = new Project();
66+
project.user = user;
67+
project.remove = jest.fn().mockResolvedValue();
10068

101-
const promise = deleteProject(request, response);
69+
request.setParams({ project_id: project._id });
70+
request.user = { _id: user._id };
10271

103-
function expectations() {
104-
expect(response.status).toHaveBeenCalledWith(200);
105-
expect(response.json).not.toHaveBeenCalled();
106-
expect(deleteObjectsFromS3).toHaveBeenCalled();
72+
Project.findById.mockResolvedValue(project);
73+
deleteObjectsFromS3.mockResolvedValue();
10774

108-
done();
109-
}
75+
await deleteProject(request, response);
11076

111-
promise.then(expectations, expectations).catch(expectations);
112-
});
77+
expect(response.status).toHaveBeenCalledWith(200);
78+
expect(deleteObjectsFromS3).toHaveBeenCalled();
79+
expect(project.remove).toHaveBeenCalled();
11380
});
11481
});

server/controllers/project.controller/deleteProject.js

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,45 +7,42 @@ const ProjectDeletionError = createApplicationErrorClass(
77
'ProjectDeletionError'
88
);
99

10-
function deleteFilesFromS3(files) {
11-
deleteObjectsFromS3(
12-
files
13-
.filter((file) => {
14-
if (
15-
file.url &&
10+
async function deleteFilesFromS3(files) {
11+
const filteredFiles = files
12+
.filter((file) => {
13+
const isValidFile =
14+
(file.url &&
1615
(file.url.includes(process.env.S3_BUCKET_URL_BASE) ||
17-
file.url.includes(process.env.S3_BUCKET))
18-
) {
19-
if (
20-
!process.env.S3_DATE ||
21-
(process.env.S3_DATE &&
22-
isBefore(new Date(process.env.S3_DATE), new Date(file.createdAt)))
23-
) {
24-
return true;
25-
}
26-
}
27-
return false;
28-
})
29-
.map((file) => getObjectKey(file.url))
30-
);
16+
file.url.includes(process.env.S3_BUCKET)) &&
17+
!process.env.S3_DATE) ||
18+
(process.env.S3_DATE &&
19+
isBefore(new Date(process.env.S3_DATE), new Date(file.createdAt)));
20+
21+
return isValidFile;
22+
})
23+
.map((file) => getObjectKey(file.url));
24+
25+
try {
26+
await deleteObjectsFromS3(filteredFiles);
27+
} catch (error) {
28+
console.error('Failed to delete files from S3:', error);
29+
}
3130
}
3231

33-
export default function deleteProject(req, res) {
34-
function sendFailure(error) {
32+
export default async function deleteProject(req, res) {
33+
const sendFailure = (error) => {
3534
res.status(error.code).json({ message: error.message });
36-
}
35+
};
3736

38-
function sendProjectNotFound() {
39-
sendFailure(
40-
new ProjectDeletionError('Project with that id does not exist', {
41-
code: 404
42-
})
43-
);
44-
}
37+
try {
38+
const project = await Project.findById(req.params.project_id);
4539

46-
function handleProjectDeletion(project) {
47-
if (project == null) {
48-
sendProjectNotFound();
40+
if (!project) {
41+
sendFailure(
42+
new ProjectDeletionError('Project with that id does not exist', {
43+
code: 404
44+
})
45+
);
4946
return;
5047
}
5148

@@ -59,19 +56,20 @@ export default function deleteProject(req, res) {
5956
return;
6057
}
6158

62-
deleteFilesFromS3(project.files);
63-
64-
project.remove((removeProjectError) => {
65-
if (removeProjectError) {
66-
sendProjectNotFound();
67-
return;
68-
}
59+
try {
60+
await deleteFilesFromS3(project.files);
61+
} catch (error) {
62+
sendFailure(
63+
new ProjectDeletionError('Failed to delete associated project files.', {
64+
code: 500
65+
})
66+
);
67+
return;
68+
}
6969

70-
res.status(200).end();
71-
});
70+
await project.remove();
71+
res.status(200).end();
72+
} catch (error) {
73+
sendFailure(error);
7274
}
73-
74-
return Project.findById(req.params.project_id)
75-
.then(handleProjectDeletion)
76-
.catch(sendFailure);
7775
}

server/models/user.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ userSchema.methods.comparePassword = async function comparePassword(
163163
candidatePassword
164164
) {
165165
if (!this.password) {
166-
console.error('No password is set for this user.');
167166
return false;
168167
}
169168

0 commit comments

Comments
 (0)