From 03953a5aed6077bccead780d0679922a61c7af61 Mon Sep 17 00:00:00 2001 From: Naidu Date: Fri, 28 Jun 2024 11:22:11 +0530 Subject: [PATCH] singup & login with OTP Installation App --- src/controllers/storeController.js | 259 ++++++++++++++++++++++++----- src/controllers/userController.js | 40 +++++ src/index.js | 102 ++++++++++++ src/models/store.js | 104 +++++++----- src/routes/storeRoute.js | 107 +++++++----- 5 files changed, 491 insertions(+), 121 deletions(-) diff --git a/src/controllers/storeController.js b/src/controllers/storeController.js index bbaac118..dc224f07 100644 --- a/src/controllers/storeController.js +++ b/src/controllers/storeController.js @@ -1,66 +1,98 @@ const boom = require("boom"); -const jwt = require('jsonwebtoken') -const bcrypt = require('bcrypt') +const bcrypt = require('bcrypt'); +const jwt = require('jsonwebtoken'); const fastify = require("fastify"); -const { Store } = require("../models/store"); +const { Install, ProfilePictureInstall } = require("../models/store"); -exports.storeSignUp = async (request, reply) => { +const supplierController = require("../controllers/supplierController") - try { - const { phone1,name,phone2, city,team,manager,picture,email, password } = request.body - - // Check if the email address is valid - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ - if (!emailRegex.test(email)) { - return reply.status(400).send({ message: 'Invalid email address' }) - } - - // Check if an admin with the same email address already exists - const existingstore = await Store.findOne({ phone1 }) - - if (existingstore) { - return reply.status(400).send({ message: 'Phone is already registered' }) - } - - // Hash the password using bcrypt - const hashedPassword = await bcrypt.hash(password, 10) - - // Create a new admin object with the hashed password - const store = new Store({ phone1,name,phone2, city,team,manager,picture,email, password: hashedPassword }) - - // Save the new admin to the database - await store.save() - - reply.send({message : "Store Account Created Sucessfully"}) - } catch (err) { - reply.status(500).send({ message: err.message }) + + +exports.installSignUp = async (request, reply) => { + try { + const { + name, + phone, + address, + installationId, + emails, + password, + profile, + team, + manager, + longitude, + latitude, + fcmId, + createdBy, + updatedBy, + } = request.body; + + // Check if the email address is valid + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (emails.some((emailObj) => !emailRegex.test(emailObj.email))) { + return reply.status(400).send({ message: 'Invalid email address' }); } - } + + // Check if a user with the same phone number already exists + const existingInstall = await Install.findOne({ phone }); + if (existingInstall) { + return reply.status(400).send({ message: 'Phone is already registered' }); + } + + // Hash the password using bcrypt + const hashedPassword = await bcrypt.hash(password, 10); + + // Create a new install object with the hashed password and other details + const install = new Install({ + name, + phone, + address, + installationId, + emails, + services: { password: { bcrypt: hashedPassword } }, + profile, + team, + manager, + longitude, + latitude, + fcmId, + createdBy, + updatedBy, + }); + + // Save the new install to the database + await install.save(); + + reply.send({ message: 'Install Account Created Successfully' }); + } catch (err) { + reply.status(500).send({ message: err.message }); + } + }; - exports.storeLogin = async (request, reply) => { + exports.installLogin = async (request, reply) => { try { const { phone1, password } = request.body // Check if an admin with the email address exists - const store = await Store.findOne({ phone1 }) + const install = await Install.findOne({ phone1 }) - if (!store) { + if (!install) { return reply.status(401).send({ message: 'Invalid Phone1 or password' }) } // Compare the password entered by the user with the hashed password stored in the database - const isPasswordValid = await bcrypt.compare(password, store.password) + const isPasswordValid = await bcrypt.compare(password, install.password) if (!isPasswordValid) { return reply.status(401).send({ message: 'Invalid phone or password' }) } // Generate a JWT token for the authenticated admin - const token = jwt.sign({ phone1: store.phone1 }, 'secret') + const token = jwt.sign({ phone1: install.phone1 }, 'secret') // Return the token to the client return { token } @@ -69,3 +101,154 @@ exports.storeSignUp = async (request, reply) => { } } + + + exports.installationVerifyPhone = async (req, reply) => { + console.log("-------------------------------------------------"); + try { + phone = req.body.phone; + phoneVerificationCode = req.body.phoneVerificationCode; + + // check if user exists in the system. If user exists , display message that + // username is not available + console.log( + "this is the phone and verification code", + phone, + phoneVerificationCode + ); + deliveryBoyExists = await Install.findOne({ + phone: phone, + //phoneVerified: false, + phoneVerificationCode: phoneVerificationCode, + }); + console.log(deliveryBoyExists); + if (deliveryBoyExists) { + // update the phoneVerified flag to true. + const filter = { + phone: phone, + phoneVerificationCode: phoneVerificationCode, + }; + const update = { phoneVerified: true }; + const doc = await Install.findOneAndUpdate(filter, update); + updatedDeliveryBoy = await Install.findOne({ phone: phone }); + + if (updatedDeliveryBoy.phoneVerified) { + loginObject = await supplierController.loginInstallation(req); + console.log("loginObject...", loginObject); + if (loginObject.same) { + const phoneVerified = loginObject.delivery.phoneVerified; + const oneTimePasswordSetFlag = + loginObject.delivery.oneTimePasswordSetFlag; + console.log( + "oneTimePasswordSetFlag is ......", + oneTimePasswordSetFlag, + typeof oneTimePasswordSetFlag, + typeof phoneVerified + ); + if (!phoneVerified) { + reply.send({ + simplydata: { + error: false, + phoneVerified: false, + + phone: loginObject.delivery.phone, + oneTimePasswordSetFlag: oneTimePasswordSetFlag, + message: "Please Verify your phone number", + }, + }); + } else if (oneTimePasswordSetFlag) { + reply.send({ + simplydata: { + error: false, + phoneVerified: phoneVerified, + phone: loginObject.delivery.phone, + oneTimePasswordSetFlag: true, + message: "Password must be reset", + }, + }); + } else { + const token = fastify.jwt.sign( + { + name: loginObject.delivery.name, + }, + //expiresIn: expressed in seconds or a string describing a time span zeit/ms. Eg: 60, "2 days", "10h", "7d". + //A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), + //otherwise milliseconds unit is used by default ("120" is equal to "120ms"). + { expiresIn: "30d" } + ); + console.log(token, "..token"); + + var d_id = loginObject.delivery._id; + + console.log(d_id, "deliveryId"); + var profilePicture = await ProfilePictureInstall.findOne({ + installationId: d_id, + }); + + // request.session.set('supplierId', loginObject.supplier._id) + + if (!profilePicture) { + reply.send({ + simplydata: { + error: false, + apiversion: fastify.config.APIVERSION, + access_token: token, + + phone: loginObject.delivery.phone, + installationId: loginObject.delivery.installationId, + name: loginObject.delivery.name, + address: loginObject.delivery.address, + phoneVerified: loginObject.delivery.phoneVerified, + oneTimePasswordSetFlag: + loginObject.delivery.oneTimePasswordSetFlag, + + + }, + }); + } + if (profilePicture) { + reply.send({ + simplydata: { + error: false, + apiversion: fastify.config.APIVERSION, + access_token: token, + picture: profilePicture.picture, + phone: loginObject.delivery.phone, + installationId: loginObject.delivery.installationId, + + name: loginObject.delivery.name, + address: loginObject.delivery.address, + phoneVerified: loginObject.delivery.phoneVerified, + oneTimePasswordSetFlag: + loginObject.delivery.oneTimePasswordSetFlag, + + }, + }); + } + } + } else { + error = { + simplydata: { + error: true, + code: 400, + message: "Invalid Details", + }, + }; + reply.send(error); + } + } + }else { + error = { + armintatankdata: { + error: true, + code: 10005, + message: "10005 - Verification code entered cannot be validated.", + }, + }; + req.body.regError = error; + reply.send(error); + } + } catch (err) { + throw boom.boomify(err); + } + }; diff --git a/src/controllers/userController.js b/src/controllers/userController.js index 013960e8..3ebae2ad 100644 --- a/src/controllers/userController.js +++ b/src/controllers/userController.js @@ -300,6 +300,38 @@ exports.loginUser = async (req) => { throw boom.boomify(err); } }; +exports.loginUserWithOTP = async (req) => { + try { + const phone = req.body.phone; + const phoneVerificationCode = req.body.phoneVerificationCode; + + const userDetails = await User.findOne({ phone: phone }); + const supplier = await Supplier.findOne({phone: phone}) + const deliveryBoy = await DeliveryBoy.findOne( { phone : phone}) + const installation = await Install.findOne( { phone : phone}) + + let user; + if(userDetails){ + user = await User.findOne({ phone: phone, 'phoneVerificationCode': phoneVerificationCode }); + } + if(supplier){ + user = await Supplier.findOne({ phone: phone, 'phoneVerificationCode': phoneVerificationCode }); + } + if(deliveryBoy){ + user = await DeliveryBoy.findOne({ phone: phone, 'phoneVerificationCode': phoneVerificationCode }); + } + if(installation){ + user = await Install.findOne({ phone: phone, 'phoneVerificationCode': phoneVerificationCode }); + } + if (user) { + return { same: true, user: user }; + } else { + return { same: false }; + } + } catch (err) { + throw boom.boomify(err); + } +}; // Update an existing user exports.updateUser = async (req, reply) => { @@ -451,6 +483,7 @@ exports.logout = async (request, reply) => { // controller.js const http = require('https'); +const { Install } = require("../models/store"); exports.sendSms = async (request, reply) => { const code = Math.floor(100000 + Math.random() * 900000); @@ -463,6 +496,9 @@ exports.sendSms = async (request, reply) => { const user = await User.findOne({phone: mobile}) const supplier = await Supplier.findOne({phone: mobile}) const deliveryBoy = await DeliveryBoy.findOne( { phone : mobile}) + const installation = await Install.findOne( { phone : mobile}) + + if(user){ await User.findOneAndUpdate({phone: mobile}, { $set: {'phoneVerificationCode': code } }) } @@ -472,6 +508,10 @@ exports.sendSms = async (request, reply) => { if(deliveryBoy){ await DeliveryBoy.findOneAndUpdate({phone: mobile}, { $set: {'phoneVerificationCode': code } }) } + if(installation){ + await Install.findOneAndUpdate({phone: mobile}, { $set: {'phoneVerificationCode': code } }) + } + const apiUrl = `https://smslogin.co/v3/api.php?username=${username}&apikey=${apiKey}&senderid=${senderId}&mobile=${mobile}&message=${encodeURIComponent(message)}`; diff --git a/src/index.js b/src/index.js index e08cba81..c0e2fc4e 100644 --- a/src/index.js +++ b/src/index.js @@ -276,6 +276,107 @@ fastify.post("/api/login", { }, }); +fastify.post("/api/installotplogin", { + schema: { + description: "This is for Login Otp Boy", + tags: ["Install"], + summary: "This is for Login Otp Boy", + body: { + type: "object", + required: ["phone", "phoneVerificationCode"], + properties: { + phoneVerificationCode: { type: "string" }, + phone: { type: "string" }, + }, + }, + }, + async handler(req, reply) { + const { phone, phoneVerificationCode } = req.body; + + // Assuming loginUserInstall function exists and works properly + try{ + + const loginObject = await userController.loginUserWithOTP(req); + + + if (loginObject.same) { + const phoneVerified = loginObject.user.phoneVerified; + const oneTimePasswordSetFlag = loginObject.user.oneTimePasswordSetFlag; + + if (!phoneVerified) { + reply.send({ + simplydata: { + error: false, + phoneVerified: false, + phone: loginObject.user.phone, + oneTimePasswordSetFlag: oneTimePasswordSetFlag, + message: "Please Verify your phone number", + }, + }); + } else if (oneTimePasswordSetFlag) { + reply.send({ + simplydata: { + error: false, + phoneVerified: phoneVerified, + phone: loginObject.user.phone, + oneTimePasswordSetFlag: true, + message: "Password must be reset", + }, + }); + } else { + const token = fastify.jwt.sign( + { + name: loginObject.user.name, + }, + 'your_jwt_secret', // Replace with your actual JWT secret + { expiresIn: '30d' } + ); + + const profilePicture = await ProfilePictureInstall.findOne({ customerId: loginObject.user._id }); + + const responsePayload = { + simplydata: { + error: false, + apiversion: fastify.config.APIVERSION, + access_token: token, + email: loginObject.user.emails, + phone: loginObject.user.phone, + name: loginObject.user.name, + address1: loginObject.user.profile.address1, + address2: loginObject.user.profile.address2, + phoneVerified: loginObject.user.phoneVerified, + oneTimePasswordSetFlag: loginObject.user.oneTimePasswordSetFlag, + type: loginObject.user.profile.role, + fcmId: loginObject.user.fcmId, + team: loginObject.user.team, + city:loginObject.user.city, + manager:loginObject.user.manager, + // typeasobj: JSON.parse(loginObject.user.profile.role), + }, + }; + + if (profilePicture) { + responsePayload.simplydata.picture = profilePicture.picture; + } + + reply.send(responsePayload); + } + } else { + reply.send({ + simplydata: { + error: true, + code: 400, + message: "Invalid phone or phoneVerificationCode supplied", + }, + }); + } + }catch(e){ + console.log('errrorrrr',e) + } + }, +}); + + fastify.get("/api/reset_token/:customerId", { schema: { @@ -361,6 +462,7 @@ fastify.register(require("./routes/forTestingRoute")); const {Storage} = require('@google-cloud/storage'); const { Supplier, profilePictureSupplier } = require("./models/supplier"); const multer = require('fastify-multer'); +const { ProfilePictureInstall } = require("./models/store.js"); fastify.register(require('fastify-formbody')); // fastify.register(multer.contentParser); // const multipart = require('fastify-multipart'); diff --git a/src/models/store.js b/src/models/store.js index 24eabcc7..58db0593 100644 --- a/src/models/store.js +++ b/src/models/store.js @@ -4,52 +4,72 @@ const ObjectId = Schema.Types.ObjectId; -const storeschema = new mongoose.Schema({ - name: { - type: String, - required: true, - +const installationschema = new mongoose.Schema({ + name: { type: String }, + phone: { type: String, unique: true, trim: true }, + address: String, + installationId: { type: String }, + phoneVerified: { type: Boolean, default: false }, + phoneVerificationCode: { type: Number, default: 11111 }, + passwordResetCode: { type: Number}, + oneTimePasswordSetFlag: { type: Boolean, default: false }, + emails: [{ email: String, verified: { type: Boolean, default: false } }], + services: { password: { bcrypt: String } }, + + profile: { + alternativeNumber: { type: String, default: null }, + address1: { type: String, default: null }, + address2: { type: String, default: null }, + city: { type: String, default: null }, + state: { type: String, default: null }, + country: { type: String, default: null }, }, - email: { - type: String, - required: true, - unique: true, - lowercase: true - }, - - phone1: { - type: String, - default: false, - - }, - phone2: { - type: String, - default: false, - - }, - city: { - type: String, - required: true, - }, - team:{ - type:String - - }, - location: { - type:String, - default: false, + team : { type: String, default: null}, + manager : { type: String, default: null}, + + longitude: { type : Number,default: 0.0}, + latitude: {type: Number,default: 0.0}, + + fcmId: { type: String, default: null }, + createdAt: { + type: Date, + default: function () { + return Date.now(); + }, }, - picture: - { type: String }, - manager:{ - type: String, - default:false, + createdBy: ObjectId, + updatedAt: { + type: Date, + default: function () { + return Date.now(); + }, }, - password: - { type: String}, + updatedBy: ObjectId, }); - const Store = mongoose.model("Store", storeschema); + const profilePictureInstallSchema = new Schema({ + installationId: { + type: String, + unique: true, + required: true + }, + picture: { + type: String, // Change the type to String + required: true, + validate: { + validator: function (value) { + const supportedFormats = ['jpg', 'jpeg', 'png']; + const fileExtension = value.split('.').pop().toLowerCase(); + return supportedFormats.includes(fileExtension); + }, + message: 'Picture must be a JPEG, PNG, or JPG image' + } + } + }); + + const ProfilePictureInstall = mongoose.model('ProfilePictureInstall', profilePictureInstallSchema); + + const Install = mongoose.model("Install", installationschema); - module.exports = { Store}; + module.exports = { Install, ProfilePictureInstall}; diff --git a/src/routes/storeRoute.js b/src/routes/storeRoute.js index 4935bcc5..35e0aa60 100644 --- a/src/routes/storeRoute.js +++ b/src/routes/storeRoute.js @@ -3,60 +3,85 @@ const storeController = require('../controllers/storeController') module.exports = function (fastify, opts, next) { -fastify.route({ - method: "POST", - url: "/api/storeSignup", - schema: { - tags: ["Store"], - description: "This is for cretae New Store Account", - summary: "This is for cretae New Store Account", - body: { - type: "object", - properties: { - name:{ type: "string"}, - phone1: { type: "string"}, - phone2: { type: "string"}, - city: { type: "string"}, - location: { type: "string"}, - picture: { type: "string"}, - team: { type: "string"}, - manager: { type: "string"}, - - email: { type: "string" }, - password: { type: "string" }, - + fastify.route({ + method: 'POST', + url: '/api/installSignup', + schema: { + tags: ['Install'], + description: 'This is for creating a New Install Account', + summary: 'This is for creating a New Install Account', + body: { + type: 'object', + properties: { + phone: { type: 'string' }, + password: { type: 'string' }, + emails: { + type: 'array', + maxItems: 2, + items: { + type: 'object', + properties: { + email: { type: 'string', default: null }, + }, + }, + }, + name: { type: 'string' }, + team: { type: 'string', default: null }, + manager: { type: 'string', default: null }, + address1: { type: 'string', default: null }, + address2: { type: 'string', default: null }, + city: { type: 'string', default: null }, + state: { type: 'string', default: null }, + zip: { type: 'string', default: null }, + country: { type: 'string', default: null }, + notes: { type: 'string', default: null }, + latitude: { type: 'number', default: 0.0 }, + longitude: { type: 'number', default: 0.0 }, + fcmId: { type: 'string', default: null }, + }, + }, + security: [ + { + basicAuth: [], + }, + ], }, - }, - security: [ - { - basicAuth: [], - }, - ], - }, - - handler: storeController.storeSignUp, - - }); - - fastify.post("/api/storeLogin", { + handler: storeController.installSignUp, + }); + fastify.post("/api/insatllLogin", { schema: { - description: "This is for Login Store", - tags: ["Store"], - summary: "This is for Login Store", + description: "This is for Login Install", + tags: ["Install"], + summary: "This is for Login Install", body: { type: "object", required: ["phone1", "password"], properties: { phone1: { type: "string" }, password: { type: "string" }, + phoneVerificationCode: { type: "string" }, }, }, }, - handler: storeController.storeLogin, + handler: storeController.installLogin, }); - - +// fastify.post("/api/installotplogin", { +// schema: { +// description: "This is for Login Otp Boy", +// tags: ["Install"], +// summary: "This is for Login Otp Boy", +// body: { +// type: "object", +// required: ["phone"], +// properties: { +// phoneVerificationCode: { type: "string" }, +// phone: { type: "string" }, +// }, +// }, +// }, +// handler: storeController.installationVerifyPhone, +// }); next();