api-v1/routes/userRoutes.js

220 lines
5.7 KiB
JavaScript

import express from "express";
import { insert, select, update } from "../db/queryHelper/index.js";
const router = express.Router();
// 1. CREATE User
router.post("/", async (req, res) => {
try {
// Parse and extract user data from request body
const {
id, // Optional: if provided, use this UUID; otherwise generate one
name,
phone_number,
avatar_url,
language,
timezone,
country_code = "+91",
} = req.body;
// Validate required fields
if (!name || !phone_number) {
return res.status(400).json({
error: "name and phone_number are required fields",
});
}
// Build user data object using JSON-based structure
const userData = {
name: name.trim(),
phone_number: phone_number.trim(),
avatar_url: avatar_url || null,
language: language || null,
timezone: timezone || null,
country_code: country_code || "+91",
};
// If id is provided, include it; otherwise let the database generate one
if (id) {
userData.id = id;
}
// Use queryHelper insert with JSON-based approach
const user = await insert({
table: 'users',
data: userData,
returning: '*',
});
res.status(201).json(user);
} catch (err) {
console.error("Error creating user:", err);
if (err.code === "23505") {
// Unique constraint violation
return res.status(400).json({
error: err.detail || "A user with this phone number or ID already exists",
});
}
if (err.code === "23503") {
// Foreign key violation
return res.status(400).json({
error: err.detail || "Foreign key constraint violation",
});
}
res.status(500).json({ error: err.message || "Internal server error" });
}
});
// 2. GET All Users
router.get("/", async (req, res) => {
try {
// Parse and validate query parameters
const limit = Math.min(parseInt(req.query.limit) || 100, 100);
const offset = parseInt(req.query.offset) || 0;
const { is_active, phone_number, name } = req.query;
// Build where conditions from query parameters
const where = { deleted: false };
if (is_active !== undefined) {
where.is_active = is_active === 'true' || is_active === true;
}
if (phone_number) {
where.phone_number = phone_number;
}
if (name) {
where.name = { op: 'ilike', value: `%${name}%` };
}
const users = await select({
table: 'users',
columns: ['id', 'name', 'phone_number', 'avatar_url', 'language', 'timezone', 'country_code', 'is_active', 'created_at', 'updated_at'],
where,
orderBy: {
column: 'created_at',
direction: 'desc',
},
limit,
offset,
});
res.json(users);
} catch (err) {
console.error("Error fetching users:", err);
res.status(500).json({ error: "Internal server error" });
}
});
// 3. GET Single User
router.get("/:id", async (req, res) => {
try {
const { id } = req.params;
// Use queryHelper select with JSON-based where conditions
const user = await select({
table: 'users',
columns: ['id', 'name', 'phone_number', 'avatar_url', 'language', 'timezone', 'country_code', 'is_active', 'created_at', 'updated_at'],
where: {
id,
deleted: false,
},
limit: 1,
});
if (user.length === 0) {
return res.status(404).json({ error: "User not found" });
}
res.json(user[0]);
} catch (err) {
console.error("Error fetching user:", err);
res.status(500).json({ error: "Internal server error" });
}
});
// 4. UPDATE User
router.put("/:id", async (req, res) => {
try {
const { id } = req.params;
// Parse and extract update data from request body
const { name, phone_number, avatar_url, language, timezone, country_code, is_active } = req.body;
// Build update data object using JSON-based structure (only include fields that are provided)
const updateData = {};
if (name !== undefined) updateData.name = name.trim();
if (phone_number !== undefined) updateData.phone_number = phone_number.trim();
if (avatar_url !== undefined) updateData.avatar_url = avatar_url || null;
if (language !== undefined) updateData.language = language || null;
if (timezone !== undefined) updateData.timezone = timezone || null;
if (country_code !== undefined) updateData.country_code = country_code;
if (is_active !== undefined) updateData.is_active = is_active === true || is_active === 'true';
// Validate that at least one field is being updated
if (Object.keys(updateData).length === 0) {
return res.status(400).json({ error: "At least one field must be provided for update" });
}
// Use queryHelper update with JSON-based where conditions
const updated = await update({
table: 'users',
data: updateData,
where: {
id,
deleted: false,
},
returning: '*',
});
if (updated.length === 0) {
return res.status(404).json({ error: "User not found" });
}
res.json(updated[0]);
} catch (err) {
console.error("Error updating user:", err);
if (err.code === "23505") {
// Unique constraint violation
return res.status(400).json({
error: err.detail || "A user with this phone number already exists",
});
}
res.status(500).json({ error: err.message || "Internal server error" });
}
});
// 5. DELETE User (Soft Delete)
router.delete("/:id", async (req, res) => {
try {
const { id } = req.params;
// Use queryHelper update with JSON-based where conditions for soft delete
const deleted = await update({
table: 'users',
data: {
deleted: true,
},
where: {
id,
deleted: false, // Only delete if not already deleted
},
returning: ['id'],
});
if (deleted.length === 0) {
return res.status(404).json({ error: "User not found or already deleted" });
}
res.json({ message: "User deleted successfully", id: deleted[0].id });
} catch (err) {
console.error("Error deleting user:", err);
res.status(500).json({ error: "Internal server error" });
}
});
export default router;