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,139 @@
|
|
|
1
|
+
const nodemailer = require("nodemailer");
|
|
2
|
+
const puppeteer = require("puppeteer-core");
|
|
3
|
+
const chromium = require("chrome-aws-lambda");
|
|
4
|
+
// const localPuppeteer = require("puppeteer");
|
|
5
|
+
|
|
6
|
+
const { invoiceEmailTemplate } = require("./invoiceTemplate");
|
|
7
|
+
|
|
8
|
+
const { ToWords } = require("to-words");
|
|
9
|
+
const { OUR_ORG_INFO } = require("../constants");
|
|
10
|
+
const toWords = new ToWords();
|
|
11
|
+
|
|
12
|
+
// const generatePDF = async (htmlContent) => {
|
|
13
|
+
// // const browser = await puppeteer.launch();
|
|
14
|
+
// // const browser = await puppeteer.launch({
|
|
15
|
+
// // // executablePath: puppeteer.executablePath(),
|
|
16
|
+
// // headless: true, // Ensure the browser runs headlessly in the cloud
|
|
17
|
+
// // // args: ["--no-sandbox", "--disable-setuid-sandbox"], // Required in some environments like Firebase
|
|
18
|
+
// // });
|
|
19
|
+
// const browser = await puppeteer.launch({
|
|
20
|
+
// executablePath: await chromium.executablePath, // Use the correct Chromium executable for Firebase
|
|
21
|
+
// args: chromium.args, // Set required arguments for headless Chrome
|
|
22
|
+
// headless: chromium.headless, // Ensure Chrome runs in headless mode
|
|
23
|
+
// });
|
|
24
|
+
// const page = await browser.newPage();
|
|
25
|
+
// await page.setContent(htmlContent);
|
|
26
|
+
// const pdfBuffer = await page.pdf({ format: "A4" });
|
|
27
|
+
// await browser.close();
|
|
28
|
+
// return pdfBuffer;
|
|
29
|
+
// };
|
|
30
|
+
const generatePDF = async (htmlContent) => {
|
|
31
|
+
try {
|
|
32
|
+
// from below is for local development
|
|
33
|
+
// const browser = await localPuppeteer.launch();
|
|
34
|
+
|
|
35
|
+
// Launch browser with necessary configuration for Firebase or serverless environments
|
|
36
|
+
const browser = await puppeteer.launch({
|
|
37
|
+
executablePath: await chromium.executablePath, // Path to Chromium for Firebase/Serverless
|
|
38
|
+
args: chromium.args, // Required arguments for running headless
|
|
39
|
+
headless: chromium.headless, // Ensure headless mode is enabled
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Create a new page in the browser
|
|
43
|
+
const page = await browser.newPage();
|
|
44
|
+
|
|
45
|
+
// Set the HTML content dynamically passed to this function
|
|
46
|
+
await page.setContent(htmlContent);
|
|
47
|
+
|
|
48
|
+
// Generate the PDF from the page's content
|
|
49
|
+
const pdfBuffer = await page.pdf({
|
|
50
|
+
format: "A4", // Set paper format to A4 (you can customize this if needed)
|
|
51
|
+
printBackground: true, // Include background images or colors in the PDF
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Close the browser once done
|
|
55
|
+
await browser.close();
|
|
56
|
+
|
|
57
|
+
// Return the PDF as a buffer
|
|
58
|
+
return pdfBuffer;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("Error generating PDF:", error);
|
|
61
|
+
throw error; // Re-throw the error for further handling
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const sendInvoice = async (recruiterWithPlan, paymentHistory) => {
|
|
65
|
+
if (!recruiterWithPlan || !paymentHistory) {
|
|
66
|
+
throw new Error("No data provided to send the invoice.");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const { recruiterEmail, gstAmount, totalAmount, amount, gstPercentage } =
|
|
70
|
+
recruiterWithPlan;
|
|
71
|
+
|
|
72
|
+
const { billNumber, jobId, planName } = paymentHistory;
|
|
73
|
+
|
|
74
|
+
// Check if the required environment variables are set
|
|
75
|
+
if (!process.env.EMAIL || !process.env.EMAIL_PASSWORD) {
|
|
76
|
+
const errorMsg = "Email credentials are not set in environment variables.";
|
|
77
|
+
console.error(errorMsg);
|
|
78
|
+
throw new Error(errorMsg); // Throw error to propagate it back to the caller
|
|
79
|
+
}
|
|
80
|
+
// console.log(totalAmount);
|
|
81
|
+
// Email content
|
|
82
|
+
const htmlBody = `
|
|
83
|
+
<p>Dear Customer,</p>
|
|
84
|
+
<p>Please find attached your invoice. If you have any questions, feel free to reach out to us.</p>
|
|
85
|
+
<p>Best regards,<br>Ocean academy</p>
|
|
86
|
+
`;
|
|
87
|
+
const invoiceData = {
|
|
88
|
+
date: new Date().toLocaleDateString(),
|
|
89
|
+
billNo: billNumber,
|
|
90
|
+
jobId,
|
|
91
|
+
items: [{ description: `${planName}`, amount: `${amount}` }],
|
|
92
|
+
totalAmount,
|
|
93
|
+
totalAmountWords: toWords.convert(totalAmount, { currency: true }),
|
|
94
|
+
gstPercentage,
|
|
95
|
+
gstAmount,
|
|
96
|
+
...OUR_ORG_INFO,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Generate the invoice HTML content
|
|
100
|
+
const invoiceHTML = invoiceEmailTemplate(invoiceData);
|
|
101
|
+
const pdfBuffer = await generatePDF(invoiceHTML);
|
|
102
|
+
|
|
103
|
+
// Create a transporter using your email credentials
|
|
104
|
+
const transporter = nodemailer.createTransport({
|
|
105
|
+
service: "gmail",
|
|
106
|
+
auth: {
|
|
107
|
+
user: process.env.EMAIL,
|
|
108
|
+
pass: process.env.EMAIL_PASSWORD, // SMTP Password
|
|
109
|
+
},
|
|
110
|
+
// === add this === //
|
|
111
|
+
tls: { rejectUnauthorized: false },
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Email options
|
|
115
|
+
const mailOptions = {
|
|
116
|
+
from: process.env.EMAIL,
|
|
117
|
+
to: recruiterEmail,
|
|
118
|
+
subject: "Welcome to our OA Job Portal!",
|
|
119
|
+
html: htmlBody, // HTML content from the template
|
|
120
|
+
attachments: [
|
|
121
|
+
{
|
|
122
|
+
filename: "invoice.pdf",
|
|
123
|
+
content: pdfBuffer,
|
|
124
|
+
encoding: "base64",
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
};
|
|
128
|
+
// Send the email with the PDF attachment
|
|
129
|
+
try {
|
|
130
|
+
const info = await transporter.sendMail(mailOptions);
|
|
131
|
+
// console.log("Email sent successfully!", info);
|
|
132
|
+
return { status: 200, message: "Email sent successfully!", info };
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error("Error sending email:", error);
|
|
135
|
+
throw new Error("Error sending email", error);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
module.exports = { sendInvoice, generatePDF };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const jwt = require("jsonwebtoken");
|
|
2
|
+
|
|
3
|
+
const generateToken = (payload, options = {}) => {
|
|
4
|
+
try {
|
|
5
|
+
// Set default expiration if not provided
|
|
6
|
+
const tokenOptions = {
|
|
7
|
+
expiresIn: options.expiresIn || "1h", // default to 1 hour
|
|
8
|
+
...options,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
return jwt.sign(payload, process.env.SECRET_KEY, tokenOptions);
|
|
12
|
+
} catch (error) {
|
|
13
|
+
console.error("Error generating token:", error.message);
|
|
14
|
+
throw new Error("Token generation failed.");
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
module.exports = { generateToken };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const validator = require("validator");
|
|
2
|
+
const { check } = require("express-validator");
|
|
3
|
+
|
|
4
|
+
// Separate validation into a function for better organization
|
|
5
|
+
const validateEmail = (email) => validator.isEmail(email);
|
|
6
|
+
|
|
7
|
+
// Utility function to capitalize space-separated words
|
|
8
|
+
const capitalizeSpaceSeparatedWords = (str) => {
|
|
9
|
+
if (!str || typeof str !== "string") {
|
|
10
|
+
return ""; // Return an empty string for undefined or non-string values
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Trim leading and trailing spaces, and replace multiple spaces with a single space
|
|
14
|
+
const trimmedStr = str.trim().replace(/\s+/g, " ");
|
|
15
|
+
|
|
16
|
+
return trimmedStr
|
|
17
|
+
.split(" ")
|
|
18
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
19
|
+
.join(" ");
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Validate mobile number and OTP code
|
|
23
|
+
const validateMobileNumber = (mobileNumber) => {
|
|
24
|
+
return typeof mobileNumber === "string" && /^\d{10}$/.test(mobileNumber);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Define custom validators
|
|
28
|
+
const validateReason = (reason) => {
|
|
29
|
+
return reason.length > 5; // Example: reason must be at least 5 characters long
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Define custom validators
|
|
33
|
+
const isIntegerValidator = {
|
|
34
|
+
validator: Number.isInteger,
|
|
35
|
+
message: "{PATH} must be an integer",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const isValidDateValidator = {
|
|
39
|
+
validator: (value) => !isNaN(Date.parse(value)),
|
|
40
|
+
message: "{PATH} must be a valid date",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const validateFile = (file) => {
|
|
44
|
+
if (!file || typeof file !== "object") {
|
|
45
|
+
throw new Error("Invalid file parameter. The file must be an object.");
|
|
46
|
+
}
|
|
47
|
+
if (!file.buffer || !Buffer.isBuffer(file.buffer)) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
"Invalid file buffer. The file must contain a valid buffer."
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (!file.mimetype || typeof file.mimetype !== "string") {
|
|
53
|
+
throw new Error(
|
|
54
|
+
"Invalid file mimetype. The file must contain a valid mimetype."
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const validateFilePath = (filePath) => {
|
|
60
|
+
if (
|
|
61
|
+
!filePath ||
|
|
62
|
+
typeof filePath !== "string" ||
|
|
63
|
+
filePath.trim().length === 0
|
|
64
|
+
) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
"Invalid filePath parameter. The filePath must be a non-empty string."
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const normalizeOrganizationName = (name) => {
|
|
72
|
+
if (typeof name !== "string") {
|
|
73
|
+
throw new TypeError("Input must be a string.");
|
|
74
|
+
}
|
|
75
|
+
return name
|
|
76
|
+
.replace(/\s+/g, "") // Remove all spaces
|
|
77
|
+
.toLowerCase(); // Convert to lowercase
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const validatePagination = [
|
|
81
|
+
check("page")
|
|
82
|
+
.optional()
|
|
83
|
+
.isInt({ min: 1 })
|
|
84
|
+
.withMessage("Page must be a positive integer."),
|
|
85
|
+
check("limit")
|
|
86
|
+
.optional()
|
|
87
|
+
.isInt({ min: 1 })
|
|
88
|
+
.withMessage("Limit must be a positive integer."),
|
|
89
|
+
check("sortField")
|
|
90
|
+
.optional()
|
|
91
|
+
.isIn(["createdAt", "updatedAt"])
|
|
92
|
+
.withMessage(
|
|
93
|
+
"Invalid sort field. Valid fields are 'createdAt' and 'updatedAt'."
|
|
94
|
+
),
|
|
95
|
+
check("sort")
|
|
96
|
+
.optional()
|
|
97
|
+
.isInt({ min: -1, max: 1 })
|
|
98
|
+
.withMessage(
|
|
99
|
+
"Invalid sort order. Use 1 for ascending and -1 for descending."
|
|
100
|
+
),
|
|
101
|
+
check("search")
|
|
102
|
+
.optional()
|
|
103
|
+
.isString()
|
|
104
|
+
.withMessage("Search query must be a string."),
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
module.exports = {
|
|
108
|
+
capitalizeSpaceSeparatedWords,
|
|
109
|
+
validateEmail,
|
|
110
|
+
validateReason,
|
|
111
|
+
isIntegerValidator,
|
|
112
|
+
isValidDateValidator,
|
|
113
|
+
validateFile,
|
|
114
|
+
validateFilePath,
|
|
115
|
+
validateMobileNumber,
|
|
116
|
+
normalizeOrganizationName,
|
|
117
|
+
validatePagination,
|
|
118
|
+
};
|