Source: models/jobPosting.js

const mongoose = require("mongoose");
const Organization = require("./organization");
const Skill = require("./skill");
const Course = require("./course");

/**
 * Defines a job posting on the website created by an organization that is visible to
 * job seekers.
 */
const JobPosting = new mongoose.Schema({
  organization: {
    type: mongoose.Schema.Types.ObjectId,
    ref: Organization.modelName,
    autopopulate: true,
  },
  jobTitle: {
    type: String,
    default: "",
  },
  zipCode: {
    type: String,
    default: "",
  },
  salary: {
    type: String,
    default: "",
  },
  location: {
    type: String,
    default: "",
  },
  benefits: {
    type: String,
    default: "",
  },
  description: {
    type: String,
    default: "",
  },
  amountOfJobs: {
    type: String,
    default: "",
  },
  jobTimeline: {
    type: String,
    default: "",
  },
  responsibilities: {
    type: String,
    default: "",
  },
  skills: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: Skill.modelName,
      autopopulate: true,
    },
  ],
  courses: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: Course.modelName,
      autopopulate: true,
    },
  ],
});

/**
 * Finds a single job posting based on the ID provided.
 *
 * @param id The id of the job posting to retrieve.
 * @returns {Promise<JobPosting>}
 */
JobPosting.statics.getJobPosting = async function (id) {
  return await this.findById(id).exec();
};

/**
 * Search all job postings and find the ones that match the given filters.
 * All filters should be provided in an object to the search function.
 *
 * @param zipCode Filter the job posting by the zip code it is located in.
 * @param skills Filter the job posting by skills that the job is looking for.
 * @returns {Promise<JobPosting[]>}
 */
JobPosting.statics.search = async function ({ zipCode, skills }) {
  let filter = {};
  if (zipCode && zipCode.length > 0) filter.zipCode = zipCode;
  if (skills && skills.length > 0) filter.skills = { $all: skills };

  return await this.find(filter).exec();
};

/**
 * Set the organization for a given job posting by the organization name.  If the organization
 * is not found in the system, a new one will be created.
 *
 * @param organization The name of the organization to set tis JobPosting to.
 * @returns {Promise<JobPosting>}
 */
JobPosting.methods.setOrganization = async function (organization) {
  let org = await Organization.findOneOrCreate(organization);
  this.organization = org._id;
  await this.save();
  return this;
};

/**
 * Add multiple required skills to this job posting by their IDs.
 *
 * @param skills A list of object IDs corresponding to the skills that should be added.
 * @returns {Promise<JobPosting>}
 */
JobPosting.methods.addSkills = async function (skills) {
  let skillEntries = await Skill.find({ _id: { $in: skills } }).exec();
  this.skills = this.skills.concat(skillEntries);
  await this.save();
  return this;
};

/**
 * Removes a skill from the job posting by the given id.  This does not delete the skill from the system.
 *
 * @param id The id of the skill to remove from the job posting
 * @returns {Promise<JobPosting>}
 */
JobPosting.methods.removeSkill = async function (id) {
  // Handle both the auto-populated object and the non auto-populated one.
  this.skills = this.skills.filter((skill) => {
    if (skill._id) return !skill._id.equals(id);
    return !skill.equals(id);
  });
  await this.save();
  return this;
};

/**
 * Add multiple suggested courses to this job posting by their IDs.
 *
 * @param courses A list of object IDs corresponding to the courses that should be added.
 * @returns {Promise<JobPosting>}
 */
JobPosting.methods.addCourses = async function (courses) {
  let courseEntries = await Course.find({ _id: { $in: courses } }).exec();
  this.courses = this.courses.concat(courseEntries);
  await this.save();
  return this;
};

/**
 * Removes a course from the job posting by the given id.  This does not delete the course from the system.
 *
 * @param id The id of the course to remove from the job posting
 * @returns {Promise<JobPosting>}
 */
JobPosting.methods.removeCourse = async function (id) {
  // Handle both the auto-populated object and the non auto-populated one.
  this.courses = this.courses.filter((course) => {
    if (course._id) return !course._id.equals(id);
    return !course.equals(id);
  });
  await this.save();
  return this;
};

module.exports = mongoose.model("JobPosting", JobPosting);