From da7783323820b0f06dbc1cc5536ae3856cc03d18 Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Wed, 16 Jul 2025 12:35:27 +0530 Subject: [PATCH] login chnages installation --- src/index.js | 460 +++++++++++++++++++++++++++++++------------- src/models/store.js | 186 ++++++++++++------ 2 files changed, 450 insertions(+), 196 deletions(-) diff --git a/src/index.js b/src/index.js index 326376a5..fae8b302 100644 --- a/src/index.js +++ b/src/index.js @@ -1138,18 +1138,131 @@ fastify.post("/api/uploads-material-recieved/:customerId/:installationId", async }); +// fastify.post("/api/installLogin", { +// schema: { +// description: "This is for Login Install", +// tags: ["Installation"], +// summary: "This is for Login Install", +// body: { +// type: "object", +// required: ["type", "phone", "password"], +// properties: { +// type: { type: "string", description: "User role type (e.g., 'admin', 'manager')" }, +// phone: { type: "string", description: "Registered phone number" }, +// password: { type: "string", description: "Password for authentication" }, +// }, +// }, +// }, +// async handler(req, reply) { +// try { +// const { type, phone, password } = req.body; + +// // Check if user exists in the Department Schema +// const user = await Deparments.findOne({ phone }); + +// if (!user) { +// return reply.code(400).send({ message: "User not found" }); +// } + +// // Verify Password +// const isMatch = await bcrypt.compare(password, user.services.password.bcrypt); + +// if (!isMatch) { +// return reply.code(400).send({ message: "Invalid credentials" }); +// } + +// // Check if department details already exist in installation schema +// let installation = await Install.findOne({ phone }); + +// if (!installation) { +// // Create a new entry in installation schema with departmentId as installationId +// installation = new Install({ +// phone: user.phone, +// installationId: user.departmentId, // Store departmentId in installationId +// firstName: user.firstName, +// lastName: user.lastName, +// email: user.email, +// alternativeNumber: user.alternativeContactNumber, +// departmentName: user.departmentName, +// designation: user.desginationName, +// reportingManager: user.reportingManager, +// city: user.city, +// zone: user.zone, +// address1: user.address1, +// address2: user.address2, +// profile: { +// state: user.state, +// country: user.country, +// role: type, // Store type in profile.role +// }, +// }); + +// await installation.save(); +// } + +// // Ensure `type` is stored in `profile.role` +// if (!installation.profile?.role) { +// installation.profile.role = type; +// await installation.save(); // Save the updated type +// } + +// // Fetch profile picture if available +// const profilePicture = await ProfilePictureInstall.findOne({ customerId: installation._id }); + +// // Generate JWT Token +// const token = fastify.jwt.sign( +// { userId: user._id, phone: user.phone, role: installation.profile?.role }, +// "your_secret_key", +// { expiresIn: "7d" } +// ); + +// // Construct response payload +// const responsePayload = { +// simplydata: { +// error: false, +// apiversion: fastify.config.APIVERSION, +// access_token: token, +// email: installation.emails || [], +// installationId: installation.installationId, +// phone: installation.phone, +// address1: installation.address1, +// address2: installation.address2, +// phoneVerified: installation.phoneVerified, +// oneTimePasswordSetFlag: installation.oneTimePasswordSetFlag, +// type: installation.profile?.role || "user", // Default to "user" if not available +// fcmIds: installation.fcmId || null, +// team: installation.team, +// city: installation.city, +// manager: installation.manager, +// firstName: installation.firstName, +// lastName: installation.lastName, +// address: installation.address || "", +// alternativeNumber: installation.alternativeNumber || null, +// profilePicture: profilePicture ? profilePicture.pictureUrl : null, // Include profile picture URL if available +// }, +// }; + +// return reply.send(responsePayload); +// } catch (error) { +// console.error("Login Error:", error); +// return reply.code(500).send({ message: "Internal server error" }); +// } +// }, +// }); + + fastify.post("/api/installLogin", { schema: { - description: "This is for Login Install", + description: "Login as Installation Manager", tags: ["Installation"], - summary: "This is for Login Install", + summary: "Installation Manager login", body: { type: "object", required: ["type", "phone", "password"], properties: { - type: { type: "string", description: "User role type (e.g., 'admin', 'manager')" }, + type: { type: "string", enum: ["Installation_Manager"], description: "Login type" }, phone: { type: "string", description: "Registered phone number" }, - password: { type: "string", description: "Password for authentication" }, + password: { type: "string", description: "Password" }, }, }, }, @@ -1157,28 +1270,24 @@ fastify.post("/api/installLogin", { try { const { type, phone, password } = req.body; - // Check if user exists in the Department Schema - const user = await Deparments.findOne({ phone }); - + // Find department record + const user = await Deparments.findOne({ phone }).lean(); if (!user) { return reply.code(400).send({ message: "User not found" }); } - // Verify Password + // Validate password const isMatch = await bcrypt.compare(password, user.services.password.bcrypt); - if (!isMatch) { - return reply.code(400).send({ message: "Invalid credentials" }); + return reply.code(401).send({ message: "Invalid credentials" }); } - // Check if department details already exist in installation schema + // Find or create installation document let installation = await Install.findOne({ phone }); - if (!installation) { - // Create a new entry in installation schema with departmentId as installationId installation = new Install({ - phone: user.phone, - installationId: user.departmentId, // Store departmentId in installationId + phone, + installationId: user.departmentId, firstName: user.firstName, lastName: user.lastName, email: user.email, @@ -1193,194 +1302,269 @@ fastify.post("/api/installLogin", { profile: { state: user.state, country: user.country, - role: type, // Store type in profile.role + role: type, // store login type }, }); - await installation.save(); - } - - // Ensure `type` is stored in `profile.role` - if (!installation.profile?.role) { + } else if (!installation.profile?.role) { installation.profile.role = type; - await installation.save(); // Save the updated type + await installation.save(); } - // Fetch profile picture if available - const profilePicture = await ProfilePictureInstall.findOne({ customerId: installation._id }); - - // Generate JWT Token + // Generate JWT const token = fastify.jwt.sign( - { userId: user._id, phone: user.phone, role: installation.profile?.role }, - "your_secret_key", + { userId: user._id, phone, role: type }, + "your_secret_key", // replace with config { expiresIn: "7d" } ); - // Construct response payload - const responsePayload = { - simplydata: { - error: false, - apiversion: fastify.config.APIVERSION, + return reply.send({ + success: true, + message: "Login successful", + data: { access_token: token, - email: installation.emails || [], installationId: installation.installationId, phone: installation.phone, - address1: installation.address1, - address2: installation.address2, - phoneVerified: installation.phoneVerified, - oneTimePasswordSetFlag: installation.oneTimePasswordSetFlag, - type: installation.profile?.role || "user", // Default to "user" if not available - fcmIds: installation.fcmId || null, - team: installation.team, - city: installation.city, - manager: installation.manager, firstName: installation.firstName, lastName: installation.lastName, - address: installation.address || "", - alternativeNumber: installation.alternativeNumber || null, - profilePicture: profilePicture ? profilePicture.pictureUrl : null, // Include profile picture URL if available + city: installation.city, + email: installation.emails?.map(e => e.email) || [], + type: installation.profile?.role || type, + team: installation.team, + manager: installation.manager, + fcmId: installation.fcmId, + alternativeNumber: installation.alternativeNumber, + phoneVerified: installation.phoneVerified, }, - }; - - return reply.send(responsePayload); - } catch (error) { - console.error("Login Error:", error); - return reply.code(500).send({ message: "Internal server error" }); + }); + } catch (err) { + console.error("installLogin error:", err); + reply.code(500).send({ message: "Internal server error" }); } - }, + } }); +// fastify.post("/api/teamMemberLogin", { +// schema: { +// description: "Login API for team members", +// tags: ["Installation"], +// summary: "Login as a Team Member", +// body: { +// type: "object", +// required: ["type", "phone", "password"], +// properties: { +// type: { type: "string", description: "Role type of the user (e.g., 'team_member')" }, +// phone: { type: "string", description: "Registered phone number of the team member" }, +// password: { type: "string", description: "Password for authentication" }, +// }, +// }, +// }, +// async handler(request, reply) { +// try { +// const { type, phone, password } = request.body; + +// // ✅ Step 1: Find the team member in `Deparments` +// const department = await Deparments.findOne({ +// "team_member.team_member.phone": phone +// }); + +// if (!department) { +// return reply.status(401).send({ +// simplydata: { +// error: true, +// message: "Invalid phone number", +// }, +// }); +// } + +// // ✅ Step 2: Find the specific team member +// const teamMember = department.team_member.team_member.find( +// (member) => member.phone === phone +// ); + +// if (!teamMember) { +// return reply.status(401).send({ +// simplydata: { +// error: true, +// message: "Invalid phone number", +// }, +// }); +// } + +// // ✅ Step 3: Verify password +// const isPasswordValid = await bcrypt.compare(password, teamMember.password); + +// if (!isPasswordValid) { +// return reply.status(401).send({ +// simplydata: { +// error: true, +// message: "Invalid phone number or password", +// }, +// }); +// } + +// console.log("Team Member First Name:", teamMember.firstName); // ✅ Debugging + +// // ✅ Step 4: Check if this team member already exists in `Install` +// let installation = await Install.findOne({ +// installationId: department.departmentId +// }); + +// if (!installation) { +// return reply.status(404).send({ +// simplydata: { +// error: true, +// message: "Installation not found", +// }, +// }); +// } + +// // Check if team member already exists in Install schema +// const existingTeamMember = installation.team_member.team_member.find( +// (member) => member.phone === phone +// ); + +// if (!existingTeamMember) { +// // ✅ Step 5: Add team member details to `Install` schema +// installation.team_member.team_member.push({ +// teamMemberId: teamMember.teamMemberId, +// firstName: teamMember.firstName, +// phone: teamMember.phone, +// email: teamMember.email, +// alternativePhone: teamMember.alternativePhone, +// installationTeamMemId: installation.installationId, +// password: teamMember.password, // Store hashed password +// status: teamMember.status || "active", +// type: type, // Store login type +// }); + +// await installation.save(); +// } + +// // ✅ Step 6: Generate JWT token +// const token = fastify.jwt.sign( +// { phone: teamMember.phone, role: type, installationId: installation.installationId }, +// "JWT_SECRET", +// { expiresIn: "1h" } +// ); + +// return reply.send({ +// simplydata: { +// error: false, +// message: "Login successful", +// access_token: token, +// phone: teamMember.phone, +// firstName: teamMember.firstName || null, // ✅ Now included +// teamMemberId: teamMember.teamMemberId, +// alternativePhone: teamMember.alternativePhone || null, +// email: teamMember.email || null, +// status: teamMember.status || "active", +// type: teamMember.type, +// installationId: installation.installationId +// }, +// }); + +// } catch (err) { +// console.error("Error logging in:", err); +// reply.status(500).send({ +// simplydata: { +// error: true, +// message: "Internal server error", +// }, +// }); +// } +// }, +// }); + + fastify.post("/api/teamMemberLogin", { schema: { - description: "Login API for team members", + description: "Login as Installation Team Member", tags: ["Installation"], - summary: "Login as a Team Member", + summary: "Team member login", body: { type: "object", required: ["type", "phone", "password"], properties: { - type: { type: "string", description: "Role type of the user (e.g., 'team_member')" }, - phone: { type: "string", description: "Registered phone number of the team member" }, - password: { type: "string", description: "Password for authentication" }, + type: { type: "string", enum: ["Installation_TeamMember"], description: "Login type" }, + phone: { type: "string", description: "Team member phone" }, + password: { type: "string", description: "Password" }, }, }, }, - async handler(request, reply) { + async handler(req, reply) { try { - const { type, phone, password } = request.body; - - // ✅ Step 1: Find the team member in `Deparments` - const department = await Deparments.findOne({ - "team_member.team_member.phone": phone - }); + const { type, phone, password } = req.body; + // Find department with this team member phone + const department = await Deparments.findOne({ "team_member.team_member.phone": phone }).lean(); if (!department) { - return reply.status(401).send({ - simplydata: { - error: true, - message: "Invalid phone number", - }, - }); + return reply.code(401).send({ message: "Invalid phone number" }); } - // ✅ Step 2: Find the specific team member - const teamMember = department.team_member.team_member.find( - (member) => member.phone === phone - ); - + // Find the actual team member + const teamMember = department.team_member.team_member.find(m => m.phone === phone); if (!teamMember) { - return reply.status(401).send({ - simplydata: { - error: true, - message: "Invalid phone number", - }, - }); + return reply.code(401).send({ message: "Invalid phone number" }); } - // ✅ Step 3: Verify password - const isPasswordValid = await bcrypt.compare(password, teamMember.password); - - if (!isPasswordValid) { - return reply.status(401).send({ - simplydata: { - error: true, - message: "Invalid phone number or password", - }, - }); + // Validate password + const isMatch = await bcrypt.compare(password, teamMember.password); + if (!isMatch) { + return reply.code(401).send({ message: "Invalid credentials" }); } - console.log("Team Member First Name:", teamMember.firstName); // ✅ Debugging - - // ✅ Step 4: Check if this team member already exists in `Install` - let installation = await Install.findOne({ - installationId: department.departmentId - }); - + // Find install document + const installation = await Install.findOne({ installationId: department.departmentId }); if (!installation) { - return reply.status(404).send({ - simplydata: { - error: true, - message: "Installation not found", - }, - }); + return reply.code(404).send({ message: "Installation not found" }); } - // Check if team member already exists in Install schema - const existingTeamMember = installation.team_member.team_member.find( - (member) => member.phone === phone - ); - - if (!existingTeamMember) { - // ✅ Step 5: Add team member details to `Install` schema + // Add team member to install if missing + const alreadyExists = installation.team_member?.team_member?.some(m => m.phone === phone); + if (!alreadyExists) { installation.team_member.team_member.push({ teamMemberId: teamMember.teamMemberId, firstName: teamMember.firstName, phone: teamMember.phone, - email: teamMember.email, - alternativePhone: teamMember.alternativePhone, installationTeamMemId: installation.installationId, - password: teamMember.password, // Store hashed password + password: teamMember.password, status: teamMember.status || "active", - type: type, // Store login type + email: teamMember.email, + alternativePhone: teamMember.alternativePhone, + type }); - await installation.save(); } - // ✅ Step 6: Generate JWT token + // Generate JWT const token = fastify.jwt.sign( - { phone: teamMember.phone, role: type, installationId: installation.installationId }, - "JWT_SECRET", + { phone, role: type, installationId: installation.installationId }, + "your_secret_key", // replace with config { expiresIn: "1h" } ); return reply.send({ - simplydata: { - error: false, - message: "Login successful", + success: true, + message: "Login successful", + data: { access_token: token, phone: teamMember.phone, - firstName: teamMember.firstName || null, // ✅ Now included + firstName: teamMember.firstName, teamMemberId: teamMember.teamMemberId, - alternativePhone: teamMember.alternativePhone || null, - email: teamMember.email || null, + alternativePhone: teamMember.alternativePhone, + email: teamMember.email, status: teamMember.status || "active", - type: teamMember.type, - installationId: installation.installationId - }, + type, + installationId: installation.installationId + } }); - } catch (err) { - console.error("Error logging in:", err); - reply.status(500).send({ - simplydata: { - error: true, - message: "Internal server error", - }, - }); + console.error("teamMemberLogin error:", err); + reply.code(500).send({ message: "Internal server error" }); } - }, + } }); diff --git a/src/models/store.js b/src/models/store.js index 4e56bb48..604c7370 100644 --- a/src/models/store.js +++ b/src/models/store.js @@ -24,75 +24,145 @@ const generateinstallationId = async () => { return result.seq; }; -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 } }, - alternativeNumber: { type: String, default: null }, - firstName: { type: String, default: null }, - lastName: { type: String, default: null }, - address1: { type: String, default: null }, - address2: { type: String, default: null }, - city: { type: String, default: null }, - designation: { type: String, default: null }, - reportingManager: { type: String, default: null }, - departmentName: { type: String, default: null }, - zone: { type: String, default: null }, - type: { type: String }, - - profile: { +// 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 } }, +// alternativeNumber: { type: String, default: null }, +// firstName: { type: String, default: null }, +// lastName: { type: String, default: null }, +// address1: { type: String, default: null }, +// address2: { type: String, default: null }, +// city: { type: String, default: null }, +// designation: { type: String, default: null }, +// reportingManager: { type: String, default: null }, +// departmentName: { type: String, default: null }, +// zone: { type: String, default: null }, +// type: { type: String }, + +// profile: { - state: { type: String, default: null }, - country: { type: String, default: null }, - }, - team : { type: String, default: null}, - manager : { type: String, default: null}, - team_member: { +// state: { type: String, default: null }, +// country: { type: String, default: null }, +// }, +// team : { type: String, default: null}, +// manager : { type: String, default: null}, +// team_member: { +// team_member: [ +// { +// teamMemberId: { type: String }, +// firstName: { type: String }, +// phone: { type: String }, +// installationTeamMemId: { type: String }, +// password: { type: String, default: null }, +// status: { type: String, default: "active" }, +// email: { type: String }, +// alternativePhone: { type: String }, + +// } +// ], + + +// }, + +// 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(); +// }, +// }, +// createdBy: ObjectId, +// updatedAt: { +// type: Date, +// default: function () { +// return Date.now(); +// }, +// }, +// updatedBy: ObjectId, + +// }); + + + + +const installationschema = new mongoose.Schema({ + phone: { type: String, unique: true, trim: true }, + address: { type: String, default: null }, + installationId: { type: String }, + phoneVerified: { type: Boolean, default: false }, + phoneVerificationCode: { type: Number, default: 11111 }, + passwordResetCode: { type: Number, default: null }, + oneTimePasswordSetFlag: { type: Boolean, default: false }, + emails: [ + { + email: { type: String }, + verified: { type: Boolean, default: false }, + }, + ], + services: { + password: { bcrypt: { type: String, default: null } }, + }, + alternativeNumber: { type: String, default: null }, + firstName: { type: String, default: null }, + lastName: { type: String, default: null }, + address1: { type: String, default: null }, + address2: { type: String, default: null }, + city: { type: String, default: null }, + designation: { type: String, default: null }, + reportingManager: { type: String, default: null }, + departmentName: { type: String, default: null }, + zone: { type: String, default: null }, + + // Store main user type (e.g., Installation_Manager, Installation_TeamMember) + type: { type: String, default: null }, + + profile: { + state: { type: String, default: null }, + country: { type: String, default: null }, + role: { type: String, default: null }, // <-- good to keep as per your login flow + }, + + team: { type: String, default: null }, + manager: { type: String, default: null }, + + team_member: { team_member: [ { - teamMemberId: { type: String }, - firstName: { type: String }, + teamMemberId: { type: String }, + firstName: { type: String, default: null }, phone: { type: String }, installationTeamMemId: { type: String }, password: { type: String, default: null }, status: { type: String, default: "active" }, - email: { type: String }, - alternativePhone: { type: String }, - - } + email: { type: String, default: null }, + alternativePhone: { type: String, default: null }, + type: { type: String, default: "Installation_TeamMember" }, // good to keep for clarity + }, ], - - }, - - 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(); - }, - }, - createdBy: ObjectId, - updatedAt: { - type: Date, - default: function () { - return Date.now(); - }, - }, - updatedBy: ObjectId, - - }); + longitude: { type: Number, default: 0.0 }, + latitude: { type: Number, default: 0.0 }, + + fcmId: { type: String, default: null }, + + createdAt: { type: Date, default: Date.now }, + createdBy: { type: ObjectId, default: null }, + updatedAt: { type: Date, default: Date.now }, + updatedBy: { type: ObjectId, default: null }, +}); const surveyschema = new mongoose.Schema({