E-Commerce-Module/backend/src/routes/settingsAdmin.js

395 lines
No EOL
15 KiB
JavaScript

const express = require('express');
const fs = require('fs').promises;
const path = require('path');
const router = express.Router();
const SystemSettings = require('../models/SystemSettings');
const config = require('../config');
module.exports = (pool, query, authMiddleware) => {
// Apply authentication middleware to all routes
router.use(authMiddleware);
/**
* Get all settings
*/
router.get('/', async (req, res, next) => {
try {
if (!req.user.is_admin) {
return res.status(403).json({
error: true,
message: 'Admin access required'
});
}
const settings = await SystemSettings.getAllSettings(pool, query);
// Group settings by category
const groupedSettings = settings.reduce((acc, setting) => {
if (!acc[setting.category]) {
acc[setting.category] = [];
}
acc[setting.category].push(setting);
return acc;
}, {});
res.json(groupedSettings);
} catch (error) {
next(error);
}
});
/**
* Get settings by category
*/
router.get('/category/:category', async (req, res, next) => {
try {
const { category } = req.params;
if (!req.user.is_admin) {
return res.status(403).json({
error: true,
message: 'Admin access required'
});
}
const settings = await SystemSettings.getSettingsByCategory(pool, query, category);
res.json(settings);
} catch (error) {
next(error);
}
});
/**
* Get a specific setting
*/
router.get('/:key', async (req, res, next) => {
try {
const { key } = req.params;
if (!req.user.is_admin) {
return res.status(403).json({
error: true,
message: 'Admin access required'
});
}
const setting = await SystemSettings.getSetting(pool, query, key);
if (!setting) {
return res.status(404).json({
error: true,
message: `Setting with key "${key}" not found`
});
}
res.json(setting);
} catch (error) {
next(error);
}
});
/**
* Update a single setting
*/
router.put('/:key', async (req, res, next) => {
try {
const { key } = req.params;
const { value, category } = req.body;
if (!req.user.is_admin) {
return res.status(403).json({
error: true,
message: 'Admin access required'
});
}
if (value === undefined || !category) {
return res.status(400).json({
error: true,
message: 'Value and category are required'
});
}
const setting = await SystemSettings.getSetting(pool, query, key)
if(setting?.super_req && !req.user.is_super_admin){
return res.status(400).json({
error: true,
message: `Super Admin access required to modify ${key}`
});
}
const updatedSetting = await SystemSettings.updateSetting(pool, query, key, value, category);
// Update config in memory
updateConfigInMemory(updatedSetting);
// Update environment file
await updateEnvironmentFile();
res.json({
message: 'Setting updated successfully',
setting: updatedSetting
});
} catch (error) {
next(error);
}
});
/**
* Update multiple settings at once
*/
router.post('/batch', async (req, res, next) => {
try {
const { settings } = req.body;
console.log(req.user)
if (!req.user.is_admin) {
return res.status(403).json({
error: true,
message: 'Admin access required'
});
}
if (!Array.isArray(settings) || settings.length === 0) {
return res.status(400).json({
error: true,
message: 'Settings array is required'
});
}
const categorySettings = await SystemSettings.getSettingsByCategory(pool, query, settings[0]?.category)
// Validate all settings have required fields
for (const setting of settings) {
if (!setting.key || setting.value === undefined || !setting.category) {
return res.status(400).json({
error: true,
message: 'Each setting must have key, value, and category fields'
});
}
if(categorySettings.find(item => item.key === setting.key)?.super_req && !req.user.is_super_admin){
return res.status(400).json({
error: true,
message: `Super Admin access required to modify ${setting.key}`
});
}
}
const updatedSettings = await SystemSettings.updateSettings(pool, query, settings);
// Update config in memory for each setting
updatedSettings.forEach(setting => {
updateConfigInMemory(setting);
});
// Update environment file
await updateEnvironmentFile();
res.json({
message: 'Settings updated successfully',
settings: updatedSettings
});
} catch (error) {
next(error);
}
});
/**
* Delete a setting
*/
router.delete('/:key', async (req, res, next) => {
try {
const { key } = req.params;
if (!req.user.is_admin) {
return res.status(403).json({
error: true,
message: 'Admin access required'
});
}
await SystemSettings.deleteSetting(pool, query, key);
// Update environment file
await updateEnvironmentFile();
res.json({
message: `Setting "${key}" deleted successfully`
});
} catch (error) {
next(error);
}
});
/**
* Helper function to update config in memory
*/
function updateConfigInMemory(setting) {
const { key, value, category } = setting;
// Map database settings to config structure
if (category === 'server') {
if (key === 'port') config.port = parseInt(value, 10);
if (key === 'node_env') config.nodeEnv = value;
if (key === 'environment') config.environment = value;
} else if (category === 'database') {
if (key === 'db_host') config.db.host = value;
if (key === 'db_user') config.db.user = value;
if (key === 'site_read_host') config.db.readHost = value;
if (key === 'db_password') config.db.password = value;
if (key === 'db_name') config.db.database = value;
if (key === 'db_port') config.db.port = parseInt(value, 10);
if (key === 'site_db_max_connections') config.db.maxConnections = parseInt(value, 10);
} else if (category === 'email') {
if (key === 'smtp_host') config.email.host = value;
if (key === 'smtp_port') config.email.port = parseInt(value, 10);
if (key === 'smtp_user') config.email.user = value;
if (key === 'smtp_password') config.email.pass = value;
if (key === 'smtp_from_email') config.email.reply = value;
} else if (category === 'payment') {
if (key === 'stripe_enabled') config.payment.stripeEnabled = value === 'true';
if (key === 'stripe_public_key') config.payment.stripePublicKey = value;
if (key === 'stripe_secret_key') config.payment.stripeSecretKey = value;
if (key === 'stripe_webhook_secret') config.payment.stripeWebhookSecret = value;
} else if (category === 'shipping') {
if (key === 'shipping_enabled') config.shipping.enabled = value === 'true';
if (key === 'easypost_enabled') config.shipping.easypostEnabled = value === 'true';
if (key === 'easypost_api_key') config.shipping.easypostApiKey = value;
if (key === 'shipping_flat_rate') config.shipping.flatRate = parseFloat(value);
if (key === 'shipping_free_threshold') config.shipping.freeThreshold = parseFloat(value);
if (key === 'shipping_origin_street') config.shipping.originAddress.street = value;
if (key === 'shipping_origin_city') config.shipping.originAddress.city = value;
if (key === 'shipping_origin_state') config.shipping.originAddress.state = value;
if (key === 'shipping_origin_zip') config.shipping.originAddress.zip = value;
if (key === 'shipping_origin_country') config.shipping.originAddress.country = value;
if (key === 'shipping_default_package_length') config.shipping.defaultPackage.length = parseFloat(value);
if (key === 'shipping_default_package_width') config.shipping.defaultPackage.width = parseFloat(value);
if (key === 'shipping_default_package_height') config.shipping.defaultPackage.height = parseFloat(value);
if (key === 'shipping_default_package_unit') config.shipping.defaultPackage.unit = value;
if (key === 'shipping_default_weight_unit') config.shipping.defaultPackage.weightUnit = value;
if (key === 'shipping_carriers_allowed') config.shipping.carriersAllowed = value.split(',');
} else if (category === 'site') {
if (key === 'site_domain') config.site.domain = value;
if (key === 'site_api_domain') config.site.apiDomain = value;
if (key === 'site_analytics_api_key') config.site.analyticApiKey = value;
if (key === 'site_environment') config.environment = value;
if (key === 'site_deployment') config.site.deployment = value;
if (key === 'site_redis_host') config.site.redisHost = value;
if (key === 'site_redis_tls') config.site.redisTLS = value;
if (key === 'site_aws_region') config.site.awsRegion = value;
if (key === 'site_aws_s3_bucket') config.site.awsS3Bucket = value;
if (key === 'site_cdn_domain') config.site.cdnDomain = value;
if (key === 'site_aws_queue_url') config.site.awsQueueUrl = value;
if (key === 'site_session_secret') config.site.sessionSecret = value;
if (key === 'site_redis_port') config.site.redisPort = value;
if (key === 'site_redis_password') config.site.redisPassword = value;
}
}
/**
* Helper function to update environment file
*/
async function updateEnvironmentFile() {
try {
// Get all settings from database
const allSettings = await SystemSettings.getAllSettings(pool, query);
// First update the config with the database settings
config.updateFromDatabase(allSettings);
// Build environment variables string
let envContent = '';
// Server configuration
envContent += '# Server configuration\n';
envContent += `PORT=${config.port}\n`;
envContent += `NODE_ENV=${config.nodeEnv}\n`;
envContent += `ENVIRONMENT=${config.environment}\n`;
envContent += `DEPLOYMENT_MODE=${config.site.deployment}\n`;
envContent += `REDIS_HOST=${config.site.redisHost}\n`;
envContent += `REDIS_TLS=${config.site.redisTLS}\n`;
envContent += `REDIS_PORT=${config.site.redisPort}\n`;
envContent += `REDIS_PASSWORD=${config.site.redisPassword}\n`;
envContent += `AWS_REGION=${config.site.awsRegion}\n`;
envContent += `S3_BUCKET=${config.site.awsS3Bucket}\n`;
envContent += `CDN_DOMAIN=${config.site.cdnDomain}\n`;
envContent += `SQS_QUEUE_URL=${config.site.awsQueueUrl}\n`;
envContent += `SESSION_SECRET=${config.site.sessionSecret}\n\n`;
// Database configuration
envContent += '# Database configuration\n';
envContent += `DB_HOST=${config.db.host}\n`;
envContent += `DB_READ_HOST=${config.db.readHost}\n`;
envContent += `DB_USER=${config.db.user}\n`;
envContent += `DB_PASSWORD=${config.db.password}\n`;
envContent += `DB_NAME=${config.db.database}\n`;
envContent += `DB_PORT=${config.db.port}\n`;
envContent += `DB_MAX_CONNECTIONS=${config.db.maxConnections}\n`;
envContent += `POSTGRES_USER=${config.db.user}\n`;
envContent += `POSTGRES_PASSWORD=${config.db.password}\n`;
envContent += `POSTGRES_DB=${config.db.database}\n\n`;
// Email configuration
envContent += '# Email configuration\n';
envContent += `EMAIL_HOST=${config.email.host}\n`;
envContent += `EMAIL_PORT=${config.email.port}\n`;
envContent += `EMAIL_USER=${config.email.user}\n`;
envContent += `EMAIL_PASS=${config.email.pass}\n`;
envContent += `EMAIL_REPLY=${config.email.reply}\n\n`;
// Payment configuration
envContent += '# Payment configuration\n';
envContent += `STRIPE_ENABLED=${config.payment.stripeEnabled}\n`;
envContent += `STRIPE_PUBLIC_KEY=${config.payment.stripePublicKey}\n`;
envContent += `STRIPE_SECRET_KEY=${config.payment.stripeSecretKey}\n`;
envContent += `STRIPE_WEBHOOK_SECRET=${config.payment.stripeWebhookSecret}\n\n`;
// Shipping configuration
envContent += '# Shipping configuration\n';
envContent += `SHIPPING_ENABLED=${config.shipping.enabled}\n`;
envContent += `EASYPOST_ENABLED=${config.shipping.easypostEnabled}\n`;
envContent += `EASYPOST_API_KEY=${config.shipping.easypostApiKey}\n`;
envContent += `SHIPPING_FLAT_RATE=${config.shipping.flatRate}\n`;
envContent += `SHIPPING_FREE_THRESHOLD=${config.shipping.freeThreshold}\n`;
envContent += `SHIPPING_ORIGIN_STREET=${config.shipping.originAddress.street}\n`;
envContent += `SHIPPING_ORIGIN_CITY=${config.shipping.originAddress.city}\n`;
envContent += `SHIPPING_ORIGIN_STATE=${config.shipping.originAddress.state}\n`;
envContent += `SHIPPING_ORIGIN_ZIP=${config.shipping.originAddress.zip}\n`;
envContent += `SHIPPING_ORIGIN_COUNTRY=${config.shipping.originAddress.country}\n`;
envContent += `SHIPPING_DEFAULT_PACKAGE_LENGTH=${config.shipping.defaultPackage.length}\n`;
envContent += `SHIPPING_DEFAULT_PACKAGE_WIDTH=${config.shipping.defaultPackage.width}\n`;
envContent += `SHIPPING_DEFAULT_PACKAGE_HEIGHT=${config.shipping.defaultPackage.height}\n`;
envContent += `SHIPPING_DEFAULT_PACKAGE_UNIT=${config.shipping.defaultPackage.unit}\n`;
envContent += `SHIPPING_DEFAULT_WEIGHT_UNIT=${config.shipping.defaultPackage.weightUnit}\n`;
envContent += `SHIPPING_CARRIERS_ALLOWED=${config.shipping.carriersAllowed.join(',')}\n\n`;
// Site configuration
envContent += '# Site configuration\n';
if (config.environment === 'prod') {
// For production, use the actual domain values
envContent += `APP_PROD_URL=${config.site.domain}\n`;
envContent += `API_PROD_URL=${config.site.apiDomain}\n`;
} else {
// For beta/development, still include these but they won't be used
envContent += `APP_PROD_URL=${config.site.domain === 'localhost:3000' ? '' : config.site.domain}\n`;
envContent += `API_PROD_URL=${config.site.apiDomain === 'localhost:4000' ? '' : config.site.apiDomain}\n`;
}
envContent += `SITE_ANALYTIC_API=${config.site.analyticApiKey}\n`;
// Write to .env file
const envPath = path.join(__dirname, '../../.env');
await fs.writeFile(envPath, envContent);
console.log('Environment file updated successfully');
return true;
} catch (error) {
console.error('Error updating environment file:', error);
throw error;
}
}
return router;
};