Skip to content

Commit

Permalink
Merge pull request #5 from Ndevu12/ft-apply
Browse files Browse the repository at this point in the history
ft apply
  • Loading branch information
Ndevu12 committed Oct 14, 2024
2 parents 8866c62 + 2418252 commit 356df75
Show file tree
Hide file tree
Showing 12 changed files with 329 additions and 36 deletions.
100 changes: 100 additions & 0 deletions combined.log

Large diffs are not rendered by default.

69 changes: 69 additions & 0 deletions error.log

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"test": "cross-env APP_ENV=test jest --coverage --detectOpenHandles --verbose --runInBand ",
"dev": "cross-env APP_ENV=dev NODE_OPTIONS='--max-old-space-size=4096' nodemon src/app.ts",
"build": "rm -rf node_modules dist && yarn install && tsc -p .",
"start": "node dist/index.js"
"start": "node dist/app.js"
},
"keywords": [],
"author": "",
Expand Down
7 changes: 6 additions & 1 deletion src/controllers/accountController.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Request, Response } from 'express';
import AccountService from '../services/accountService';
import logger from '../utils/logger';

class AccountController {
// Get user information
Expand All @@ -16,7 +17,11 @@ class AccountController {
// Update user information
async updateUser(req: Request, res: Response) {
try {
const { userId } = req.params;
if (!req.user) {
logger.error('User not authenticated', { label: 'AccountController' });
return res.status(400).json({ message: 'User not authenticated' });
}
const userId = req.user.id;
const result = await AccountService.updateUser(userId, req.body, req);
return res.status(result.status).json({ message: result.message, user: result.user });
} catch (error: any) {
Expand Down
60 changes: 58 additions & 2 deletions src/controllers/jobController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Request, Response } from 'express';
import JobService from '../services/jobService';
import logger from '../utils/logger';
import { jobSchema } from '../helpers/validator/JobValidator';
import mongoose from 'mongoose';

class JobController {
// Create a new job entry
Expand All @@ -14,6 +15,8 @@ class JobController {

const { error } = jobSchema.validate(req.body);
if (error) {
logger.info('Invalid input: %o', error.details[0].message);
logger.info('input: ', req.body);
return res.status(400).json({ message: 'Invalid input', error: error.details[0].message });
}

Expand All @@ -29,6 +32,10 @@ class JobController {
async getJobById(req: Request, res: Response) {
try {
const { jobId } = req.params;
if (!jobId || !mongoose.Types.ObjectId.isValid(jobId)) {
logger.info('Invalid Job ID: %s', jobId);
return res.status(400).json({ message: 'Invalid Job ID' });
}
const result = await JobService.getJobById(jobId);
return res.status(result.status).json({ message: result.message, job: result.job });
} catch (error: any) {
Expand All @@ -49,7 +56,11 @@ class JobController {
// Update a job entry
async updateJob(req: Request, res: Response) {
try {
const { jobId } = req.params;
const { jobId } = req.params;
if (!jobId || !mongoose.Types.ObjectId.isValid(jobId)) {
logger.info('Invalid Job ID: %s', jobId);
return res.status(400).json({ message: 'Invalid Job ID' });
}
const result = await JobService.updateJob(jobId, req.body);
return res.status(result.status).json({ message: result.message, job: result.job });
} catch (error: any) {
Expand All @@ -60,13 +71,58 @@ class JobController {
// Delete a job entry
async deleteJob(req: Request, res: Response) {
try {
const { jobId } = req.params;
const { jobId } = req.params;
if (!jobId || !mongoose.Types.ObjectId.isValid(jobId)) {
logger.info('Invalid Job ID: %s', jobId);
return res.status(400).json({ message: 'Invalid Job ID' });
}
const result = await JobService.deleteJob(jobId);
return res.status(result.status).json({ message: result.message });
} catch (error: any) {
return res.status(500).json({ message: 'Server error', error: error.message });
}
}

// Apply for a job with an existing CV
async applyWithExistingCV(req: Request, res: Response) {
try {
const { jobId } = req.params;
if (!req.user) {
logger.info('User not authenticated');
return res.status(400).json({ message: 'Invalid Job ID' });
}
const userId = req.user.id; // Use req.userId from the middleware
if (!jobId || !mongoose.Types.ObjectId.isValid(jobId)) {
logger.info('Invalid Job ID: %s', jobId);
return res.status(400).json({ message: 'Invalid Job ID' });
}
const result = await JobService.applyWithExistingCV(jobId, userId);
return res.status(result.status).json({ message: result.message });
} catch (error: any) {
return res.status(500).json({ message: 'Server error', error: error.message });
}
}

// Apply for a job with a new CV
async applyWithNewCV(req: Request, res: Response) {
try {
const { jobId } = req.params;
if (!req.user) {
logger.info('User not authenticated');
return res.status(400).json({ message: 'Invalid Job ID' });
}
const userId = req.user.id; // Use req.userId from the middleware
const { cv } = req.body;
if (!jobId || !mongoose.Types.ObjectId.isValid(jobId)) {
logger.info('Invalid Job ID: %s', jobId);
return res.status(400).json({ message: 'Invalid Job ID' });
}
const result = await JobService.applyWithNewCV(jobId, userId, cv);
return res.status(result.status).json({ message: result.message });
} catch (error: any) {
return res.status(500).json({ message: 'Server error', error: error.message });
}
}
}

export default new JobController();
2 changes: 1 addition & 1 deletion src/helpers/validator/JobValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const jobSchema = Joi.object({
name: Joi.string().required(),
website: Joi.string().uri().required(),
logo: Joi.string().uri().required(),
logoBackground: Joi.string().required(),
logoBackground: Joi.string().optional(),
}).required(),
contract: Joi.string().required(),
position: Joi.string().required(),
Expand Down
2 changes: 2 additions & 0 deletions src/models/AppliedJob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface IAppliedJob extends Document {
company: string;
userId: string;
appliedAt: Date;
cv: string;
}

const AppliedJobSchema: Schema = new Schema({
Expand All @@ -14,6 +15,7 @@ const AppliedJobSchema: Schema = new Schema({
company: { type: String, default: '' },
userId: { type: String, required: true },
appliedAt: { type: Date, default: null },
cv: { type: String, default: '' }, // Add cv field to schema
});

const AppliedJob = mongoose.model<IAppliedJob>('AppliedJob', AppliedJobSchema);
Expand Down
2 changes: 1 addition & 1 deletion src/models/Company.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const CompanySchema: Schema = new Schema({
website: { type: String, default: '' },
logo: { type: String, default: '' },
userId: { type: String, required: true },
logoBackground: { type: String, default: '' },
logoBackground: { type: String, default: '#FFFFFF' },
});

const Company = mongoose.model<ICompany>('Company', CompanySchema);
Expand Down
2 changes: 2 additions & 0 deletions src/models/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface IUser extends Document {
education?: IEducation[];
experience?: IExperience[];
skills?: ISkill[];
cv?: string; // Add cv property
}

const UserSchema: Schema = new Schema({
Expand All @@ -36,6 +37,7 @@ const UserSchema: Schema = new Schema({
education: [{ type: Schema.Types.ObjectId, ref: 'Education', default: [] }],
experience: [{ type: Schema.Types.ObjectId, ref: 'Experience', default: [] }],
skills: [{ type: Schema.Types.ObjectId, ref: 'Skill', default: [] }],
cv: { type: String, default: '' }, // Add cv field to schema
});

// Middleware to auto-populate sub-models
Expand Down
15 changes: 3 additions & 12 deletions src/routes/accountRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
import { Router } from 'express';
import AccountController from '../controllers/accountController';
import multer from '../middleware/Uploader'
import { isAdminAuth, isAuth } from '../middleware/isAuth';

const router = Router();

// Get user information
router.get('/:userId', AccountController.getUserInfo);

// Update user information
router.put('/:userId', multer.single('profileImage'), AccountController.updateUser);
router.put('/', isAuth, multer.single('profileImage'), AccountController.updateUser);

// Delete user
router.delete('/:userId', AccountController.deleteUser);
router.delete('/:userId', isAdminAuth, AccountController.deleteUser);

export default router;

// import { isAuth } from '../middleware/isAuth'

// const router = Router();

// const accountControllers = new Account();

// router.get('/', isAuth, accountControllers.getAccountInfo);

// export default router;
4 changes: 4 additions & 0 deletions src/routes/jobRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ router.get('/jobs/:jobId', JobController.getJobById);
router.put('/jobs/:jobId', isAuth, JobController.updateJob);
router.delete('/jobs/:jobId', isAuth, JobController.deleteJob);

// Apply routes
router.post('/jobs/:jobId/apply/existing', isAuth , JobController.applyWithExistingCV);
router.post('/jobs/:jobId/apply/new', isAuth, JobController.applyWithNewCV);

export default router;
100 changes: 82 additions & 18 deletions src/services/jobService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import AppliedJob from '../models/AppliedJob';
import Company from '../models/Company';
import Job, { IJob } from '../models/Job';
import User from '../models/User';
import logger from '../utils/logger';

class JobService {
Expand Down Expand Up @@ -47,6 +49,24 @@ class JobService {
}
}

// Get all job entries
async getAllJobs() {
try {
const jobs = await Job.find()
.populate('company')
.populate('appliedJobs')
.populate({
path: 'userId',
select: 'id name profileImage occupation', // Include only specific fields
options: { lean: true }
});
return { status: 200, jobs };
} catch (error: any) {
logger.error('Error getting jobs: %o', error);
return { status: 500, message: 'Server error. Try again later.', error: error.message };
}
}

// Update a job entry
async updateJob(jobId: string, input: Partial<IJob>) {
try {
Expand All @@ -67,24 +87,6 @@ class JobService {
}
}

// Get all job entries
async getAllJobs() {
try {
const jobs = await Job.find()
.populate('company')
.populate('appliedJobs')
.populate({
path: 'userId',
select: 'id name profileImage occupation', // Include only specific fields
options: { lean: true }
});
return { status: 200, jobs };
} catch (error: any) {
logger.error('Error getting jobs: %o', error);
return { status: 500, message: 'Server error. Try again later.', error: error.message };
}
}

// Delete a job entry
async deleteJob(jobId: string) {
try {
Expand All @@ -104,6 +106,68 @@ class JobService {
return { status: 500, message: 'Server error. Try again later.', error: error.message };
}
}

// Apply for a job with an existing CV
async applyWithExistingCV(jobId: string, userId: string) {
try {
const job = await Job.findById(jobId);
if (!job) {
return { status: 404, message: 'Job not found' };
}

const user = await User.findById(userId);
if (!user || !user.cv) {
logger.error('User CV not found');
return { status: 400, message: 'User CV not found' };
}

const appliedJob = new AppliedJob({
jobId,
position: job.position,
company: job.company.toString(),
userId,
appliedAt: new Date(),
cv: user.cv,
});

await appliedJob.save();
job.appliedJobs.push(appliedJob._id as any); // Cast to any to avoid type error
await job.save();

return { status: 200, message: 'Applied successfully' };
} catch (error: any) {
logger.error('Error applying for job: %o', error);
return { status: 500, message: 'Server error. Try again later.', error: error.message };
}
}

// Apply for a job with a new CV
async applyWithNewCV(jobId: string, userId: string, cv: string) {
try {
const job = await Job.findById(jobId);
if (!job) {
return { status: 404, message: 'Job not found' };
}

const appliedJob = new AppliedJob({
jobId,
position: job.position,
company: job.company.toString(),
userId,
appliedAt: new Date(),
cv,
});

await appliedJob.save();
job.appliedJobs.push(appliedJob._id as any);
await job.save();

return { status: 200, message: 'Applied successfully' };
} catch (error: any) {
logger.error('Error applying for job: %o', error);
return { status: 500, message: 'Server error. Try again later.', error: error.message };
}
}
}

export default new JobService();

0 comments on commit 356df75

Please sign in to comment.