init
This commit is contained in:
188
server.js
188
server.js
@@ -5,108 +5,154 @@ const session = require('express-session');
|
||||
const cors = require('cors');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
let usersConfig = { users: [] };
|
||||
try {
|
||||
usersConfig = JSON.parse(fs.readFileSync(path.join(__dirname, 'users.json'), 'utf8'));
|
||||
} catch (err) {
|
||||
console.warn('⚠️ users.json not found or invalid JSON. Falling back to env-based admin only.');
|
||||
}
|
||||
|
||||
const rolePermissions = {
|
||||
superadmin: { folders: null, canCreate: true, canEdit: true, canDelete: true },
|
||||
frontend_admin: { folders: ['frontend'], canCreate: true, canEdit: true, canDelete: true },
|
||||
backend_admin: { folders: ['backend'], canCreate: true, canEdit: true, canDelete: true },
|
||||
frontend_moder: { folders: ['frontend'], canCreate: true, canEdit: true, canDelete: false },
|
||||
backend_moder: { folders: ['backend'], canCreate: true, canEdit: true, canDelete: false },
|
||||
viewer: { folders: null, canCreate: false, canEdit: false, canDelete: false },
|
||||
};
|
||||
|
||||
function getUser(username) {
|
||||
return usersConfig.users.find(u => u.username === username);
|
||||
}
|
||||
|
||||
function getTableFolder(tableName) {
|
||||
if (!tableName) return 'default';
|
||||
const parts = tableName.split('__');
|
||||
return parts.length > 1 ? parts[0] : 'default';
|
||||
}
|
||||
|
||||
function getRolePermissions(role) {
|
||||
return rolePermissions[role] || rolePermissions.viewer;
|
||||
}
|
||||
|
||||
function canAccessTable(role, tableName) {
|
||||
const perms = getRolePermissions(role);
|
||||
if (!perms.folders) return true;
|
||||
const folder = getTableFolder(tableName);
|
||||
return perms.folders.includes(folder);
|
||||
}
|
||||
|
||||
// Initialize Express app
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
||||
// Middleware
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
app.use(express.static('.'));
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
// Session configuration
|
||||
app.use(session({
|
||||
secret: process.env.SESSION_SECRET || 'default-secret-change-this',
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
cookie: { secure: false } // Set to true if using HTTPS
|
||||
cookie: {
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
httpOnly: true,
|
||||
maxAge: 1000 * 60 * 60 * 24 * 7 // 7 days
|
||||
}
|
||||
}));
|
||||
|
||||
// Database connection pool (uses .env configuration)
|
||||
// Database connection pool
|
||||
const pool = new Pool({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT,
|
||||
database: process.env.DB_NAME,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
port: process.env.DB_PORT || 5432,
|
||||
database: process.env.DB_NAME || 'postgres',
|
||||
user: process.env.DB_USER || 'postgres',
|
||||
password: process.env.DB_PASSWORD || 'postgres',
|
||||
});
|
||||
|
||||
// Test database connection on startup
|
||||
// Test database connection
|
||||
pool.connect((err, client, release) => {
|
||||
if (err) {
|
||||
console.error('❌ Error connecting to PostgreSQL:', err.message);
|
||||
console.log('Проверьте настройки в .env файле');
|
||||
} else {
|
||||
console.log('✅ Connected to PostgreSQL database');
|
||||
console.log(` Host: ${process.env.DB_HOST}:${process.env.DB_PORT}`);
|
||||
console.log(` Database: ${process.env.DB_NAME}`);
|
||||
console.log(` Host: ${process.env.DB_HOST || 'localhost'}:${process.env.DB_PORT || 5432}`);
|
||||
console.log(` Database: ${process.env.DB_NAME || 'postgres'}`);
|
||||
release();
|
||||
}
|
||||
});
|
||||
|
||||
// Helper: get primary key column for a table (returns null if none)
|
||||
async function getPrimaryKeyColumn(tableName) {
|
||||
const result = await pool.query(`
|
||||
SELECT kcu.column_name
|
||||
FROM information_schema.table_constraints tc
|
||||
JOIN information_schema.key_column_usage kcu
|
||||
ON tc.constraint_name = kcu.constraint_name
|
||||
AND tc.table_schema = kcu.table_schema
|
||||
WHERE tc.constraint_type = 'PRIMARY KEY'
|
||||
AND tc.table_name = $1
|
||||
AND tc.table_schema = 'public'
|
||||
LIMIT 1
|
||||
`, [tableName]);
|
||||
// Initialize database schema
|
||||
async function initializeDatabase() {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
// Check if users table exists, if not create it
|
||||
await client.query(`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255) UNIQUE NOT NULL,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
role VARCHAR(50) NOT NULL DEFAULT 'viewer',
|
||||
active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
return result.rows[0]?.column_name || null;
|
||||
CREATE TABLE IF NOT EXISTS activity_logs (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||
action VARCHAR(255),
|
||||
details JSONB,
|
||||
created_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_activity_logs_user_id ON activity_logs(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_activity_logs_created_at ON activity_logs(created_at);
|
||||
`);
|
||||
|
||||
// Create default admin user if doesn't exist
|
||||
const adminExists = await client.query(
|
||||
'SELECT id FROM users WHERE email = $1',
|
||||
['admin@example.com']
|
||||
);
|
||||
|
||||
if (adminExists.rows.length === 0) {
|
||||
const hashedPassword = await bcrypt.hash('admin123', 10);
|
||||
await client.query(
|
||||
`INSERT INTO users (name, email, password, role, active)
|
||||
VALUES ($1, $2, $3, $4, $5)`,
|
||||
['Admin', 'admin@example.com', hashedPassword, 'superadmin', true]
|
||||
);
|
||||
console.log('✅ Created default admin user: admin@example.com / admin123');
|
||||
}
|
||||
|
||||
console.log('✅ Database schema initialized');
|
||||
} catch (error) {
|
||||
console.error('Database initialization error:', error);
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
// Middleware to check if user is authenticated
|
||||
const requireAuth = (req, res, next) => {
|
||||
if (req.session && req.session.authenticated) {
|
||||
next();
|
||||
} else {
|
||||
res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
};
|
||||
// Initialize on startup
|
||||
initializeDatabase();
|
||||
|
||||
// Login endpoint - checks users.json (fallback to .env admin)
|
||||
// Routes
|
||||
const authRoutes = require('./src/routes/auth');
|
||||
const userRoutes = require('./src/routes/users');
|
||||
const dbRoutes = require('./src/routes/db-tables');
|
||||
const adminRoutes = require('./src/routes/admin');
|
||||
|
||||
// API Routes
|
||||
app.use('/api/auth', authRoutes(pool));
|
||||
app.use('/api/users', userRoutes(pool));
|
||||
app.use('/api/db', dbRoutes(pool));
|
||||
app.use('/api/admin', adminRoutes(pool));
|
||||
|
||||
// SPA catch-all route
|
||||
app.get('*', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
||||
});
|
||||
|
||||
// Error handling middleware
|
||||
app.use((err, req, res, next) => {
|
||||
console.error('Error:', err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Internal server error',
|
||||
error: process.env.NODE_ENV === 'development' ? err.message : undefined
|
||||
});
|
||||
});
|
||||
|
||||
// Start server
|
||||
app.listen(PORT, () => {
|
||||
console.log(`\n🚀 PostgreSQL Admin Panel running at http://localhost:${PORT}`);
|
||||
console.log(`📦 Environment: ${process.env.NODE_ENV || 'development'}`);
|
||||
console.log(`\n💾 Database Connection:`);
|
||||
console.log(` Host: ${process.env.DB_HOST || 'localhost'}`);
|
||||
console.log(` Database: ${process.env.DB_NAME || 'postgres'}`);
|
||||
console.log('\n');
|
||||
});
|
||||
|
||||
// Graceful shutdown
|
||||
process.on('SIGTERM', () => {
|
||||
console.log('SIGTERM received. Shutting down gracefully...');
|
||||
pool.end(() => {
|
||||
console.log('Connection pool closed');
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = app;
|
||||
app.post('/api/login', async (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user