jp-shared 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/configs/firebase-admin.js +24 -0
- package/configs/index.js +3 -0
- package/constants/configuration.js +6 -0
- package/constants/database.js +6 -0
- package/constants/index.js +6 -0
- package/constants/org.js +30 -0
- package/constants/time-constant.js +4 -0
- package/helpers/index.js +4 -0
- package/helpers/otp-helper.js +48 -0
- package/helpers/validateMongoId.js +13 -0
- package/index.js +15 -0
- package/models/admin-models/admin-model.js +62 -0
- package/models/admin-models/index.js +4 -0
- package/models/admin-models/token-model.js +20 -0
- package/models/candidate-models/candidateModel.js +375 -0
- package/models/candidate-models/index.js +8 -0
- package/models/candidate-models/mobileOTPModel.js +75 -0
- package/models/candidate-models/otpModel.js +75 -0
- package/models/candidate-models/requestModel.js +26 -0
- package/models/candidate-models/savedJobModel.js +20 -0
- package/models/candidate-models/searchAppearanceModel.js +50 -0
- package/models/candidate-models/tokenModel.js +20 -0
- package/models/common-models/course-model.js +20 -0
- package/models/common-models/downloadedResumeHistory-model.js +54 -0
- package/models/common-models/education-model.js +17 -0
- package/models/common-models/index.js +19 -0
- package/models/common-models/jobApplication-model.js +57 -0
- package/models/common-models/jobApproach-model.js +14 -0
- package/models/common-models/jobOffer-model.js +20 -0
- package/models/common-models/jobType-model.js +22 -0
- package/models/common-models/noticePeriod.js +14 -0
- package/models/common-models/paymentHistory-model.js +128 -0
- package/models/common-models/plan-model.js +144 -0
- package/models/common-models/role-model.js +22 -0
- package/models/common-models/searchAppearanceHistory-model.js +36 -0
- package/models/common-models/skill-model.js +21 -0
- package/models/common-models/sms-student-model.js +44 -0
- package/models/common-models/speakingLanguage.js +14 -0
- package/models/common-models/specialization-model.js +20 -0
- package/models/common-models/viewedProfileHistory-model.js +44 -0
- package/models/index.js +8 -0
- package/models/jobPost-models/active-model.js +71 -0
- package/models/jobPost-models/draft-model.js +42 -0
- package/models/jobPost-models/expired-model.js +46 -0
- package/models/jobPost-models/index.js +10 -0
- package/models/jobPost-models/invitation-model.js +72 -0
- package/models/jobPost-models/onHold-model.js +58 -0
- package/models/jobPost-models/pending-model.js +45 -0
- package/models/jobPost-models/rejected-model.js +51 -0
- package/models/jobPost-models/verification-model.js +50 -0
- package/models/organization-models/active-model.js +111 -0
- package/models/organization-models/index.js +4 -0
- package/models/organization-models/verification-model.js +52 -0
- package/models/recruiter-models/active-model.js +45 -0
- package/models/recruiter-models/basicDetail-model.js +113 -0
- package/models/recruiter-models/counter-model.js +13 -0
- package/models/recruiter-models/emailOTP-model.js +68 -0
- package/models/recruiter-models/index.js +10 -0
- package/models/recruiter-models/mobileOTP-model.js +88 -0
- package/models/recruiter-models/pending-model.js +44 -0
- package/models/recruiter-models/request-model.js +75 -0
- package/models/recruiter-models/token-model.js +15 -0
- package/models/recruiter-models/verification-model.js +63 -0
- package/package.json +28 -0
- package/schemes/address-schema.js +43 -0
- package/schemes/index.js +7 -0
- package/schemes/pendingJobPostStep1-schema.js +192 -0
- package/schemes/pendingJobPostStep2-scheme.js +117 -0
- package/schemes/pendingJobPostStep3-scheme.js +21 -0
- package/schemes/pendingJobPostStep4-scheme.js +22 -0
- package/utils/env-utils.js +12 -0
- package/utils/firebase-utils.js +220 -0
- package/utils/index.js +12 -0
- package/utils/invoiceTemplate.js +123 -0
- package/utils/otp-utils.js +23 -0
- package/utils/password-utils.js +49 -0
- package/utils/percentageWeights.js +106 -0
- package/utils/populate-utils.js +57 -0
- package/utils/sendEmail-utils.js +40 -0
- package/utils/sendInvoice-utils.js +139 -0
- package/utils/token-utils.js +18 -0
- package/utils/validate-utils.js +118 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require("dotenv").config();
|
|
2
|
+
const admin = require("firebase-admin");
|
|
3
|
+
|
|
4
|
+
// console.log(process.env.MY_FIREBASE_SERVICE_ACCOUNT, "serviceAccount");
|
|
5
|
+
|
|
6
|
+
const serviceAccount = JSON.parse(process.env.MY_FIREBASE_SERVICE_ACCOUNT);
|
|
7
|
+
|
|
8
|
+
if (!serviceAccount) {
|
|
9
|
+
console.error(
|
|
10
|
+
"MY_FIREBASE_SERVICE_ACCOUNT is not set in the environment or is invalid."
|
|
11
|
+
);
|
|
12
|
+
process.exit(1); // Exit the process if the service account is not set
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Initialize Firebase Admin SDK
|
|
16
|
+
admin.initializeApp({
|
|
17
|
+
credential: admin.credential.cert(serviceAccount),
|
|
18
|
+
storageBucket: process.env.STORAGE_BUCKET_NAME, // Ensure this matches your Firebase storage bucket
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const storage = admin.storage();
|
|
22
|
+
const bucket = storage.bucket();
|
|
23
|
+
|
|
24
|
+
module.exports = { bucket };
|
package/configs/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
// Configuration constants
|
|
3
|
+
REGION: "asia-south1",
|
|
4
|
+
MONGO_URI: `mongodb+srv://${process.env.MONGODB_USERNAME}:${process.env.MONGODB_PASSWORD}@oceanacademy.atrtb.mongodb.net/?retryWrites=true&w=majority&appName=OceanAcademy`,
|
|
5
|
+
MONGO_OPTIONS: { maxPoolSize: 20 }, // Connection Pooling
|
|
6
|
+
};
|
package/constants/org.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const COMPANY_NAME = "Ocean Academy IT Solution";
|
|
2
|
+
const COMPANY_ADDRESS =
|
|
3
|
+
"No. 10, 2nd Floor, 45 Feet Road, Vengateswara Nagar, Near HDFC Bank, Saram, Puducherry-605013.";
|
|
4
|
+
const LOGO_URL =
|
|
5
|
+
"https://recruiter.oceanacademy.co.in/assets/recuiterLogo-Pau498dW.png";
|
|
6
|
+
const SUPPORT_EMAIL = "Oceanacademy@gmail.com";
|
|
7
|
+
const SUPPORT_MOBILE = "9458348957";
|
|
8
|
+
const GST_NUMBER = "85734985fhjd92347128";
|
|
9
|
+
const TERMS_URL = "https://recruiter.oceanacademy.co.in/terms-condition";
|
|
10
|
+
|
|
11
|
+
const OUR_ORG_INFO = {
|
|
12
|
+
companyName: COMPANY_NAME,
|
|
13
|
+
companyAddress: COMPANY_ADDRESS,
|
|
14
|
+
logoUrl: LOGO_URL,
|
|
15
|
+
supportEmail: SUPPORT_EMAIL,
|
|
16
|
+
supportMobile: SUPPORT_MOBILE,
|
|
17
|
+
gstNumber: GST_NUMBER,
|
|
18
|
+
termsUrl: TERMS_URL,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
OUR_ORG_INFO,
|
|
23
|
+
LOGO_URL,
|
|
24
|
+
COMPANY_ADDRESS,
|
|
25
|
+
COMPANY_NAME,
|
|
26
|
+
SUPPORT_EMAIL,
|
|
27
|
+
SUPPORT_MOBILE,
|
|
28
|
+
GST_NUMBER,
|
|
29
|
+
TERMS_URL,
|
|
30
|
+
};
|
package/helpers/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Helper function to send OTP via SMS
|
|
2
|
+
const axios = require("axios");
|
|
3
|
+
|
|
4
|
+
const sendOTPviaSMS = async (name, mobileNumber, otpCode) => {
|
|
5
|
+
// Validate name
|
|
6
|
+
if (!name || typeof name !== "string" || name.trim().length === 0) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
"Invalid or missing name. Name must be a non-empty string."
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Validate mobile number
|
|
13
|
+
if (
|
|
14
|
+
!mobileNumber ||
|
|
15
|
+
typeof mobileNumber !== "string" ||
|
|
16
|
+
!/^\d{10}$/.test(mobileNumber)
|
|
17
|
+
) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
"Invalid or missing mobile number. It must be exactly 10 digits."
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Validate OTP code as a string
|
|
24
|
+
if (!otpCode || typeof otpCode !== "string" || !/^\d{4,6}$/.test(otpCode)) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"Invalid or missing OTP. OTP must be a string with 4 to 6 digits."
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Construct the message
|
|
31
|
+
const message = `Dear ${name}, Your OTP is: ${otpCode}. Please enter this code to verify your identity. Do not share this OTP with anyone. - OCEAN ACADEMY`;
|
|
32
|
+
|
|
33
|
+
// Construct the SMS URL
|
|
34
|
+
const smsUrl = `https://sapteleservices.com/SMS_API/sendsms.php?username=oceanacademy&password=Ocean@123&mobile=${mobileNumber}&sendername=OCEAJP&message=${encodeURIComponent(
|
|
35
|
+
message
|
|
36
|
+
)}&routetype=1&tid=1707172233290230214`;
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
// Send the SMS
|
|
40
|
+
await axios.get(smsUrl);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
// Log and rethrow the error
|
|
43
|
+
console.error("Error in sendOTPviaSMS:", error.message);
|
|
44
|
+
throw new Error("Failed to send OTP. Reason: " + error.message);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
module.exports = { sendOTPviaSMS };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
|
|
3
|
+
// Helper function to check if an array contains valid MongoDB ObjectIds
|
|
4
|
+
const areValidObjectIds = (ids) =>
|
|
5
|
+
ids.every((id) => mongoose.Types.ObjectId.isValid(id));
|
|
6
|
+
|
|
7
|
+
// Helper function to check if it contains valid MongoDB ObjectIds
|
|
8
|
+
const isValidObjectId = (id) => mongoose.Types.ObjectId.isValid(id);
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
areValidObjectIds,
|
|
12
|
+
isValidObjectId,
|
|
13
|
+
};
|
package/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const configs = require("./configs");
|
|
2
|
+
const constants = require("./constants");
|
|
3
|
+
const helpers = require("./helpers");
|
|
4
|
+
const models = require("./models");
|
|
5
|
+
const schemes = require("./schemes");
|
|
6
|
+
const utils = require("./utils");
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
configs,
|
|
10
|
+
constants,
|
|
11
|
+
helpers,
|
|
12
|
+
models,
|
|
13
|
+
schemes,
|
|
14
|
+
utils,
|
|
15
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
const { hashPassword } = require("../../utils");
|
|
3
|
+
const { getDatabaseName } = require("../../constants");
|
|
4
|
+
|
|
5
|
+
// Define the schema with validation and best practices
|
|
6
|
+
const schema = new mongoose.Schema(
|
|
7
|
+
{
|
|
8
|
+
email: {
|
|
9
|
+
type: String,
|
|
10
|
+
required: true,
|
|
11
|
+
unique: true,
|
|
12
|
+
lowercase: true,
|
|
13
|
+
trim: true,
|
|
14
|
+
validate: {
|
|
15
|
+
validator: function (v) {
|
|
16
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v);
|
|
17
|
+
},
|
|
18
|
+
message: (props) => `${props.value} is not a valid email!`,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
otp: {
|
|
22
|
+
type: String,
|
|
23
|
+
required: true,
|
|
24
|
+
// minlength: 6, // Ensure a minimum OTP length
|
|
25
|
+
// maxlength: 6, // Ensure a maximum OTP length
|
|
26
|
+
},
|
|
27
|
+
sentAt: {
|
|
28
|
+
type: Date,
|
|
29
|
+
required: true,
|
|
30
|
+
default: Date.now,
|
|
31
|
+
},
|
|
32
|
+
expiresAt: {
|
|
33
|
+
type: Date,
|
|
34
|
+
required: true,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
timestamps: true, // Automatically adds createdAt and updatedAt fields
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// Pre-save hook to hash the OTP before saving
|
|
43
|
+
schema.pre("save", async function (next) {
|
|
44
|
+
if (!this.isModified("otp")) {
|
|
45
|
+
return next();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
this.otp = await hashPassword(this.otp); // Hash the OTP
|
|
50
|
+
next();
|
|
51
|
+
} catch (error) {
|
|
52
|
+
next(error); // Pass the error to the next middleware
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Using a separate database instance
|
|
57
|
+
const myDB = mongoose.connection.useDb(getDatabaseName());
|
|
58
|
+
|
|
59
|
+
// Model definition
|
|
60
|
+
const AdminModel = myDB.model("Admin", schema);
|
|
61
|
+
|
|
62
|
+
module.exports = AdminModel;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
const { getDatabaseName } = require("../../constants");
|
|
3
|
+
|
|
4
|
+
const schema = new mongoose.Schema({
|
|
5
|
+
adminId: {
|
|
6
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
7
|
+
ref: "Admin", // Reference to the Admin model
|
|
8
|
+
required: true,
|
|
9
|
+
},
|
|
10
|
+
token: {
|
|
11
|
+
type: String,
|
|
12
|
+
required: true,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const myDB = mongoose.connection.useDb(getDatabaseName());
|
|
17
|
+
|
|
18
|
+
const AdminTokenModel = myDB.model("admin-token", schema);
|
|
19
|
+
|
|
20
|
+
module.exports = AdminTokenModel;
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
const { percentageWeights } = require("../../utils");
|
|
3
|
+
const { getDatabaseName } = require("../../constants");
|
|
4
|
+
const { ObjectId } = mongoose.Types;
|
|
5
|
+
|
|
6
|
+
// Enum Definitions
|
|
7
|
+
const WORK_STATUS = ["fresher", "experienced", null];
|
|
8
|
+
const MARITAL_STATUS = [
|
|
9
|
+
"married",
|
|
10
|
+
"unmarried",
|
|
11
|
+
"widowed",
|
|
12
|
+
"divorced",
|
|
13
|
+
"separated",
|
|
14
|
+
"other",
|
|
15
|
+
null,
|
|
16
|
+
];
|
|
17
|
+
const GENDER = ["male", "female", "other", null];
|
|
18
|
+
const PROJECT_STATUS = ["completed", "notCompleted", null];
|
|
19
|
+
|
|
20
|
+
const educationSchema = new mongoose.Schema({
|
|
21
|
+
_id: { type: ObjectId, auto: true },
|
|
22
|
+
qualificationId: { type: ObjectId, required: true },
|
|
23
|
+
// qualification: { type: String, required: true },
|
|
24
|
+
specializationId: {
|
|
25
|
+
type: ObjectId,
|
|
26
|
+
required: function () {
|
|
27
|
+
return !this.isOther;
|
|
28
|
+
},
|
|
29
|
+
default: null,
|
|
30
|
+
},
|
|
31
|
+
// specialization: { type: String, required: true },
|
|
32
|
+
courseId: {
|
|
33
|
+
type: ObjectId,
|
|
34
|
+
required: function () {
|
|
35
|
+
return !this.isOther;
|
|
36
|
+
},
|
|
37
|
+
default: null,
|
|
38
|
+
},
|
|
39
|
+
// course: { type: String, required: true },
|
|
40
|
+
institute: { type: String, required: true },
|
|
41
|
+
courseType: { type: String, required: true },
|
|
42
|
+
courseStartYear: {
|
|
43
|
+
type: Number,
|
|
44
|
+
required: true,
|
|
45
|
+
validate: {
|
|
46
|
+
validator: Number.isInteger,
|
|
47
|
+
message: "Course start year must be an integer.",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
courseEndYear: {
|
|
51
|
+
type: Number,
|
|
52
|
+
required: true,
|
|
53
|
+
validate: [
|
|
54
|
+
{
|
|
55
|
+
validator: Number.isInteger,
|
|
56
|
+
message: "Course end year must be an integer.",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
validator: function (value) {
|
|
60
|
+
return this.courseStartYear <= value;
|
|
61
|
+
},
|
|
62
|
+
message:
|
|
63
|
+
"Course start year must be less than or equal to course end year.",
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
courseStartMonth: {
|
|
68
|
+
type: Number,
|
|
69
|
+
required: true,
|
|
70
|
+
min: 1,
|
|
71
|
+
max: 12,
|
|
72
|
+
},
|
|
73
|
+
courseEndMonth: {
|
|
74
|
+
type: Number,
|
|
75
|
+
required: true,
|
|
76
|
+
min: 1,
|
|
77
|
+
max: 12,
|
|
78
|
+
validate: {
|
|
79
|
+
validator: function (value) {
|
|
80
|
+
if (this.courseStartYear === this.courseEndYear) {
|
|
81
|
+
return this.courseStartMonth <= value;
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
},
|
|
85
|
+
message:
|
|
86
|
+
"Course start month must be less than or equal to course end month within the same year.",
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
markPercentage: { type: Number, default: null },
|
|
90
|
+
isPrimary: { type: Boolean, required: true },
|
|
91
|
+
isOther: { type: Boolean, default: false },
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const schoolSchema = new mongoose.Schema({
|
|
95
|
+
_id: { type: ObjectId, auto: true },
|
|
96
|
+
qualification: { type: String, required: true },
|
|
97
|
+
schoolBoard: { type: String, required: true },
|
|
98
|
+
schoolPassedOutYear: {
|
|
99
|
+
type: Number,
|
|
100
|
+
required: true,
|
|
101
|
+
validate: {
|
|
102
|
+
validator: Number.isInteger,
|
|
103
|
+
message: "School passed-out year must be an integer.",
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
schoolPassedOutMonth: {
|
|
107
|
+
type: Number,
|
|
108
|
+
required: true,
|
|
109
|
+
min: 1,
|
|
110
|
+
max: 12,
|
|
111
|
+
validate: {
|
|
112
|
+
validator: Number.isInteger,
|
|
113
|
+
message: "School passed-out month must be an integer.",
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
schoolMedium: {
|
|
117
|
+
type: String,
|
|
118
|
+
default: null,
|
|
119
|
+
validate: {
|
|
120
|
+
validator: function (value) {
|
|
121
|
+
return value === null || value.trim().length > 0;
|
|
122
|
+
},
|
|
123
|
+
message: "School medium cannot be an empty string.",
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
markPercentage: {
|
|
127
|
+
type: Number,
|
|
128
|
+
default: null,
|
|
129
|
+
min: 0,
|
|
130
|
+
max: 100,
|
|
131
|
+
validate: {
|
|
132
|
+
validator: function (value) {
|
|
133
|
+
if (value !== null && (value < 0 || value > 100)) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
return true;
|
|
137
|
+
},
|
|
138
|
+
message: "Mark percentage must be between 0 and 100.",
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Define the schema
|
|
144
|
+
const schema = new mongoose.Schema(
|
|
145
|
+
{
|
|
146
|
+
profilePercentage: { type: Number, default: 0 },
|
|
147
|
+
skillIds: { type: [ObjectId], ref: "skill", default: [] },
|
|
148
|
+
roleIds: { type: [ObjectId], ref: "role", default: [] },
|
|
149
|
+
resume: {
|
|
150
|
+
type: {
|
|
151
|
+
resumeName: { type: String, default: null },
|
|
152
|
+
resumeLink: { type: String, default: null },
|
|
153
|
+
createdAt: { type: Date, default: Date.now },
|
|
154
|
+
},
|
|
155
|
+
default: null,
|
|
156
|
+
},
|
|
157
|
+
linkedIn: { type: String, default: null },
|
|
158
|
+
workStatus: {
|
|
159
|
+
type: String,
|
|
160
|
+
enum: WORK_STATUS,
|
|
161
|
+
default: null,
|
|
162
|
+
validate: {
|
|
163
|
+
validator: function (value) {
|
|
164
|
+
return WORK_STATUS.includes(value);
|
|
165
|
+
},
|
|
166
|
+
message: "Invalid work status",
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
experience: {
|
|
170
|
+
type: {
|
|
171
|
+
years: {
|
|
172
|
+
type: Number,
|
|
173
|
+
default: null,
|
|
174
|
+
validate: {
|
|
175
|
+
validator: function (value) {
|
|
176
|
+
return (
|
|
177
|
+
this.workStatus === "fresher" || (value !== null && value >= 0)
|
|
178
|
+
);
|
|
179
|
+
},
|
|
180
|
+
message: "Years of experience must be at least 0 for non-freshers.",
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
months: {
|
|
184
|
+
type: Number,
|
|
185
|
+
default: null,
|
|
186
|
+
validate: {
|
|
187
|
+
validator: function (value) {
|
|
188
|
+
return (
|
|
189
|
+
this.workStatus === "fresher" || (value !== null && value >= 0)
|
|
190
|
+
);
|
|
191
|
+
},
|
|
192
|
+
message:
|
|
193
|
+
"Months of experience must be at least 0 for non-freshers.",
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
default: null,
|
|
198
|
+
validate: {
|
|
199
|
+
validator: function (value) {
|
|
200
|
+
if (this.workStatus === "fresher") {
|
|
201
|
+
return (
|
|
202
|
+
value === null || (value.years === null && value.months === null)
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
return true;
|
|
206
|
+
},
|
|
207
|
+
message: "Experience should be null for freshers.",
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
currentSalary: {
|
|
211
|
+
type: Number,
|
|
212
|
+
default: null,
|
|
213
|
+
validate: {
|
|
214
|
+
validator: function (value) {
|
|
215
|
+
return this.workStatus !== "fresher" || value === null;
|
|
216
|
+
},
|
|
217
|
+
message: "currentSalary is required for non-freshers",
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
salaryExpectation: {
|
|
221
|
+
type: Number,
|
|
222
|
+
default: null,
|
|
223
|
+
validate: {
|
|
224
|
+
validator: function (value) {
|
|
225
|
+
return value === null || value > 0;
|
|
226
|
+
},
|
|
227
|
+
message: "Salary expectation must be a positive number.",
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
noticePeriod: { type: String, default: null },
|
|
231
|
+
profileSummary: { type: String, default: null },
|
|
232
|
+
avatar: { type: String, default: null },
|
|
233
|
+
fullName: { type: String, default: null },
|
|
234
|
+
mobileNumber: { type: Number, default: null },
|
|
235
|
+
email: { type: String, default: null, required: true },
|
|
236
|
+
countryCode: { type: String, default: "+91" },
|
|
237
|
+
maritalStatus: {
|
|
238
|
+
type: String,
|
|
239
|
+
enum: MARITAL_STATUS,
|
|
240
|
+
default: null,
|
|
241
|
+
validate: {
|
|
242
|
+
validator: function (value) {
|
|
243
|
+
return MARITAL_STATUS.includes(value);
|
|
244
|
+
},
|
|
245
|
+
message: "Invalid marital status",
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
gender: {
|
|
249
|
+
type: String,
|
|
250
|
+
enum: GENDER,
|
|
251
|
+
default: null,
|
|
252
|
+
validate: {
|
|
253
|
+
validator: function (value) {
|
|
254
|
+
return GENDER.includes(value);
|
|
255
|
+
},
|
|
256
|
+
message: "Invalid gender",
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
dob: { type: Date, default: null },
|
|
260
|
+
address: {
|
|
261
|
+
type: {
|
|
262
|
+
city: { type: String, default: null },
|
|
263
|
+
area: { type: String, default: null },
|
|
264
|
+
street: { type: String, default: null },
|
|
265
|
+
pincode: { type: Number, default: null },
|
|
266
|
+
},
|
|
267
|
+
default: null,
|
|
268
|
+
},
|
|
269
|
+
speakingLanguageIds: {
|
|
270
|
+
type: [ObjectId],
|
|
271
|
+
ref: "speaking-language",
|
|
272
|
+
default: [],
|
|
273
|
+
},
|
|
274
|
+
educations: {
|
|
275
|
+
type: [educationSchema],
|
|
276
|
+
default: [],
|
|
277
|
+
},
|
|
278
|
+
// Fields for 10th and 12th qualifications
|
|
279
|
+
schools: {
|
|
280
|
+
type: [schoolSchema],
|
|
281
|
+
default: [],
|
|
282
|
+
validate: {
|
|
283
|
+
validator: function (schools) {
|
|
284
|
+
// Count how many entries are there for 10th and 12th grades
|
|
285
|
+
const count10th = schools.filter(
|
|
286
|
+
(school) => school.qualification === "10th"
|
|
287
|
+
).length;
|
|
288
|
+
const count12th = schools.filter(
|
|
289
|
+
(school) => school.qualification === "12th"
|
|
290
|
+
).length;
|
|
291
|
+
|
|
292
|
+
// Ensure there's exactly one entry for 10th and one entry for 12th
|
|
293
|
+
return count10th <= 1 && count12th <= 1;
|
|
294
|
+
},
|
|
295
|
+
message:
|
|
296
|
+
"Candidate must have exactly one school entry for 10th grade and one entry for 12th grade.",
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
projects: {
|
|
300
|
+
type: [
|
|
301
|
+
{
|
|
302
|
+
_id: { type: ObjectId, auto: true },
|
|
303
|
+
projectName: { type: String, default: null },
|
|
304
|
+
projectStatus: {
|
|
305
|
+
type: String,
|
|
306
|
+
enum: PROJECT_STATUS,
|
|
307
|
+
default: null,
|
|
308
|
+
validate: {
|
|
309
|
+
validator: function (value) {
|
|
310
|
+
return PROJECT_STATUS.includes(value);
|
|
311
|
+
},
|
|
312
|
+
message: "Invalid project status",
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
projectURL: { type: String, default: null },
|
|
316
|
+
projectDescription: { type: String, default: null },
|
|
317
|
+
projectStartYear: { type: Number, default: null },
|
|
318
|
+
projectStartMonth: { type: Number, default: null },
|
|
319
|
+
projectEndYear: {
|
|
320
|
+
type: Number,
|
|
321
|
+
default: null,
|
|
322
|
+
validate: {
|
|
323
|
+
validator: function (value) {
|
|
324
|
+
// Allow non-null value only if the project status is 'completed'
|
|
325
|
+
if (this.projectStatus === "completed" && value === null) {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
// Ensure projectEndYear is null if projectStatus is not 'completed'
|
|
329
|
+
if (this.projectStatus !== "completed" && value !== null) {
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
return true;
|
|
333
|
+
},
|
|
334
|
+
message:
|
|
335
|
+
"projectEndYear must be provided only for completed projects.",
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
projectEndMonth: {
|
|
339
|
+
type: Number,
|
|
340
|
+
default: null,
|
|
341
|
+
validate: {
|
|
342
|
+
validator: function (value) {
|
|
343
|
+
if (this.projectStatus === "completed" && value === null) {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
if (this.projectStatus !== "completed" && value !== null) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
return true;
|
|
350
|
+
},
|
|
351
|
+
message:
|
|
352
|
+
"projectEndMonth must be provided only for completed projects.",
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
],
|
|
357
|
+
default: [],
|
|
358
|
+
},
|
|
359
|
+
isActive: { type: Boolean, default: true },
|
|
360
|
+
isVerified: { type: Boolean, default: true },
|
|
361
|
+
password: { type: String, default: null },
|
|
362
|
+
isResetPassword: { type: Boolean, default: false },
|
|
363
|
+
},
|
|
364
|
+
{ timestamps: { createdAt: true, updatedAt: true } }
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
const myDB = mongoose.connection.useDb(getDatabaseName());
|
|
368
|
+
|
|
369
|
+
schema.index({ isActive: 1 });
|
|
370
|
+
schema.index({ profilePercentage: 1 });
|
|
371
|
+
|
|
372
|
+
// Create the model
|
|
373
|
+
const CandidateModel = myDB.model("candidate", schema);
|
|
374
|
+
|
|
375
|
+
module.exports = CandidateModel;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
CandidateModel: require("./candidateModel"),
|
|
3
|
+
CandidateMobileOTPModel: require("./mobileOTPModel"),
|
|
4
|
+
CandidateOTPModel: require("./otpModel"),
|
|
5
|
+
CandidateRequestModel: require("./requestModel"),
|
|
6
|
+
CandidateSavedJobModel: require("./savedJobModel"),
|
|
7
|
+
SearchAppearanceModel: require("./searchAppearanceModel"),
|
|
8
|
+
};
|