Files
SkyArtShop/backend/routes/users.js

332 lines
8.3 KiB
JavaScript
Raw Normal View History

const express = require("express");
const bcrypt = require("bcrypt");
const { query } = require("../config/database");
const { requireAuth, requireRole } = require("../middleware/auth");
const router = express.Router();
// Require admin role for all routes
router.use(requireAuth);
router.use(requireRole("role-admin"));
// Get all users with roles
router.get("/", async (req, res) => {
try {
const result = await query(`
SELECT
2025-12-14 01:54:40 -06:00
u.id, u.username, u.email, u.name, u.role, u.isactive,
u.last_login, u.createdat, u.passwordneverexpires
FROM adminusers u
ORDER BY u.createdat DESC
`);
res.json({
success: true,
users: result.rows,
});
} catch (error) {
console.error("Get users error:", error);
res.status(500).json({ success: false, message: "Server error" });
}
});
// Get all roles
router.get("/roles", async (req, res) => {
try {
const result = await query(`
SELECT id, name, description, permissions
FROM roles
ORDER BY name
`);
res.json({
success: true,
roles: result.rows,
});
} catch (error) {
console.error("Get roles error:", error);
res.status(500).json({ success: false, message: "Server error" });
}
});
// Create new user
router.post("/", async (req, res) => {
try {
const { username, email, password, role_id, password_never_expires } =
req.body;
// Validate required fields
if (!username || !email || !password || !role_id) {
return res.status(400).json({
success: false,
message: "Username, email, password, and role are required",
});
}
// Check if user already exists
const existing = await query("SELECT id FROM adminusers WHERE email = $1", [
email,
]);
if (existing.rows.length > 0) {
return res.status(400).json({
success: false,
message: "User with this email already exists",
});
}
// Hash password
const hashedPassword = await bcrypt.hash(password, 10);
// Calculate password expiry (90 days from now if not never expires)
let passwordExpiresAt = null;
if (!password_never_expires) {
const expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() + 90);
passwordExpiresAt = expiryDate.toISOString();
}
// Insert new user
const result = await query(
`
INSERT INTO adminusers (
id, username, email, passwordhash, role_id,
password_never_expires, password_expires_at,
isactive, created_by, createdat, last_password_change
) VALUES (
'user-' || gen_random_uuid()::text,
$1, $2, $3, $4, $5, $6, true, $7, NOW(), NOW()
)
RETURNING id, username, email, role_id, isactive, createdat
`,
[
username,
email,
hashedPassword,
role_id,
password_never_expires || false,
passwordExpiresAt,
req.session.user.email,
]
);
res.json({
success: true,
message: "User created successfully",
user: result.rows[0],
});
} catch (error) {
console.error("Create user error:", error);
res.status(500).json({ success: false, message: "Server error" });
}
});
// Update user
router.put("/:id", async (req, res) => {
try {
const { id } = req.params;
const { username, email, role_id, isactive, password_never_expires } =
req.body;
// Build update query dynamically
const updates = [];
const values = [];
let paramCount = 1;
if (username !== undefined) {
updates.push(`username = $${paramCount++}`);
values.push(username);
}
if (email !== undefined) {
updates.push(`email = $${paramCount++}`);
values.push(email);
}
if (role_id !== undefined) {
updates.push(`role_id = $${paramCount++}`);
values.push(role_id);
}
if (isactive !== undefined) {
updates.push(`isactive = $${paramCount++}`);
values.push(isactive);
}
if (password_never_expires !== undefined) {
updates.push(`password_never_expires = $${paramCount++}`);
values.push(password_never_expires);
// If setting to never expire, clear expiry date
if (password_never_expires) {
updates.push(`password_expires_at = NULL`);
}
}
updates.push(`updated_at = NOW()`);
values.push(id);
const result = await query(
`
UPDATE adminusers
SET ${updates.join(", ")}
WHERE id = $${paramCount}
RETURNING id, username, email, role_id, isactive, password_never_expires
`,
values
);
if (result.rows.length === 0) {
return res.status(404).json({
success: false,
message: "User not found",
});
}
res.json({
success: true,
message: "User updated successfully",
user: result.rows[0],
});
} catch (error) {
console.error("Update user error:", error);
res.status(500).json({ success: false, message: "Server error" });
}
});
// Reset user password
router.post("/:id/reset-password", async (req, res) => {
try {
const { id } = req.params;
const { new_password } = req.body;
if (!new_password || new_password.length < 6) {
return res.status(400).json({
success: false,
message: "Password must be at least 6 characters long",
});
}
// Hash new password
const hashedPassword = await bcrypt.hash(new_password, 10);
// Get user's password expiry setting
const userResult = await query(
"SELECT password_never_expires FROM adminusers WHERE id = $1",
[id]
);
if (userResult.rows.length === 0) {
return res.status(404).json({
success: false,
message: "User not found",
});
}
// Calculate new expiry date (90 days from now if not never expires)
let passwordExpiresAt = null;
if (!userResult.rows[0].password_never_expires) {
const expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() + 90);
passwordExpiresAt = expiryDate.toISOString();
}
// Update password
await query(
`
UPDATE adminusers
SET passwordhash = $1,
password_expires_at = $2,
last_password_change = NOW(),
updated_at = NOW()
WHERE id = $3
`,
[hashedPassword, passwordExpiresAt, id]
);
res.json({
success: true,
message: "Password reset successfully",
});
} catch (error) {
console.error("Reset password error:", error);
res.status(500).json({ success: false, message: "Server error" });
}
});
// Delete user
router.delete("/:id", async (req, res) => {
try {
const { id } = req.params;
// Prevent deleting yourself
if (id === req.session.user.id) {
return res.status(400).json({
success: false,
message: "Cannot delete your own account",
});
}
const result = await query(
"DELETE FROM adminusers WHERE id = $1 RETURNING id",
[id]
);
if (result.rows.length === 0) {
return res.status(404).json({
success: false,
message: "User not found",
});
}
res.json({
success: true,
message: "User deleted successfully",
});
} catch (error) {
console.error("Delete user error:", error);
res.status(500).json({ success: false, message: "Server error" });
}
});
// Toggle user active status
router.post("/:id/toggle-status", async (req, res) => {
try {
const { id } = req.params;
// Prevent deactivating yourself
if (id === req.session.user.id) {
return res.status(400).json({
success: false,
message: "Cannot deactivate your own account",
});
}
const result = await query(
`
UPDATE adminusers
SET isactive = NOT isactive,
updated_at = NOW()
WHERE id = $1
RETURNING id, isactive
`,
[id]
);
if (result.rows.length === 0) {
return res.status(404).json({
success: false,
message: "User not found",
});
}
res.json({
success: true,
message: `User ${
result.rows[0].isactive ? "activated" : "deactivated"
} successfully`,
isactive: result.rows[0].isactive,
});
} catch (error) {
console.error("Toggle status error:", error);
res.status(500).json({ success: false, message: "Server error" });
}
});
module.exports = router;