admin stuff

This commit is contained in:
Jake Kasper
2025-08-29 08:59:10 -04:00
parent 0cc5372e3d
commit 8c728d42d4
6 changed files with 485 additions and 14 deletions

View File

@@ -226,6 +226,84 @@ router.put('/users/:id/role', validateParams(idParamSchema), async (req, res, ne
}
});
// @route PUT /api/admin/users/:id
// @desc Update user details
// @access Private (Admin)
router.put('/users/:id', validateParams(idParamSchema), async (req, res, next) => {
try {
const userId = req.params.id;
const { firstName, lastName, email, role, password } = req.body;
// Validate required fields
if (!firstName || !lastName || !email || !role) {
throw new AppError('First name, last name, email, and role are required', 400);
}
if (!['admin', 'user'].includes(role)) {
throw new AppError('Invalid role', 400);
}
// Prevent removing admin role from yourself
if (parseInt(userId) === req.user.id && role !== 'admin') {
throw new AppError('Cannot remove admin role from yourself', 400);
}
// Check if user exists
const userCheck = await pool.query(
'SELECT id, role FROM users WHERE id = $1',
[userId]
);
if (userCheck.rows.length === 0) {
throw new AppError('User not found', 404);
}
// Check if email is already taken by another user
const emailCheck = await pool.query(
'SELECT id FROM users WHERE email = $1 AND id != $2',
[email, userId]
);
if (emailCheck.rows.length > 0) {
throw new AppError('Email already exists', 400);
}
let updateQuery = 'UPDATE users SET first_name = $1, last_name = $2, email = $3, role = $4, updated_at = CURRENT_TIMESTAMP';
let queryParams = [firstName, lastName, email, role];
// If password is provided, hash it and include in update
if (password) {
const bcrypt = require('bcrypt');
const saltRounds = 10;
const hashedPassword = await bcrypt.hash(password, saltRounds);
updateQuery += ', password_hash = $5';
queryParams.push(hashedPassword);
}
updateQuery += ' WHERE id = $' + (queryParams.length + 1) + ' RETURNING id, email, first_name, last_name, role';
queryParams.push(userId);
const result = await pool.query(updateQuery, queryParams);
const user = result.rows[0];
res.json({
success: true,
message: 'User updated successfully',
data: {
user: {
id: user.id,
email: user.email,
firstName: user.first_name,
lastName: user.last_name,
role: user.role
}
}
});
} catch (error) {
next(error);
}
});
// @route DELETE /api/admin/users/:id
// @desc Delete user account
// @access Private (Admin)
@@ -967,4 +1045,79 @@ router.delete('/products/user/spreader-settings/:id', validateParams(idParamSche
}
});
// @route GET /api/admin/settings
// @desc Get admin settings
// @access Private (Admin)
router.get('/settings', async (req, res, next) => {
try {
// For now, we'll store settings in the database. Let's create a simple settings table approach
// First check if settings table exists, if not create it
await pool.query(`
CREATE TABLE IF NOT EXISTS admin_settings (
id SERIAL PRIMARY KEY,
setting_key VARCHAR(255) UNIQUE NOT NULL,
setting_value TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
// Insert default registration setting if it doesn't exist
await pool.query(`
INSERT INTO admin_settings (setting_key, setting_value)
VALUES ('registrationEnabled', 'true')
ON CONFLICT (setting_key) DO NOTHING
`);
// Get all settings
const settingsResult = await pool.query('SELECT setting_key, setting_value FROM admin_settings');
const settings = {};
settingsResult.rows.forEach(row => {
// Convert string values to appropriate types
if (row.setting_value === 'true' || row.setting_value === 'false') {
settings[row.setting_key] = row.setting_value === 'true';
} else {
settings[row.setting_key] = row.setting_value;
}
});
res.json({
success: true,
data: settings
});
} catch (error) {
next(error);
}
});
// @route PUT /api/admin/settings
// @desc Update admin settings
// @access Private (Admin)
router.put('/settings', async (req, res, next) => {
try {
const updates = req.body;
// Update each setting
for (const [key, value] of Object.entries(updates)) {
const stringValue = typeof value === 'boolean' ? value.toString() : value;
await pool.query(`
INSERT INTO admin_settings (setting_key, setting_value, updated_at)
VALUES ($1, $2, CURRENT_TIMESTAMP)
ON CONFLICT (setting_key)
DO UPDATE SET setting_value = $2, updated_at = CURRENT_TIMESTAMP
`, [key, stringValue]);
}
res.json({
success: true,
message: 'Settings updated successfully',
data: updates
});
} catch (error) {
next(error);
}
});
module.exports = router;

View File

@@ -333,4 +333,46 @@ router.get('/me', authenticateToken, async (req, res, next) => {
}
});
// @route GET /api/auth/registration-status
// @desc Get registration status (public endpoint)
// @access Public
router.get('/registration-status', async (req, res, next) => {
try {
// Create admin_settings table if it doesn't exist
await pool.query(`
CREATE TABLE IF NOT EXISTS admin_settings (
id SERIAL PRIMARY KEY,
setting_key VARCHAR(255) UNIQUE NOT NULL,
setting_value TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
// Insert default registration setting if it doesn't exist
await pool.query(`
INSERT INTO admin_settings (setting_key, setting_value)
VALUES ('registrationEnabled', 'true')
ON CONFLICT (setting_key) DO NOTHING
`);
// Get registration setting
const settingResult = await pool.query(
'SELECT setting_value FROM admin_settings WHERE setting_key = $1',
['registrationEnabled']
);
const enabled = settingResult.rows.length > 0 ? settingResult.rows[0].setting_value === 'true' : true;
res.json({
success: true,
data: {
enabled
}
});
} catch (error) {
next(error);
}
});
module.exports = router;