first commit

This commit is contained in:
Gunaseelan P
2026-07-13 17:59:12 +05:30
commit f07c46a9a6
19 changed files with 7345 additions and 0 deletions
+410
View File
@@ -0,0 +1,410 @@
const express = require('express');
const { Pool } = require('pg');
const cors = require('cors');
const path = require('path');
require('dotenv').config();
const app = express();
const port = process.env.PORT || 3001;
app.use(cors());
app.use(express.json({ limit: '10mb' })); // support large payloads for base64 background images
// Database connection configuration
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false // Required for Neon Postgres
}
});
// Default regions data
const DEFAULT_REGIONS = [
{
id: "assam",
name: "Assam",
address: "INDUSTRIES GROWTH CENTRE, MATIA (MORNAI)\nOPPOSITE TO SAINIK SCHOOL, GOALPARA, ASSAM - 783 101.",
phone: "",
},
{
id: "bhiwandi",
name: "Bhiwandi Plant",
address: "S.NO. 31/B / 32 A, DHAMANGAON OLD AGRA ROAD,\nTAL. - BHIWANDI, DISTT. - THANE, MUMBAI, MAHARASHTRA - 421 302.",
phone: "",
},
{
id: "erode",
name: "Erode",
address: "SF NO. 532, BHAVANI TO ANTHIYUR MAIN ROAD, MYLAMPADI,\nKANNADIPALAYAM POST, BHAVANI TK, ERODE DT - 638 314.",
phone: "04256 - 238 202 / 302 / 402",
},
{
id: "haridwar",
name: "Haridwar",
address: "PLOT NO.16 & 17,SECTOR-4, INTEGRATED INDUSTRIAL ESTATE,\nSIDCUL,RANIPUR, HARIDWAR-249403",
phone: "01334-239246",
},
{
id: "kanchipuram",
name: "Kanchipuram",
address: "NO. 18, ARYAPERUMBAKKAM VILLAGE, KANCHIPURAM - 631 502.",
phone: "2729 4580/81",
},
{
id: "pondy",
name: "Pondy",
address: "R.S. NO. 81/4, KORKADU VILLAGE, NETTAPAKKAM COMMUNE,\nPONDICHERRY -605 110.",
phone: "0413 - 2665146",
},
{
id: "ro-east",
name: "RO East",
address: "14TH FLOOR, P.S. SRIJAN TECH PARK, DN - 52, DN BLOCK, SECTOR - 5,\nSALT LAKE CITY, KOLKATA - 700091",
phone: "033 - 40669540",
},
{
id: "ro-north",
name: "RO North",
address: "D-12/ 2ND FLOOR, KAUSHAMBI, GHAZIABAD - 201010\nUTTAR PRADESH",
phone: "0120-4335396",
},
{
id: "ro-south",
name: "RO South",
address: "NO. 12, POONAMALLEE ROAD, EKKATTUTHANGAL,\nCHENNAI - 6OO 032.",
phone: "044 - 2225 1011 / 12",
},
{
id: "ro-west",
name: "RO West",
address: "504-A, RAHEJA PLAZA PREMISES CO-OP SOCIETY LTD.,\nL.B.S. MARG, GHATKOPAR (WEST), MUMBAI – 400086",
phone: "",
},
];
// Initialize Database Tables
async function initDb() {
let client;
try {
console.log("Connecting to Neon PostgreSQL database...");
client = await pool.connect();
console.log("Initializing database tables...");
await client.query("BEGIN");
// 1. App Users Table
await client.query(`
CREATE TABLE IF NOT EXISTS app_users (
username VARCHAR(255) PRIMARY KEY,
password VARCHAR(255) NOT NULL,
role VARCHAR(50) NOT NULL
)
`);
// 2. Regions Table
await client.query(`
CREATE TABLE IF NOT EXISTS regions (
id VARCHAR(255) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
address TEXT NOT NULL,
phone VARCHAR(255)
)
`);
// 3. Stats Table
await client.query(`
CREATE TABLE IF NOT EXISTS stats (
unit_id VARCHAR(255) PRIMARY KEY,
count INT NOT NULL DEFAULT 0
)
`);
// 4. Settings Table
await client.query(`
CREATE TABLE IF NOT EXISTS settings (
key VARCHAR(255) PRIMARY KEY,
value TEXT NOT NULL
)
`);
// Seed default users if empty
const usersCountRes = await client.query("SELECT COUNT(*) FROM app_users");
if (parseInt(usersCountRes.rows[0].count) === 0) {
console.log("Seeding default users...");
await client.query(`
INSERT INTO app_users (username, password, role) VALUES
('user', 'user', 'user'),
('admin', 'admin', 'admin')
`);
}
// Seed default regions if empty
const regionsCountRes = await client.query("SELECT COUNT(*) FROM regions");
if (parseInt(regionsCountRes.rows[0].count) === 0) {
console.log("Seeding default regions...");
for (const region of DEFAULT_REGIONS) {
await client.query(
"INSERT INTO regions (id, name, address, phone) VALUES ($1, $2, $3, $4)",
[region.id, region.name, region.address, region.phone]
);
}
}
await client.query("COMMIT");
console.log("Database initialized successfully.");
} catch (err) {
if (client) {
try {
await client.query("ROLLBACK");
} catch (rollbackErr) {
console.error("Rollback failed:", rollbackErr);
}
}
console.error("Error initializing database:", err);
} finally {
if (client) client.release();
}
}
// REST API Endpoints
// Authentication API
app.post('/api/auth/login', async (req, res) => {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json({ error: "Username and password are required" });
}
try {
const result = await pool.query(
"SELECT role FROM app_users WHERE username = $1 AND password = $2",
[username, password]
);
if (result.rows.length > 0) {
res.json({ success: true, role: result.rows[0].role });
} else {
res.status(401).json({ error: "Invalid username or password" });
}
} catch (err) {
console.error(err);
res.status(500).json({ error: "Database error during authentication" });
}
});
app.post('/api/auth/reset', async (req, res) => {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json({ error: "Username and password are required" });
}
try {
const result = await pool.query(
"UPDATE app_users SET password = $2 WHERE username = $1 RETURNING role",
[username, password]
);
if (result.rows.length > 0) {
res.json({ success: true });
} else {
res.status(404).json({ error: "Username not found" });
}
} catch (err) {
console.error(err);
res.status(500).json({ error: "Database error during password reset" });
}
});
// Users Management APIs
app.get('/api/users', async (req, res) => {
try {
const result = await pool.query("SELECT username, role, password FROM app_users");
const usersMap = {};
result.rows.forEach(row => {
usersMap[row.username] = { password: row.password, role: row.role };
});
res.json(usersMap);
} catch (err) {
console.error(err);
res.status(500).json({ error: "Failed to fetch users" });
}
});
app.post('/api/users', async (req, res) => {
const { username, password, role } = req.body;
if (!username || !password || !role) {
return res.status(400).json({ error: "Missing fields" });
}
try {
await pool.query(
"INSERT INTO app_users (username, password, role) VALUES ($1, $2, $3)",
[username, password, role]
);
res.json({ success: true });
} catch (err) {
console.error(err);
if (err.code === '23505') {
res.status(400).json({ error: "Username already exists" });
} else {
res.status(500).json({ error: "Failed to create user" });
}
}
});
app.put('/api/users/:username', async (req, res) => {
const { username } = req.params;
const { password, role } = req.body;
if (!password || !role) {
return res.status(400).json({ error: "Missing fields" });
}
try {
const result = await pool.query(
"UPDATE app_users SET password = $1, role = $2 WHERE username = $3",
[password, role, username]
);
if (result.rowCount > 0) {
res.json({ success: true });
} else {
res.status(404).json({ error: "User not found" });
}
} catch (err) {
console.error(err);
res.status(500).json({ error: "Failed to update user" });
}
});
app.delete('/api/users/:username', async (req, res) => {
const { username } = req.params;
try {
const result = await pool.query("DELETE FROM app_users WHERE username = $1", [username]);
if (result.rowCount > 0) {
res.json({ success: true });
} else {
res.status(404).json({ error: "User not found" });
}
} catch (err) {
console.error(err);
res.status(500).json({ error: "Failed to delete user" });
}
});
// Regions Management APIs
app.get('/api/regions', async (req, res) => {
try {
const result = await pool.query("SELECT id, name, address, phone FROM regions ORDER BY name ASC");
res.json(result.rows);
} catch (err) {
console.error(err);
res.status(500).json({ error: "Failed to fetch regions" });
}
});
app.post('/api/regions', async (req, res) => {
const regions = req.body;
if (!Array.isArray(regions)) {
return res.status(400).json({ error: "Invalid payload, expected array" });
}
const client = await pool.connect();
try {
await client.query("BEGIN");
await client.query("DELETE FROM regions");
for (const region of regions) {
await client.query(
"INSERT INTO regions (id, name, address, phone) VALUES ($1, $2, $3, $4)",
[region.id, region.name, region.address, region.phone || '']
);
}
await client.query("COMMIT");
res.json({ success: true });
} catch (err) {
await client.query("ROLLBACK");
console.error(err);
res.status(500).json({ error: "Failed to save regions" });
} finally {
client.release();
}
});
// Stats Logging APIs
app.get('/api/stats', async (req, res) => {
try {
const result = await pool.query("SELECT unit_id, count FROM stats");
const statsMap = {};
result.rows.forEach(row => {
statsMap[row.unit_id] = row.count;
});
res.json(statsMap);
} catch (err) {
console.error(err);
res.status(500).json({ error: "Failed to fetch stats" });
}
});
app.post('/api/stats', async (req, res) => {
const { unitId, count } = req.body;
if (!unitId || count === undefined) {
return res.status(400).json({ error: "Missing unitId or count" });
}
try {
await pool.query(
`INSERT INTO stats (unit_id, count) VALUES ($1, $2)
ON CONFLICT (unit_id) DO UPDATE SET count = stats.count + $2`,
[unitId, count]
);
res.json({ success: true });
} catch (err) {
console.error(err);
res.status(500).json({ error: "Failed to log stats" });
}
});
// Settings APIs
app.get('/api/settings/:key', async (req, res) => {
const { key } = req.params;
try {
const result = await pool.query("SELECT value FROM settings WHERE key = $1", [key]);
if (result.rows.length > 0) {
res.json({ value: result.rows[0].value });
} else {
res.json({ value: null });
}
} catch (err) {
console.error(err);
res.status(500).json({ error: "Failed to fetch settings" });
}
});
app.post('/api/settings', async (req, res) => {
const { key, value } = req.body;
if (!key || value === undefined) {
return res.status(400).json({ error: "Missing key or value" });
}
try {
await pool.query(
`INSERT INTO settings (key, value) VALUES ($1, $2)
ON CONFLICT (key) DO UPDATE SET value = $2`,
[key, value]
);
res.json({ success: true });
} catch (err) {
console.error(err);
res.status(500).json({ error: "Failed to update settings" });
}
});
// Serve Static Files in Production
app.use(express.static(path.join(__dirname, 'dist')));
// Fallback for Single Page Application routing (Vite React app)
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});
// Start Server and Init Database
app.listen(port, async () => {
console.log(`Server is running on port ${port}`);
await initDb();
});