Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
9 changes: 9 additions & 0 deletions apps/api/src/controllers/jobBudgetValidation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function validateJobBudgetRange(budgetMin, budgetMax) {
if (budgetMin !== undefined && budgetMax !== undefined && Number(budgetMax) < Number(budgetMin)) {
return {
valid: false,
message: "budgetMax cannot be less than budgetMin"
};
}
return { valid: true };
}
14 changes: 14 additions & 0 deletions apps/api/src/controllers/uploadFileValidation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export function handleFileUploadRequest(req, res) {
if (!req.file) {
return res.status(400).json({
success: false,
message: "File is required"
});
}

return res.status(201).json({
success: true,
status: "uploaded",
filename: req.file.filename || req.file.originalname
});
}
4 changes: 4 additions & 0 deletions apps/api/src/routes/authenticatedUploadRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export function registerAuthenticatedUploadRoute(router, authMiddleware, uploadMiddleware, uploadFileController) {
router.post("/", authMiddleware, uploadMiddleware.single("file"), uploadFileController);
return router;
}
4 changes: 4 additions & 0 deletions apps/api/src/routes/uploadRoutesSecurity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export function applyUploadAuthProtection(router, uploadMiddleware, authMiddleware, uploadFileHandler) {
router.post("/", authMiddleware, uploadMiddleware.single("file"), uploadFileHandler);
return router;
}
20 changes: 20 additions & 0 deletions apps/api/src/routes/uploadRoutesSecurity.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { applyUploadAuthProtection } from './uploadRoutesSecurity';

describe('Upload Route Security Protection', () => {
it('should register authMiddleware before upload processing', () => {
const postCalls = [];
const mockRouter = {
post: (...args) => postCalls.push(args)
};
const mockUpload = { single: () => 'uploadSingleMiddleware' };
const mockAuth = 'authMiddleware';
const mockHandler = 'uploadFileHandler';

applyUploadAuthProtection(mockRouter, mockUpload, mockAuth, mockHandler);

expect(postCalls.length).toBe(1);
expect(postCalls[0][0]).toBe('/');
expect(postCalls[0][1]).toBe(mockAuth);
expect(postCalls[0][2]).toBe('uploadSingleMiddleware');
});
});
14 changes: 14 additions & 0 deletions apps/api/src/tests/authenticatedUpload.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { registerAuthenticatedUploadRoute } from '../routes/authenticatedUploadRoutes';

describe('Authenticated Upload Route Security', () => {
it('should register authMiddleware before upload processing', () => {
const router = { post: jest.fn() };
const authMiddleware = jest.fn();
const uploadMiddleware = { single: jest.fn().mockReturnValue('multerMiddleware') };
const uploadFileController = jest.fn();

registerAuthenticatedUploadRoute(router, authMiddleware, uploadMiddleware, uploadFileController);

expect(router.post).toHaveBeenCalledWith("/", authMiddleware, "multerMiddleware", uploadFileController);
});
});
14 changes: 14 additions & 0 deletions apps/api/src/tests/jobBudgetValidation.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { validateJobBudgetRange } from '../controllers/jobBudgetValidation';

describe('Job Budget Range Validation', () => {
it('should reject inverted budget ranges where budgetMax < budgetMin', () => {
const result = validateJobBudgetRange(500, 100);
expect(result.valid).toBe(false);
expect(result.message).toBe("budgetMax cannot be less than budgetMin");
});

it('should accept valid ordered budget ranges where budgetMax >= budgetMin', () => {
const result = validateJobBudgetRange(100, 500);
expect(result.valid).toBe(true);
});
});
36 changes: 36 additions & 0 deletions apps/api/src/tests/uploadValidation.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { handleFileUploadRequest } from '../controllers/uploadFileValidation';

describe('File Upload Controller Validation', () => {
it('should return HTTP 400 when file is missing', () => {
const req = {};
const res = {
status: jest.fn().mockReturnThis(),
json: jest.fn()
};

handleFileUploadRequest(req, res);

expect(res.status).toHaveBeenCalledWith(400);
expect(res.json).toHaveBeenCalledWith({
success: false,
message: "File is required"
});
});

it('should return HTTP 201 when valid file is provided', () => {
const req = { file: { filename: 'test.png' } };
const res = {
status: jest.fn().mockReturnThis(),
json: jest.fn()
};

handleFileUploadRequest(req, res);

expect(res.status).toHaveBeenCalledWith(201);
expect(res.json).toHaveBeenCalledWith({
success: true,
status: "uploaded",
filename: "test.png"
});
});
});
Loading