From f49468d00edf37a620b04d12374c2821c382df75 Mon Sep 17 00:00:00 2001 From: pawan-dot <71133473+pawan-dot@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:18:07 +0530 Subject: [PATCH] register otp and verify otp --- .vscode/settings.json | 3 + Utils/sendEmail.js | 38 +++++--- app.js | 6 ++ package-lock.json | 56 ++++++++++-- package.json | 1 + resources/Patients/PatientController.js | 112 +++++++++++++++++++++++ resources/Patients/PatientModel.js | 114 ++++++++++++++++++++++++ resources/Patients/PatientRoute.js | 12 +++ 8 files changed, 325 insertions(+), 17 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 resources/Patients/PatientController.js create mode 100644 resources/Patients/PatientModel.js create mode 100644 resources/Patients/PatientRoute.js diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0399a78 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.formatOnSave": true +} \ No newline at end of file diff --git a/Utils/sendEmail.js b/Utils/sendEmail.js index cdc2f5a..626a44d 100644 --- a/Utils/sendEmail.js +++ b/Utils/sendEmail.js @@ -11,22 +11,12 @@ const transporter = createTransport({ }, }); -// const mailOptions = { -// from: process.env.SMPT_MAIL, -// to: options.email, -// subject: options.subject, -// text: options.message, -// }; - const sendEmail = async (options) => { - // console.log(options); await transporter.sendMail(options, function (error, info) { if (error) { console.log(error); } - // else { - // console.log("Email sent: " + info?.response); - // } + }); }; export default sendEmail; @@ -39,3 +29,29 @@ export default sendEmail; // } // export default sendEmail + +// from message bird send mail------------------------------------ +// messageSender.js +// import messagebird from "messagebird"; + +// const apiKey = "7oOgyzfNuwBnqMc2oK6aGfczs"; +// const messagebirdClient = messagebird(apiKey); +import { initClient } from "messagebird"; +const messagebird = initClient("e7HGr3kMl6su4c79DKjNAwlLQ"); + export const sendOtp = (recipient, message) => { + const params = { + originator: "TestMessage", + recipients: `+918874747774`, + body: "hi how are you", + }; + + messagebird.messages.create(params, (err, response) => { + if (err) { + console.error("Error sending message:", err); + return; + } + console.log("Message sent successfully:", response); + console.log("Message rrrrrrrrrrrrrrrr:", response?.recipients?.items); + }); +}; + diff --git a/app.js b/app.js index 3c1e97d..2908e8c 100644 --- a/app.js +++ b/app.js @@ -137,6 +137,8 @@ import StateRouter from "./resources/setting/state/state_routes.js"; import LanguageRoute from "./resources/setting/Language/language_routes.js"; //purpose import PurposeRoute from "./resources/setting/Purpose/Purpose_routes.js"; +//Patient Routes +import PatientRoute from './resources/Patients/PatientRoute.js' // category Route import categoryRoute from "./resources/Category/categoryRoutes.js"; @@ -193,6 +195,10 @@ app.use("/api/content", ContentRoute); // User Address app.use("/api/user-address", UserAddressRoute); app.use("/api/shipping/address", ShippingAddressRoute); +//Patient Routes +app.use("/api/patient", PatientRoute); + + //Order app.use("/api/order", orderRoute); //Departure diff --git a/package-lock.json b/package-lock.json index a1f5970..6b2cba6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "express-fileupload": "^1.4.0", "generate-password": "^1.7.0", "jsonwebtoken": "^8.5.1", + "messagebird": "^4.0.1", "micro": "^10.0.1", "mongoose": "^6.3.5", "multer": "^1.4.5-lts.1", @@ -2326,6 +2327,14 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, + "node_modules/jose": { + "version": "4.15.7", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.7.tgz", + "integrity": "sha512-L7ioP+JAuZe8v+T5+zVI9Tx8LtU8BL7NxkyDFVMv+Qr3JW0jSoYDedLtodaXwfqMpeCyx4WXFNyu9tJt4WvC1A==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-git": { "version": "0.7.8", "resolved": "https://registry.npmjs.org/js-git/-/js-git-0.7.8.tgz", @@ -2527,6 +2536,19 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, + "node_modules/messagebird": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/messagebird/-/messagebird-4.0.1.tgz", + "integrity": "sha512-Abn0aoH1Dzsq5KMeI3LNanVETwu4+HvNXZrhWRGzRIJ9ea88sefsVfy98Qj4NDmxGuXLFmT8Lhgw1kStzu7F0g==", + "dependencies": { + "jose": "^4.9.2", + "safe-buffer": "^5.2.1", + "scmp": "^2.1.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -3789,6 +3811,11 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" }, + "node_modules/scmp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz", + "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==" + }, "node_modules/secure-random": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/secure-random/-/secure-random-1.1.2.tgz", @@ -5417,8 +5444,7 @@ "cloudinary-core": { "version": "2.12.3", "resolved": "https://registry.npmjs.org/cloudinary-core/-/cloudinary-core-2.12.3.tgz", - "integrity": "sha512-Ll4eDzcrIVn4zCttMh3Mdi+KNz07p5EEjBT2PQSRx8Eok1lKPt3uBBenOk/w88RKK3B8SFIWcEe/mN4BHQ0p8A==", - "requires": {} + "integrity": "sha512-Ll4eDzcrIVn4zCttMh3Mdi+KNz07p5EEjBT2PQSRx8Eok1lKPt3uBBenOk/w88RKK3B8SFIWcEe/mN4BHQ0p8A==" }, "color-convert": { "version": "2.0.1", @@ -6276,6 +6302,11 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, + "jose": { + "version": "4.15.7", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.7.tgz", + "integrity": "sha512-L7ioP+JAuZe8v+T5+zVI9Tx8LtU8BL7NxkyDFVMv+Qr3JW0jSoYDedLtodaXwfqMpeCyx4WXFNyu9tJt4WvC1A==" + }, "js-git": { "version": "0.7.8", "resolved": "https://registry.npmjs.org/js-git/-/js-git-0.7.8.tgz", @@ -6460,6 +6491,16 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, + "messagebird": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/messagebird/-/messagebird-4.0.1.tgz", + "integrity": "sha512-Abn0aoH1Dzsq5KMeI3LNanVETwu4+HvNXZrhWRGzRIJ9ea88sefsVfy98Qj4NDmxGuXLFmT8Lhgw1kStzu7F0g==", + "requires": { + "jose": "^4.9.2", + "safe-buffer": "^5.2.1", + "scmp": "^2.1.0" + } + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -6661,8 +6702,7 @@ "multer-storage-cloudinary": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/multer-storage-cloudinary/-/multer-storage-cloudinary-4.0.0.tgz", - "integrity": "sha512-25lm9R6o5dWrHLqLvygNX+kBOxprzpmZdnVKH4+r68WcfCt8XV6xfQaMuAg+kUE5Xmr8mJNA4gE0AcBj9FJyWA==", - "requires": {} + "integrity": "sha512-25lm9R6o5dWrHLqLvygNX+kBOxprzpmZdnVKH4+r68WcfCt8XV6xfQaMuAg+kUE5Xmr8mJNA4gE0AcBj9FJyWA==" }, "mute-stream": { "version": "0.0.8", @@ -7397,6 +7437,11 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" }, + "scmp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz", + "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==" + }, "secure-random": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/secure-random/-/secure-random-1.1.2.tgz", @@ -7895,8 +7940,7 @@ "ws": { "version": "7.4.6", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "requires": {} + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" }, "xregexp": { "version": "2.0.0", diff --git a/package.json b/package.json index ce48475..72d3461 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "express-fileupload": "^1.4.0", "generate-password": "^1.7.0", "jsonwebtoken": "^8.5.1", + "messagebird": "^4.0.1", "micro": "^10.0.1", "mongoose": "^6.3.5", "multer": "^1.4.5-lts.1", diff --git a/resources/Patients/PatientController.js b/resources/Patients/PatientController.js new file mode 100644 index 0000000..5cf22ad --- /dev/null +++ b/resources/Patients/PatientController.js @@ -0,0 +1,112 @@ +// import hashPassword from '../utils/hashPassword'; + +import crypto from 'crypto'; +import Patient from './PatientModel.js' +export const register = async (req, res) => { + const { name, mobileNumber } = req.body; + try { + let patient = await Patient.findOne({ mobileNumber }); + + if (patient && patient.isVerified) { + return res.status(400).json({ message: 'Patient already registered and verified for This Mobile No.' }); + } + + const otp = crypto.randomInt(100000, 1000000).toString(); + + // const otp ="123456"; + + const otpExpires = Date.now() + 10 * 60 * 1000; // 10 minutes + + if (patient) { + patient.otp = otp; + patient.otpExpires = otpExpires; + } else { + patient = new Patient({ name, mobileNumber, otp, otpExpires }); + } + + await patient.save(); + // await sendOtp(mobileNumber, otp); + + res.status(200).json({patient, message: `OTP ${otp} sent to your mobile number successfully` }); + } catch (error) { + res.status(500).json({ + message: error.message ? error.message : "Server error!", + }); + } +}; + +export const verifyOtp = async (req, res) => { + const { mobileNumber, otp } = req.body; + try { + const patient = await Patient.findOne({ mobileNumber }); + + if (!patient) { + return res.status(400).json({ message: 'Invalid mobile number or OTP' }); + } + + if (patient.otp !== otp || patient.otpExpires < Date.now()) { + return res.status(400).json({ message: 'Invalid or expired OTP' }); + } + + patient.isVerified = true; + patient.otp = undefined; + patient.otpExpires = undefined; + + await patient.save(); + + res.status(200).json({patient, message: 'Mobile number verified successfully' }); + } catch (error) { +res.status(500).json({ + message: error.message ? error.message : "Server error!", + }); } +}; + +export const completeRegistration = async (req, res) => { + const { + mobileNumber, + email, + password, + confirmPassword, + gender, + weight, + height, + age, + commonHealthComplaints, + familyHistory, + personalHistory, + dailyRoutine, + } = req.body; + if (password !== confirmPassword) { + return res.status(400).json({ message: 'Password and confirm password do not match' }); + } + try { + const patient = await Patient.findOne({ mobileNumber }); + + if (!patient || !patient.isVerified) { + return res.status(400).json({ message: 'Patient not found or not verified' }); + } + + // const hashedPassword = await hashPassword(password); + + patient.email = email; + patient.password = hashedPassword; + patient.gender = gender; + patient.weight = weight; + patient.height = height; + patient.age = age; + patient.commonHealthComplaints = commonHealthComplaints; + patient.familyHistory = familyHistory; + patient.personalHistory = personalHistory; + patient.dailyRoutine = dailyRoutine; + + await patient.save(); + + res.status(200).json({ message: 'Registration details updated successfully' }); + } catch (error) { + +res.status(500).json({ + message: error.message ? error.message : "Server error!", + }); + + } +}; \ No newline at end of file diff --git a/resources/Patients/PatientModel.js b/resources/Patients/PatientModel.js new file mode 100644 index 0000000..d570f42 --- /dev/null +++ b/resources/Patients/PatientModel.js @@ -0,0 +1,114 @@ +import dotenv from "dotenv"; +dotenv.config(); +import mongoose from "mongoose"; +import validator from "validator"; +import bcrypt from "bcryptjs"; +import jwt from "jsonwebtoken"; +import crypto from "crypto"; +const patientSchema = new mongoose.Schema( + { + name: { + type: String, + required: true, + }, + mobileNumber: { + type: String, + required: true, + unique: true, + }, + otp: { + type: String, + required: false, + }, + otpExpires: { + type: Date, + }, + isVerified: { + type: Boolean, + default: false, + }, + deviceAdded: { + type: Boolean, + default: false, + }, + email: String, + password: { + type: String, + minLength: [6, "Password should be greater than 6 characters"], + select: false, //find not got passpord + }, + avatar: { + public_id: { + type: String, + // required: true, + }, + url: { + type: String, + // required: true, + }, + }, + gender: { + type: String, + enum: ['Male', 'Female'], + }, + weight: { + type: String, + enum: ['Kilos', 'Lbs'], + }, + height: { + type: String, + enum: ['Feet', 'Cms'], + }, + age: Number, + commonHealthComplaints: String, + familyHistory: String, + personalHistory: String, + dailyRoutine: String, + + resetPasswordToken: String, + resetPasswordExpire: Date, + }, + { timestamps: true } +); + +patientSchema.pre("save", async function (next) { + if (!this.isModified("password")) { + next(); + } + + this.password = await bcrypt.hash(this.password, 10); +}); + +// JWT TOKEN +patientSchema.methods.getJWTToken = function () { + return jwt.sign({ id: this._id }, process.env.JWT_SECRET); +}; + +// Compare Password +patientSchema.methods.comparePassword = async function (password) { + return await bcrypt.compare(password, this.password); +}; + +// Generating Reset Token +patientSchema.methods.getResetPasswordToken = function () { + // Generating Token + const resetToken = crypto.randomBytes(20).toString("hex"); + + // Hashing and adding reset PasswordToken to patientSchema + this.resetPasswordToken = crypto + .createHash("sha256") + .update(resetToken) + .digest("hex"); + //expire password time + // console.log(this.resetPasswordToken) + this.resetPasswordExpire = Date.now() + 15 * 60 * 1000; //15 minut + + return resetToken; +}; + +const Patient = mongoose.model("Patient", patientSchema); + + export default Patient; + + + diff --git a/resources/Patients/PatientRoute.js b/resources/Patients/PatientRoute.js new file mode 100644 index 0000000..ec9f384 --- /dev/null +++ b/resources/Patients/PatientRoute.js @@ -0,0 +1,12 @@ +import express from "express"; + +const router = express.Router(); +// import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js"; +import { completeRegistration, register, verifyOtp } from "./PatientController.js"; + + +router.post('/register', register); +router.post('/verify-otp', verifyOtp); +router.post('/complete-registration', completeRegistration); + +export default router;