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.
Files changed (82) hide show
  1. package/configs/firebase-admin.js +24 -0
  2. package/configs/index.js +3 -0
  3. package/constants/configuration.js +6 -0
  4. package/constants/database.js +6 -0
  5. package/constants/index.js +6 -0
  6. package/constants/org.js +30 -0
  7. package/constants/time-constant.js +4 -0
  8. package/helpers/index.js +4 -0
  9. package/helpers/otp-helper.js +48 -0
  10. package/helpers/validateMongoId.js +13 -0
  11. package/index.js +15 -0
  12. package/models/admin-models/admin-model.js +62 -0
  13. package/models/admin-models/index.js +4 -0
  14. package/models/admin-models/token-model.js +20 -0
  15. package/models/candidate-models/candidateModel.js +375 -0
  16. package/models/candidate-models/index.js +8 -0
  17. package/models/candidate-models/mobileOTPModel.js +75 -0
  18. package/models/candidate-models/otpModel.js +75 -0
  19. package/models/candidate-models/requestModel.js +26 -0
  20. package/models/candidate-models/savedJobModel.js +20 -0
  21. package/models/candidate-models/searchAppearanceModel.js +50 -0
  22. package/models/candidate-models/tokenModel.js +20 -0
  23. package/models/common-models/course-model.js +20 -0
  24. package/models/common-models/downloadedResumeHistory-model.js +54 -0
  25. package/models/common-models/education-model.js +17 -0
  26. package/models/common-models/index.js +19 -0
  27. package/models/common-models/jobApplication-model.js +57 -0
  28. package/models/common-models/jobApproach-model.js +14 -0
  29. package/models/common-models/jobOffer-model.js +20 -0
  30. package/models/common-models/jobType-model.js +22 -0
  31. package/models/common-models/noticePeriod.js +14 -0
  32. package/models/common-models/paymentHistory-model.js +128 -0
  33. package/models/common-models/plan-model.js +144 -0
  34. package/models/common-models/role-model.js +22 -0
  35. package/models/common-models/searchAppearanceHistory-model.js +36 -0
  36. package/models/common-models/skill-model.js +21 -0
  37. package/models/common-models/sms-student-model.js +44 -0
  38. package/models/common-models/speakingLanguage.js +14 -0
  39. package/models/common-models/specialization-model.js +20 -0
  40. package/models/common-models/viewedProfileHistory-model.js +44 -0
  41. package/models/index.js +8 -0
  42. package/models/jobPost-models/active-model.js +71 -0
  43. package/models/jobPost-models/draft-model.js +42 -0
  44. package/models/jobPost-models/expired-model.js +46 -0
  45. package/models/jobPost-models/index.js +10 -0
  46. package/models/jobPost-models/invitation-model.js +72 -0
  47. package/models/jobPost-models/onHold-model.js +58 -0
  48. package/models/jobPost-models/pending-model.js +45 -0
  49. package/models/jobPost-models/rejected-model.js +51 -0
  50. package/models/jobPost-models/verification-model.js +50 -0
  51. package/models/organization-models/active-model.js +111 -0
  52. package/models/organization-models/index.js +4 -0
  53. package/models/organization-models/verification-model.js +52 -0
  54. package/models/recruiter-models/active-model.js +45 -0
  55. package/models/recruiter-models/basicDetail-model.js +113 -0
  56. package/models/recruiter-models/counter-model.js +13 -0
  57. package/models/recruiter-models/emailOTP-model.js +68 -0
  58. package/models/recruiter-models/index.js +10 -0
  59. package/models/recruiter-models/mobileOTP-model.js +88 -0
  60. package/models/recruiter-models/pending-model.js +44 -0
  61. package/models/recruiter-models/request-model.js +75 -0
  62. package/models/recruiter-models/token-model.js +15 -0
  63. package/models/recruiter-models/verification-model.js +63 -0
  64. package/package.json +28 -0
  65. package/schemes/address-schema.js +43 -0
  66. package/schemes/index.js +7 -0
  67. package/schemes/pendingJobPostStep1-schema.js +192 -0
  68. package/schemes/pendingJobPostStep2-scheme.js +117 -0
  69. package/schemes/pendingJobPostStep3-scheme.js +21 -0
  70. package/schemes/pendingJobPostStep4-scheme.js +22 -0
  71. package/utils/env-utils.js +12 -0
  72. package/utils/firebase-utils.js +220 -0
  73. package/utils/index.js +12 -0
  74. package/utils/invoiceTemplate.js +123 -0
  75. package/utils/otp-utils.js +23 -0
  76. package/utils/password-utils.js +49 -0
  77. package/utils/percentageWeights.js +106 -0
  78. package/utils/populate-utils.js +57 -0
  79. package/utils/sendEmail-utils.js +40 -0
  80. package/utils/sendInvoice-utils.js +139 -0
  81. package/utils/token-utils.js +18 -0
  82. package/utils/validate-utils.js +118 -0
@@ -0,0 +1,45 @@
1
+ const mongoose = require("mongoose");
2
+ const {
3
+ pendingJobPostStep1Schema,
4
+ pendingJobPostStep2Schema,
5
+ pendingJobPostStep3Schema,
6
+ pendingJobPostStep4Schema,
7
+ } = require("../../schemes");
8
+ const { getDatabaseName } = require("../../constants");
9
+ const { ObjectId } = mongoose.Schema.Types;
10
+
11
+ const schema = new mongoose.Schema(
12
+ {
13
+ recruiterId: {
14
+ type: ObjectId,
15
+ required: [true, "Recruiter ID is required"],
16
+ validate: {
17
+ validator: mongoose.Types.ObjectId.isValid,
18
+ message: "Invalid recruiter ID",
19
+ },
20
+ },
21
+ step1: {
22
+ type: pendingJobPostStep1Schema,
23
+ required: [true, "Step 1 data is required"],
24
+ },
25
+ step2: {
26
+ type: pendingJobPostStep2Schema,
27
+ required: [true, "Step 2 data is required"],
28
+ },
29
+ step3: {
30
+ type: pendingJobPostStep3Schema,
31
+ required: [true, "Step 3 data is required"],
32
+ },
33
+ step4: pendingJobPostStep4Schema, // This will not be required
34
+ },
35
+ {
36
+ timestamps: { createdAt: true, updatedAt: true },
37
+ }
38
+ );
39
+
40
+ // Create the model
41
+ const myDB = mongoose.connection.useDb(getDatabaseName());
42
+
43
+ const PendingJobPostModel = myDB.model("pending-jobPost", schema);
44
+
45
+ module.exports = PendingJobPostModel;
@@ -0,0 +1,51 @@
1
+ const mongoose = require("mongoose");
2
+ const {
3
+ pendingJobPostStep1Schema,
4
+ pendingJobPostStep2Schema,
5
+ pendingJobPostStep3Schema,
6
+ pendingJobPostStep4Schema,
7
+ } = require("../../schemes");
8
+ const { validateReason } = require("../../utils");
9
+ const { getDatabaseName } = require("../../constants");
10
+ const { ObjectId } = mongoose.Schema.Types;
11
+
12
+ const schema = new mongoose.Schema(
13
+ {
14
+ recruiterId: {
15
+ type: ObjectId,
16
+ required: [true, "Recruiter ID is required"],
17
+ validate: {
18
+ validator: mongoose.Types.ObjectId.isValid,
19
+ message: "Invalid recruiter ID",
20
+ },
21
+ },
22
+ step1: {
23
+ type: pendingJobPostStep1Schema,
24
+ required: [true, "Step 1 data is required"],
25
+ },
26
+ step2: {
27
+ type: pendingJobPostStep2Schema,
28
+ required: [true, "Step 2 data is required"],
29
+ },
30
+ step3: {
31
+ type: pendingJobPostStep3Schema,
32
+ required: [true, "Step 3 data is required"],
33
+ },
34
+ step4: pendingJobPostStep4Schema, // This will not be required
35
+ reason: {
36
+ type: String,
37
+ required: [true, "Reason is required"],
38
+ validate: [validateReason, "Reason must be at least 5 characters long"],
39
+ },
40
+ },
41
+ {
42
+ timestamps: { createdAt: true, updatedAt: true },
43
+ }
44
+ );
45
+
46
+ // Create the model
47
+ const myDB = mongoose.connection.useDb(getDatabaseName());
48
+
49
+ const RejectedJobPostModel = myDB.model("rejected-jobPost", schema);
50
+
51
+ module.exports = RejectedJobPostModel;
@@ -0,0 +1,50 @@
1
+ const mongoose = require("mongoose");
2
+ const {
3
+ pendingJobPostStep1Schema,
4
+ pendingJobPostStep2Schema,
5
+ pendingJobPostStep3Schema,
6
+ pendingJobPostStep4Schema,
7
+ } = require("../../schemes");
8
+ const { getDatabaseName } = require("../../constants");
9
+ const { ObjectId } = mongoose.Schema.Types;
10
+
11
+ const schema = new mongoose.Schema(
12
+ {
13
+ recruiterId: {
14
+ type: ObjectId,
15
+ required: [true, "Recruiter ID is required"],
16
+ validate: {
17
+ validator: mongoose.Types.ObjectId.isValid,
18
+ message: "Invalid recruiter ID",
19
+ },
20
+ },
21
+ step1: {
22
+ type: pendingJobPostStep1Schema,
23
+ required: [true, "Step 1 data is required"],
24
+ },
25
+ step2: {
26
+ type: pendingJobPostStep2Schema,
27
+ required: [true, "Step 2 data is required"],
28
+ },
29
+ step3: {
30
+ type: pendingJobPostStep3Schema,
31
+ required: [true, "Step 3 data is required"],
32
+ },
33
+ step4: {
34
+ type: pendingJobPostStep4Schema,
35
+ required: [true, "Step 4 data is required"],
36
+ },
37
+ },
38
+ {
39
+ timestamps: { createdAt: true, updatedAt: true },
40
+ }
41
+ );
42
+
43
+ schema.index({ recruiterId: 1 });
44
+
45
+ // Create the model
46
+ const myDB = mongoose.connection.useDb(getDatabaseName());
47
+
48
+ const VerificationJobPostModel = myDB.model("verification-jobPost", schema);
49
+
50
+ module.exports = VerificationJobPostModel;
@@ -0,0 +1,111 @@
1
+ const mongoose = require("mongoose");
2
+ const { addressSchema } = require("../../schemes");
3
+ const { getDatabaseName } = require("../../constants");
4
+
5
+ const { ObjectId } = mongoose.Schema.Types;
6
+
7
+ // Define the schema
8
+ const schema = new mongoose.Schema(
9
+ {
10
+ recruiterId: {
11
+ type: ObjectId,
12
+ required: [true, "Recruiter ID is required"],
13
+ ref: "RecruiterModel",
14
+ },
15
+ organizationLogo: {
16
+ type: String,
17
+ required: [true, "Organization logo is required"],
18
+ // match: [
19
+ // /^(https?:\/\/.*\.(?:png|jpg|jpeg|svg))$/i,
20
+ // "Organization logo must be a valid URL and of type png, jpg, jpeg, or svg",
21
+ // ],
22
+ },
23
+ organizationName: {
24
+ type: String,
25
+ required: [true, "Organization name is required"],
26
+ trim: true,
27
+ minlength: [2, "Organization name must be at least 2 characters long"],
28
+ maxlength: [100, "Organization name cannot exceed 100 characters"],
29
+ },
30
+ normalizedOrganizationName: {
31
+ type: String,
32
+ trim: true,
33
+ minlength: [
34
+ 2,
35
+ "Normalized organization name must be at least 2 characters long",
36
+ ],
37
+ maxlength: [
38
+ 100,
39
+ "Normalized organization name cannot exceed 100 characters",
40
+ ],
41
+ lowercase: true, // Ensuring normalization for consistent database querying
42
+ },
43
+ about: {
44
+ type: String,
45
+ required: [true, "About section is required"],
46
+ trim: true,
47
+ minlength: [10, "About section must be at least 10 characters long"],
48
+ maxlength: [1000, "About section cannot exceed 1000 characters"],
49
+ },
50
+ websiteLink: {
51
+ type: String,
52
+ required: [true, "Website link is required"],
53
+ // match: [
54
+ // /^(https?:\/\/)?(www\.)?([a-zA-Z0-9]+)(\.[a-z]{2,})+(\/[^\s]*)?$/,
55
+ // "Website link must be a valid URL",
56
+ // ],
57
+ trim: true,
58
+ },
59
+ gallery: {
60
+ type: [String],
61
+ validate: {
62
+ validator: function (v) {
63
+ return Array.isArray(v) && v.length >= 3 && v.length <= 6;
64
+ },
65
+ message:
66
+ "Gallery should have at least 3 images and a maximum of 6 images.",
67
+ },
68
+ },
69
+ teamSize: {
70
+ type: String,
71
+ required: [true, "Team size is required"],
72
+ // enum: {
73
+ // values: ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"],
74
+ // message: "Team size must be one of the predefined values",
75
+ // },
76
+ },
77
+ foundedYear: {
78
+ type: Number,
79
+ required: [true, "Founded year is required"],
80
+ min: [1800, "Founded year cannot be before 1800"],
81
+ max: [new Date().getFullYear(), "Founded year cannot be in the future"],
82
+ },
83
+ address: {
84
+ type: addressSchema,
85
+ required: [true, "Address is required"],
86
+ },
87
+ gstNumber: {
88
+ type: String,
89
+ required: [true, "GST number is required"],
90
+ match: [
91
+ /^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[Z]{1}[A-Z0-9]{1}$/,
92
+ "Invalid GST number format",
93
+ ],
94
+ unique: true, // Ensures that the GST number is unique in the collection
95
+ },
96
+ },
97
+ {
98
+ timestamps: { createdAt: true, updatedAt: true },
99
+ }
100
+ );
101
+
102
+ // Indexing for better performance
103
+ schema.index({ recruiterId: 1 });
104
+ schema.index({ normalizedOrganizationName: 1 });
105
+
106
+ const myDB = mongoose.connection.useDb(getDatabaseName());
107
+
108
+ // Create the model
109
+ const ActiveOrganizationModel = myDB.model("active-organization", schema);
110
+
111
+ module.exports = ActiveOrganizationModel;
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ ActiveOrganizationModel: require("./active-model"),
3
+ OrganizationVerificationModel: require("./verification-model"),
4
+ };
@@ -0,0 +1,52 @@
1
+ const mongoose = require("mongoose");
2
+ const { addressSchema } = require("../../schemes");
3
+ const { getDatabaseName } = require("../../constants");
4
+
5
+ const { ObjectId } = mongoose.Schema.Types;
6
+
7
+ // Define the schema
8
+ const schema = new mongoose.Schema(
9
+ {
10
+ recruiterId: { type: ObjectId, required: true },
11
+ organizationLogo: { type: String, required: true },
12
+ organizationName: { type: String, required: true }, // For display purposes
13
+ normalizedOrganizationName: { type: String }, // For database queries and comparisons
14
+ about: { type: String, required: true },
15
+ websiteLink: {
16
+ type: String,
17
+ required: true,
18
+ },
19
+ gallery: {
20
+ type: [String],
21
+ validate: {
22
+ validator: function (v) {
23
+ return Array.isArray(v) && v.length >= 3 && v.length <= 6;
24
+ },
25
+ message:
26
+ "Gallery should have at least 3 images and a maximum of 6 images.",
27
+ },
28
+ },
29
+ teamSize: { type: String, required: true },
30
+ foundedYear: { type: Number, required: true },
31
+ address: { type: addressSchema, required: true },
32
+ gstNumber: {
33
+ type: String,
34
+ required: [true, "GST number is required"],
35
+ match: [
36
+ /^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[Z]{1}[A-Z0-9]{1}$/,
37
+ "Invalid GST number format",
38
+ ],
39
+ },
40
+ },
41
+ { timestamps: { createdAt: true, updatedAt: true } }
42
+ );
43
+
44
+ const myDB = mongoose.connection.useDb(getDatabaseName());
45
+
46
+ // Create the model
47
+ const OrganizationVerificationModel = myDB.model(
48
+ "verification-organization",
49
+ schema
50
+ );
51
+
52
+ module.exports = OrganizationVerificationModel;
@@ -0,0 +1,45 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ const { ObjectId } = mongoose.Schema.Types;
5
+
6
+ // Define the schema
7
+ const schema = new mongoose.Schema(
8
+ {
9
+ avatar: { type: String, required: true },
10
+ fullName: { type: String, required: true, minlength: 2, maxlength: 50 },
11
+ designation: { type: String, required: true, minlength: 2, maxlength: 50 },
12
+ email: {
13
+ type: String,
14
+ required: true,
15
+ match: /^\S+@\S+\.\S+$/,
16
+ unique: true, // Unique index (no need for manual index)
17
+ lowercase: true, // Ensure case-insensitive uniqueness
18
+ trim: true, // Remove accidental spaces
19
+ },
20
+ countryCode: { type: String, required: true, enum: ["+91"] },
21
+ mobileNumber: {
22
+ type: String,
23
+ required: true,
24
+ minlength: 10,
25
+ maxlength: 10,
26
+ unique: true, // Unique index (no need for manual index)
27
+ },
28
+ password: { type: String, required: true },
29
+ organizationId: {
30
+ type: ObjectId,
31
+ required: true,
32
+ },
33
+ },
34
+ { timestamps: { createdAt: true, updatedAt: true } }
35
+ );
36
+
37
+ // Indexing for performance
38
+ schema.index({ organizationId: 1 });
39
+
40
+ const myDB = mongoose.connection.useDb(getDatabaseName());
41
+
42
+ // Create the model
43
+ const ActiveRecruiterModel = myDB.model("active-recruiter", schema);
44
+
45
+ module.exports = ActiveRecruiterModel;
@@ -0,0 +1,113 @@
1
+ const mongoose = require("mongoose");
2
+ const bcrypt = require("bcrypt");
3
+ const { isMobilePhone } = require("validator");
4
+ const { getDatabaseName } = require("../../constants");
5
+ const {
6
+ Schema,
7
+ Types: { ObjectId },
8
+ } = mongoose;
9
+
10
+ // Define the schema
11
+ const schema = new Schema(
12
+ {
13
+ recruiterId: {
14
+ type: ObjectId,
15
+ required: [true, "Recruiter ID is required"],
16
+ },
17
+ fullName: {
18
+ type: String,
19
+ required: [true, "Full name is required"],
20
+ trim: true,
21
+ minlength: [3, "Full name must be at least 3 characters long"],
22
+ maxlength: [50, "Full name must be at most 50 characters long"],
23
+ },
24
+ designation: {
25
+ type: String,
26
+ required: [true, "Designation is optional"], // Optional field
27
+ minlength: [2, "Designation must be at least 2 characters long"],
28
+ maxlength: [50, "Designation cannot exceed 50 characters"],
29
+ },
30
+ // mobileNumber: {
31
+ // type: String,
32
+ // required: [true, "Mobile number is required"],
33
+ // minlength: [10, "Mobile number must be exactly 10 digits long"],
34
+ // maxlength: [10, "Mobile number must be exactly 10 digits long"],
35
+ // match: [/^\d{10}$/, "Mobile number must be exactly 10 digits"],
36
+ // unique: true, // Ensure mobileNumber is unique
37
+ // },
38
+ // countryCode: {
39
+ // type: String,
40
+ // required: [true, "Country code is required"],
41
+ // minlength: [1, "Country code must be at least 1 character long"],
42
+ // maxlength: [4, "Country code cannot exceed 4 characters"],
43
+ // enum: ["+91"], // Only allow +91
44
+ // },
45
+ password: {
46
+ type: String,
47
+ required: [true, "Password is required"],
48
+ },
49
+ email: {
50
+ type: String,
51
+ required: [true, "Email is required"],
52
+ unique: true,
53
+ match: [
54
+ /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
55
+ "Please enter a valid email address",
56
+ ],
57
+ maxlength: 100,
58
+ },
59
+ OTP: {
60
+ type: String,
61
+ required: [true, "OTP is required"],
62
+ },
63
+ requests: [
64
+ {
65
+ date: {
66
+ type: Date,
67
+ required: [true, "Request date is required"],
68
+ default: Date.now,
69
+ },
70
+ attempts: {
71
+ type: Number,
72
+ default: 0,
73
+ min: [0, "Attempts cannot be negative"],
74
+ },
75
+ successful: {
76
+ type: Boolean,
77
+ default: false,
78
+ },
79
+ },
80
+ ],
81
+ expiryDate: {
82
+ type: Date,
83
+ required: [true, "Expiry date is required"],
84
+ validate: {
85
+ validator: function (v) {
86
+ return v > Date.now();
87
+ },
88
+ message: "Expiry date must be in the future.",
89
+ },
90
+ },
91
+ deleteAt: {
92
+ type: Date,
93
+ required: [true, "Deletion time is required"],
94
+ validate: {
95
+ validator: function (v) {
96
+ return v > Date.now();
97
+ },
98
+ message: "Deletion time must be in the future.",
99
+ },
100
+ },
101
+ },
102
+ { timestamps: { createdAt: true, updatedAt: true } }
103
+ );
104
+
105
+ // Define indexes for TTL and other fields
106
+ schema.index({ deleteAt: 1 }, { expireAfterSeconds: 0 });
107
+ schema.index({ recruiterId: 1 });
108
+
109
+ // Create the model
110
+ const myDB = mongoose.connection.useDb(getDatabaseName());
111
+ const RecruiterBasicDetailModel = myDB.model("recruiter-basic-detail", schema);
112
+
113
+ module.exports = { RecruiterBasicDetailModel };
@@ -0,0 +1,13 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ const counterSchema = new mongoose.Schema({
5
+ _id: { type: String, required: true },
6
+ sequenceValue: { type: Number, default: 0 },
7
+ });
8
+
9
+ // Create the model
10
+ const myDB = mongoose.connection.useDb(getDatabaseName());
11
+ const CounterModel = myDB.model("counter", counterSchema);
12
+
13
+ module.exports = { CounterModel };
@@ -0,0 +1,68 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+ const {
4
+ Schema,
5
+ Types: { ObjectId },
6
+ } = mongoose;
7
+
8
+ // Define the schema
9
+ const schema = new Schema(
10
+ {
11
+ recruiterId: {
12
+ type: ObjectId,
13
+ required: [true, "Recruiter ID is required"],
14
+ },
15
+ email: { type: String, required: true },
16
+ OTP: {
17
+ type: String, // Encrypted OTP
18
+ required: [true, "OTP is required"],
19
+ maxlength: [6, "OTP must be 6 digits"], // Adjust based on encryption
20
+ },
21
+ attempts: [
22
+ {
23
+ date: {
24
+ type: Date,
25
+ required: [true, "Attempt date is required"],
26
+ },
27
+ successful: {
28
+ type: Boolean,
29
+ default: false,
30
+ },
31
+ },
32
+ ],
33
+ expiry: {
34
+ type: Date,
35
+ required: [true, "Expiry date is required"],
36
+ validate: {
37
+ validator: function (v) {
38
+ return v > new Date(); // Ensure expiry is in the future
39
+ },
40
+ message: "Expiry must be a future date.",
41
+ },
42
+ },
43
+
44
+ deleteAt: {
45
+ type: Date,
46
+ required: [true, "DeleteAt date is required"],
47
+ validate: {
48
+ validator: function (v) {
49
+ return v > new Date(); // Ensure deleteAt is in the future
50
+ },
51
+ message: "DeleteAt must be a future date.",
52
+ },
53
+ },
54
+ },
55
+ { timestamps: { createdAt: true, updatedAt: true } }
56
+ );
57
+
58
+ // Create the model
59
+ const myDB = mongoose.connection.useDb(getDatabaseName());
60
+ const RecruiterEmailOTPModel = myDB.model("recruiter-email-otp", schema);
61
+
62
+ // Ensure deleteAt index is created (for document expiry)
63
+ schema.index({ deleteAt: 1 }, { expireAfterSeconds: 0 });
64
+
65
+ // Consider adding indexes for frequently queried fields
66
+ schema.index({ recruiterId: 1 });
67
+
68
+ module.exports = { RecruiterEmailOTPModel };
@@ -0,0 +1,10 @@
1
+ module.exports = {
2
+ ActiveRecruiterModel: require("./active-model"),
3
+ PendingRecruiterModel: require("./pending-model"),
4
+ RecruiterBasicDetailModel: require("./basicDetail-model"),
5
+ RecruiterTokenModel: require("./token-model"),
6
+ CounterModel: require("./counter-model"),
7
+ RequestRecruiterModel: require("./request-model"),
8
+ VerificationRecruiterModel: require("./verification-model"),
9
+ RecruiterMobileOTPModel: require("./mobileOTP-model"),
10
+ };
@@ -0,0 +1,88 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+ const {
4
+ Schema,
5
+ Types: { ObjectId },
6
+ } = mongoose;
7
+
8
+ // Define the schema
9
+ const schema = new Schema(
10
+ {
11
+ recruiterId: {
12
+ type: ObjectId,
13
+ required: [true, "Recruiter ID is required"],
14
+ },
15
+ mobileNumber: {
16
+ type: String,
17
+ required: [true, "Mobile number is required"],
18
+ validate: {
19
+ validator: function (v) {
20
+ return /^\d{10}$/.test(v); // Example validation for a 10-digit number
21
+ },
22
+ message: "Invalid mobile number format.",
23
+ },
24
+ },
25
+ countryCode: {
26
+ type: String,
27
+ required: [true, "Country code is required"],
28
+ validate: {
29
+ validator: function (v) {
30
+ return /^\+\d{1,4}$/.test(v); // Example validation for country code (e.g., +1, +44)
31
+ },
32
+ message: "Invalid country code format.",
33
+ },
34
+ },
35
+ OTP: {
36
+ type: String, // Encrypted OTP
37
+ required: [true, "OTP is required"],
38
+ maxlength: [6, "OTP must be 6 digits"], // Adjust based on encryption
39
+ },
40
+ attempts: [
41
+ {
42
+ date: {
43
+ type: Date,
44
+ required: [true, "Attempt date is required"],
45
+ },
46
+ successful: {
47
+ type: Boolean,
48
+ default: false,
49
+ },
50
+ },
51
+ ],
52
+ expiry: {
53
+ type: Date,
54
+ required: [true, "Expiry date is required"],
55
+ validate: {
56
+ validator: function (v) {
57
+ return v > new Date(); // Ensure expiry is in the future
58
+ },
59
+ message: "Expiry must be a future date.",
60
+ },
61
+ },
62
+ deleteAt: {
63
+ type: Date,
64
+ required: [true, "DeleteAt date is required"],
65
+ validate: {
66
+ validator: function (v) {
67
+ return v > new Date(); // Ensure deleteAt is in the future
68
+ },
69
+ message: "DeleteAt must be a future date.",
70
+ },
71
+ },
72
+ },
73
+ { timestamps: { createdAt: true, updatedAt: true } }
74
+ );
75
+
76
+ // Create the model
77
+ const myDB = mongoose.connection.useDb(getDatabaseName());
78
+ const RecruiterMobileOTPModel = myDB.model("recruiter-mobile-otp", schema);
79
+
80
+ // Ensure deleteAt index is created (for document expiry)
81
+ schema.index({ deleteAt: 1 }, { expireAfterSeconds: 0 });
82
+
83
+ // Consider adding indexes for frequently queried fields
84
+ schema.index({ recruiterId: 1 });
85
+ schema.index({ mobileNumber: 1 });
86
+ schema.index({ countryCode: 1 });
87
+
88
+ module.exports = RecruiterMobileOTPModel;