powr-sdk-api
Version:
Shared API core library for PowrStack projects. Zero dependencies - works with Express, Next.js API routes, and other frameworks. All features are optional and install only what you need.
256 lines (239 loc) • 6.31 kB
JavaScript
"use strict";
const express = require("express");
const router = express.Router();
const {
getDb
} = require("../services/mongo");
const {
ObjectId
} = require("mongodb");
const {
verifyToken
} = require("../middleware/jwtToken");
const {
getClientIp
} = require("../utils/getClientIp");
const {
coercePhoneForStorage
} = require("../utils/phone");
// Create User
router.post("/", verifyToken, async (req, res) => {
const {
phoneNumber,
email,
...userData
} = req.body;
const projectId = req.projectId; // Use middleware-injected projectId
try {
// Check if user already exists
const db = await getDb();
const storedPhone = phoneNumber && !String(phoneNumber).includes("@") ? coercePhoneForStorage(phoneNumber) : phoneNumber;
if (phoneNumber && !String(phoneNumber).includes("@") && !storedPhone) {
return res.status(400).json({
success: false,
message: "Invalid phone number"
});
}
const existingUser = await db.collection("users").findOne({
$or: [{
phoneNumber: storedPhone
}, {
email
}]
});
if (existingUser) {
return res.status(400).json({
success: false,
message: "User with this phone number or email already exists"
});
}
const newUser = {
...userData,
phoneNumber: storedPhone,
email,
createdAt: new Date(),
updatedAt: new Date()
};
const result = await db.collection("users").insertOne(newUser);
// Create profile for this project
const newProfile = {
userId: result.insertedId,
projectId: projectId,
access: userData.access || 1,
createdAt: new Date(),
lastActiveAt: new Date(),
lastActiveFrom: getClientIp(req)
};
await db.collection("profiles").insertOne(newProfile);
return res.status(201).json({
success: true,
message: "User created successfully",
userId: result.insertedId
});
} catch (error) {
console.error("Error creating user:", error);
return res.status(500).json({
success: false,
message: "Failed to create user."
});
}
});
// Get All Users
router.get("/", verifyToken, async (req, res) => {
const {
_id,
phoneNumber,
email
} = req.query;
const projectId = req.projectId; // Use middleware-injected projectId
try {
let query = {};
// Add filters if provided
if (_id) {
query._id = new ObjectId(_id);
}
if (phoneNumber) {
query.phoneNumber = phoneNumber;
}
if (email) {
query.email = email;
}
const db = await getDb();
const users = await db.collection("users").find(query).toArray();
// Get profiles for this project
const userIds = users.map(user => user._id);
const profiles = await db.collection("profiles").find({
userId: {
$in: userIds
},
projectId: projectId
}).toArray();
// Merge user data with profile data
const usersWithProfiles = users.map(user => {
const profile = profiles.find(p => p.userId.toString() === user._id.toString());
return {
...user,
access: profile ? profile.access : 1,
projectId: projectId
};
});
return res.json({
success: true,
data: usersWithProfiles
});
} catch (error) {
console.error("Error fetching users:", error);
return res.status(500).json({
success: false,
message: "Failed to fetch users."
});
}
});
// Update User
router.put("/:id", verifyToken, async (req, res) => {
const {
id
} = req.params;
const {
phoneNumber,
email,
...userData
} = req.body;
const projectId = req.projectId; // Use middleware-injected projectId
try {
// Check if user exists
const db = await getDb();
const existingUser = await db.collection("users").findOne({
_id: new ObjectId(id)
});
if (!existingUser) {
return res.status(404).json({
success: false,
message: "User not found"
});
}
// Update user
const normalizedPhone = phoneNumber && !String(phoneNumber).includes("@") ? coercePhoneForStorage(phoneNumber) : phoneNumber;
if (phoneNumber && !String(phoneNumber).includes("@") && !normalizedPhone) {
return res.status(400).json({
success: false,
message: "Invalid phone number"
});
}
const updateData = {
...userData,
phoneNumber: normalizedPhone,
email,
updatedAt: new Date()
};
await db.collection("users").updateOne({
_id: new ObjectId(id)
}, {
$set: updateData
});
// Update profile if access level is provided
if (userData.access !== undefined) {
await db.collection("profiles").updateOne({
userId: new ObjectId(id),
projectId: projectId
}, {
$set: {
access: userData.access,
updatedAt: new Date()
}
}, {
upsert: true
});
}
return res.json({
success: true,
message: "User updated successfully"
});
} catch (error) {
console.error("Error updating user:", error);
return res.status(500).json({
success: false,
message: "Failed to update user."
});
}
});
// Delete User
router.delete("/:id", verifyToken, async (req, res) => {
const {
id
} = req.params;
const projectId = req.projectId; // Use middleware-injected projectId
try {
// Check if user exists
const db = await getDb();
const existingUser = await db.collection("users").findOne({
_id: new ObjectId(id)
});
if (!existingUser) {
return res.status(404).json({
success: false,
message: "User not found"
});
}
// Delete user
await db.collection("users").deleteOne({
_id: new ObjectId(id)
});
// Delete profile for this project
await db.collection("profiles").deleteOne({
userId: new ObjectId(id),
projectId: projectId
});
return res.json({
success: true,
message: "User deleted successfully"
});
} catch (error) {
console.error("Error deleting user:", error);
return res.status(500).json({
success: false,
message: "Failed to delete user."
});
}
});
module.exports = router;