ArgusSite/server.js
2023-08-01 16:05:54 +03:00

978 lines
25 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require("express");
const app = express();
const path = require("path");
const { Pool } = require("pg");
const fs = require("fs");
const handlebars = require("handlebars");
require("dotenv").config();
const multer = require("multer");
const http = require("http");
// Для сохранения загруженных фотографий
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads"); // Папка для сохранения фотографий
},
filename: function (req, file, cb) {
cb(null, Date.now() + "-" + file.originalname);
},
});
const upload = multer({ storage: storage });
app.use(express.static(path.join(__dirname, "static")));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.get("/", index);
app.get("/login", login);
app.get("/register", register);
app.get("/live", live);
app.get("/reports", reports);
app.get("/reports/346", reports346);
app.get("/devices", devices);
app.get("/devices/drivers", drivers);
app.get("/devices/update", update);
const DB_User = process.env.DB_USER;
const DB_Password = process.env.DB_PASSWORD;
const DB_Host = process.env.DB_HOST;
const DB_Port = process.env.DB_PORT;
const DB_Name = process.env.DB_NAME;
// const DB_User = "postgres";
// const DB_Password = "password";
// const DB_Host = "postgres";
// const DB_Port = "5432";
// const DB_Name = "postgres";
async function index(req, res) {
var templateData = {
Organisation: "Название организации",
User: "Тестовое Имя",
ifDBError: false,
Count: "",
};
try {
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
const client = await pool.connect();
// Выполняем запрос и получаем результат
const query = `
SELECT COUNT(*) AS count
FROM registrars
`;
const registrars = await client.query(query);
templateData.Count = registrars.rows[0].count;
console.log(templateData);
const source = fs.readFileSync("static/templates/index.html", "utf8");
const template = handlebars.compile(source);
const resultT = template(templateData);
res.send(resultT);
} catch (error) {
console.error(error);
templateData.ifDBError = true;
const source = fs.readFileSync("static/templates/index.html", "utf8");
const template = handlebars.compile(source);
const resultT = template(templateData);
res.send(resultT);
}
// res.sendFile(path.join(__dirname, "static/templates/index.html"));
}
function login(req, res) {
res.sendFile(path.join(__dirname, "static/templates/login.html"));
}
function register(req, res) {
res.sendFile(path.join(__dirname, "static/templates/register.html"));
}
async function live(req, res) {
let templateData = {
Organisation: "Название организации",
User: "Тестовое Имя",
ifDBError: false,
Registrars: [],
};
try {
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
const client = await pool.connect();
const minuteInMillis = 60 * 1000;
const query = `
SELECT id, serial, lastkeepalive FROM registrars ORDER BY id ASC
`;
const registrars = await client.query(query);
templateData.Registrars = registrars.rows.map((row) => ({
id: row.id,
serial: row.serial,
status: Date.now() - Date.parse(row.lastkeepalive) <= minuteInMillis,
}));
console.log(templateData);
const source = fs.readFileSync("static/templates/live.html", "utf8");
const template = handlebars.compile(source);
const resultHTML = template(templateData);
res.send(resultHTML);
client.release();
} catch (error) {
console.error(error);
templateData.ifDBError = true;
const source = fs.readFileSync("static/templates/live.html", "utf8");
const template = handlebars.compile(source);
const resultT = template(templateData);
res.send(resultT);
}
}
app.post("/devices-geo", async (req, res) => {
const selectedDevices = req.body.devices;
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
// console.log(selectedDevices);
const placeholders = selectedDevices
.map((_, index) => `$${index + 1}`)
.join(",");
const subquery = `
SELECT g.serial, g.longitude, g.latitude, g.direction, g.speed, r.lastkeepalive
FROM geo g
INNER JOIN (
SELECT serial, MAX(time) AS time
FROM geo
WHERE serial IN (
SELECT serial
FROM registrars
WHERE id IN (${placeholders})
)
GROUP BY serial
) s ON g.serial = s.serial AND g.time = s.time
INNER JOIN registrars r ON g.serial = r.serial
`;
pool.query(subquery, selectedDevices, (err, result) => {
if (err) {
console.error("Ошибка выполнения запроса:", err);
res.status(500).json({ error: "Ошибка сервера" });
return;
}
const minuteInMillis = 60000;
// Process the result to include lastkeepalive information
const devicesData = result.rows.map((row) => ({
serial: row.serial,
longitude: row.longitude,
latitude: row.latitude,
direction: row.direction,
speed: row.speed,
status: Date.now() - Date.parse(row.lastkeepalive) <= minuteInMillis,
}));
// console.log(result.rows);
res.json({ devicesData });
});
});
async function reports(req, res) {
let templateData = {
Organisation: "Название организации",
User: "Тестовое Имя",
ifDBError: false,
Registrars: [],
};
try {
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
const client = await pool.connect();
// Выполняем запрос и получаем результат
const query = `
SELECT a.id, a.cmdno, a.time, a.serial, a.st, r.plate, g.latitude, g.longitude
FROM (
SELECT id, cmdno, time, serial, st
FROM alarms
ORDER BY time DESC
LIMIT 100
) AS a
LEFT JOIN registrars AS r ON a.serial = r.serial
LEFT JOIN (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY serial ORDER BY ABS(EXTRACT(EPOCH FROM (time - $1)))) AS row_num
FROM geo
) AS g ON a.serial = g.serial AND g.row_num = 1
ORDER BY a.time DESC;
`;
const alarms = await client.query(query, [new Date()]); // Pass current date/time to the query for finding the nearest geoposition.
function formatDate(date) {
const options = {
year: "2-digit",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
};
const formattedDate = new Date(date).toLocaleString("ru-RU", options);
return formattedDate.replace(",", "");
}
(templateData.Alarms = alarms.rows.map((alarm) => {
let type;
switch (alarm.st) {
case "0":
type = "Усталость";
break;
case "1":
type = "Водитель пропал";
break;
case "2":
type = "Разговор по телефону";
break;
case "3":
type = "Курение за рулём";
break;
case "4":
type = "Водитель отвлекся";
break;
case "5":
type = "Выезд с полосы движения";
break;
case "6":
type = "!!! Лобовое столкновение";
break;
case "7":
type = "Скорость превышена";
break;
case "8":
type = "Распознавание номерных знаков";
break;
case "9":
type = "!! Маленькое расстояние спереди";
break;
case "10":
type = "Водитель зевает";
break;
case "11":
type = "!!! Столкновение с пешеходом";
break;
case "12":
type = "Проходы переполнены";
break;
case "13":
type = "!! Посадка/высадка вне остановки";
break;
case "14":
type = "!! Смена полосы с нарушением ПДД";
break;
case "15":
type = "! Включенный телефон у водителя";
break;
case "16":
type = "!!! Ремень безопасности";
break;
case "17":
type = "Проверка не удалась";
break;
case "18":
type = "Слепые зоны справа";
break;
case "19":
type = "!!! Заднее столкновение";
break;
case "20":
type = "!!! Управление без рук";
break;
case "21":
type = "!! Управление одной рукой";
break;
case "22":
type = "Очки, блокирующие инфракрасное излучение";
break;
case "23":
type = "Слепые зоны слева";
break;
case "24":
type = "Помехи для пассажиров";
break;
case "25":
type = "На перекрестке ограничена скорость";
break;
case "26":
type = "Обнаружен перекресток";
break;
case "27":
type = "Пешеходы на переходе";
break;
case "28":
type = "! Неучтивое отношение к пешеходам";
break;
case "29":
type = "Обнаружен пешеходный переход";
break;
case "30":
type = "Водитель матерится";
break;
default:
type = "Неизвестный тип";
}
return {
id: alarm.id,
cmdno: alarm.cmdno,
time: formatDate(alarm.time),
serial: alarm.serial,
st: alarm.st,
type: type,
plate: alarm.plate,
latitude: alarm.latitude,
longitude: alarm.longitude,
geo: alarm.latitude + "," + alarm.longitude,
};
})),
console.log(templateData);
const source = fs.readFileSync(
"static/templates/reports/index.html",
"utf8"
);
const template = handlebars.compile(source);
const resultT = template(templateData);
res.send(resultT);
} catch (error) {
console.error(error);
templateData.ifDBError = true;
const source = fs.readFileSync(
"static/templates/reports/index.html",
"utf8"
);
const template = handlebars.compile(source);
const resultT = template(templateData);
res.send(resultT);
}
}
app.get("/api/devices", async (req, res) => {
try {
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
const { page = 1, limit = 10 } = req.query;
const offset = (page - 1) * limit;
const query = `
SELECT a.id, a.cmdno, a.time, a.serial, a.st, r.plate, g.latitude, g.longitude
FROM (
SELECT id, cmdno, time, serial, st
FROM alarms
ORDER BY time DESC
LIMIT $1 OFFSET $2
) AS a
LEFT JOIN registrars AS r ON a.serial = r.serial
LEFT JOIN (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY serial ORDER BY ABS(EXTRACT(EPOCH FROM (time - $3)))) AS row_num
FROM geo
) AS g ON a.serial = g.serial AND g.row_num = 1
ORDER BY a.time DESC;
`;
const alarms = await pool.query(query, [limit, offset, new Date()]); // Pass current date/time to the query for finding the nearest geoposition.
function formatDate(date) {
const options = {
year: "2-digit",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
};
const formattedDate = new Date(date).toLocaleString("ru-RU", options);
return formattedDate.replace(",", "");
}
const alarmsData = alarms.rows.map((alarm) => {
let type;
switch (alarm.st) {
case "0":
type = "Усталость";
break;
case "1":
type = "Отсутствие водителя";
break;
case "2":
type = "Разговор по телефону";
break;
default:
type = "Неизвестный тип";
}
return {
id: alarm.id,
cmdno: alarm.cmdno,
time: formatDate(alarm.time),
serial: alarm.serial,
st: alarm.st,
type: type,
plate: alarm.plate,
latitude: alarm.latitude,
longitude: alarm.longitude,
geo: alarm.latitude + "," + alarm.longitude,
};
});
const totalCountQuery = "SELECT COUNT(*) FROM alarms;";
const totalCount = await pool.query(totalCountQuery);
const totalPages = Math.ceil(totalCount.rows[0].count / limit);
res.json({
data: alarmsData,
totalPages: totalPages,
});
} catch (error) {
console.error("Error executing query:", error);
res.status(500).json({ error: "Internal server error" });
}
});
function reports346(req, res) {
res.sendFile(path.join(__dirname, "static/templates/reports/346.html"));
}
async function devices(req, res) {
let templateData = {
Organisation: "Название организации",
User: "Тестовое Имя",
ifDBError: false,
Registrars: [],
};
try {
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
const client = await pool.connect();
const minuteInMillis = 60 * 1000;
// Выполняем запрос, чтобы получить все данные из таблицы registrars
const queryRegistrars = `
SELECT id, serial, lastkeepalive, name, "group", plate, sim, ip, port
FROM registrars
ORDER BY id
`;
const registrarsResult = await client.query(queryRegistrars);
const allRegistrars = registrarsResult.rows;
// Определяем статус connected на основе lastkeepalive
const templateData = {
Registrars: allRegistrars.map((registrar) => ({
id: registrar.id,
serial: registrar.serial,
status: Date.now() - Date.parse(registrar.lastkeepalive) <= minuteInMillis,
name: registrar.name,
group: registrar.group,
plate: registrar.plate,
sim: registrar.sim,
ip: registrar.ip,
port: registrar.port,
})),
};
console.log(templateData);
const source = fs.readFileSync("static/templates/devices/index.html", "utf8");
const template = handlebars.compile(source);
const resultT = template(templateData);
res.send(resultT);
client.release();
} catch (error) {
console.error(error);
templateData.ifDBError = true;
const source = fs.readFileSync(
"static/templates/devices/index.html",
"utf8"
);
const template = handlebars.compile(source);
const resultT = template(templateData);
res.send(resultT);
}
}
app.post("/devicedata", async (req, res) => {
const id = req.body.id;
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
const client = await pool.connect();
try {
// Выполняем запрос и получаем результат
const query = "SELECT * FROM registrars WHERE id = $1;";
const devicedata = await client.query(query, [id]);
// Формирование и отправка ответа
const response = devicedata.rows[0];
res.json(response);
} finally {
client.release();
}
});
app.post("/updatedevice", async (req, res) => {
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
const client = await pool.connect();
var {
plateNumber,
plateColor,
serialNumber,
channelsAmount,
connectionProtocol,
IPAddress,
deviceGroup,
serverPort,
sumNumber,
simIMEI,
simIMSI,
simModule,
transportType,
transportFactory,
transportStrength,
transportEngine,
transportStanina,
transportFuel,
transportCertificate,
transportCategory,
transportExpire,
transportConsumption,
transportProvince,
transportCity,
equipmentName,
equipmentPassword,
equipmentNumber,
equipmentReleased,
equipmentInstaller,
equipmentInstalled,
equipmentDescription,
} = req.body;
try {
// Обновление строки в таблице registrars
const query = `
UPDATE registrars
SET
plate = $1,
plate_color = $2,
channels = $3,
protocol = $4,
ip = $5,
"group" = $6,
port = $7,
sim = $8,
imei = $9,
imsi = $10,
module = $11,
auto = $12,
factory = $13,
capacity = $14,
engine = $15,
stanina = $16,
fuel = $17,
certificate = $18,
category = $19,
certificate_exp = $20,
consumption = $21,
region = $22,
city = $23,
name = $24,
password = $25,
batch = $26,
release = $27,
installer = $28,
installation = $29,
description = $30
WHERE serial = $31
RETURNING *;
`;
const values = [
plateNumber,
plateColor,
channelsAmount,
connectionProtocol,
IPAddress,
deviceGroup,
serverPort,
sumNumber,
simIMEI,
simIMSI,
simModule,
transportType,
transportFactory,
transportStrength,
transportEngine,
transportStanina,
transportFuel,
transportCertificate,
transportCategory,
transportExpire,
transportConsumption,
transportProvince,
transportCity,
equipmentName,
equipmentPassword,
equipmentNumber,
equipmentReleased,
equipmentInstaller,
equipmentInstalled,
equipmentDescription,
serialNumber,
];
const result = await client.query(query, values);
const updatedRow = result.rows[0];
console.log("Updated row:", updatedRow);
res.send("Data updated successfully");
} catch (error) {
console.error("Error updating data:", error);
res.status(500).send("An error occurred while updating data");
} finally {
client.release();
}
});
app.post("/updatedriver", upload.single("upload-file"), async (req, res) => {
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
const client = await pool.connect();
var {
driverName,
driverSurname,
driverCard,
driverGender,
driverLicense,
driverPassport,
driverPhone,
driverEmail,
driverTransport,
driverDescription,
driverID,
} = req.body;
try {
// Вставка новой строки в таблицу drivers
const query = `
UPDATE drivers
SET name = $1,
surname = $2,
card = $3,
gender = $4,
license = $5,
passport = $6,
phone = $7,
email = $8,
transport = $9,
description = $10
WHERE id = $11
RETURNING *;
`;
const values = [
driverName,
driverSurname,
driverCard,
driverGender,
driverLicense,
driverPassport,
driverPhone,
driverEmail,
driverTransport,
driverDescription,
driverID,
];
const result = await client.query(query, values);
const newRow = result.rows[0];
console.log("New driver added:", newRow);
res.send("Data added successfully");
} catch (error) {
console.error("Error adding data:", error);
res.status(500).send("An error occurred while adding data");
} finally {
client.release();
}
});
app.post("/adddriver", upload.single("upload-file"), async (req, res) => {
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
const client = await pool.connect();
var {
driverName,
driverSurname,
driverCard,
driverGender,
driverLicense,
driverPassport,
driverPhone,
driverEmail,
driverTransport,
driverDescription,
} = req.body;
try {
// Вставка новой строки в таблицу drivers
const query = `
INSERT INTO drivers (
name,
surname,
card,
gender,
license,
passport,
phone,
email,
transport,
description
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING *;
`;
const values = [
driverName,
driverSurname,
driverCard,
driverGender,
driverLicense,
driverPassport,
driverPhone,
driverEmail,
driverTransport,
driverDescription,
];
const result = await client.query(query, values);
const newRow = result.rows[0];
console.log("New driver added:", newRow);
res.send("Data added successfully");
} catch (error) {
console.error("Error adding data:", error);
res.status(500).send("An error occurred while adding data");
} finally {
client.release();
}
});
app.post("/driverdata", async (req, res) => {
const id = req.body.id;
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
const client = await pool.connect();
try {
// Выполняем запрос и получаем результат
const query = "SELECT * FROM drivers WHERE id = $1;";
const driverdata = await client.query(query, [id]);
// Формирование и отправка ответа
const response = driverdata.rows[0];
res.json(response);
} finally {
client.release();
}
});
app.post("/deletedriver", async (req, res) => {
const id = req.body.id;
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
const client = await pool.connect();
try {
// Выполняем запрос и получаем результат
const query = "DELETE FROM drivers WHERE id = $1;";
const driverdata = await client.query(query, [id]);
// Формирование и отправка ответа
res.send("Data deleted successfully");
} finally {
client.release();
}
});
async function drivers(req, res) {
let templateData = {
Organisation: "Название организации",
User: "Тестовое Имя",
ifDBError: false,
Drivers: [],
Registrars: [],
};
try {
const pool = new Pool({
user: DB_User,
host: DB_Host,
database: DB_Name,
password: DB_Password,
port: DB_Port,
});
const client = await pool.connect();
// Выполняем запрос для объединения данных из таблиц drivers и registrars
const queryDrivers = `
SELECT d.id, d.name, d.surname, d.transport, d.phone, d.email, d.card, r.connected
FROM drivers d
LEFT JOIN registrars r ON d.transport = r.serial
ORDER BY r.connected DESC NULLS LAST, CASE WHEN r.connected = true THEN 0 ELSE 1 END, d.id
`;
const driversResult = await client.query(queryDrivers);
templateData.Drivers = driversResult.rows.map((driver) => ({
id: driver.id,
name: driver.name,
surname: driver.surname,
transport: driver.transport,
phone: driver.phone,
email: driver.email,
card: driver.card,
}));
const queryRegistrars = `
SELECT serial
FROM registrars
`;
const registrarsResult = await client.query(queryRegistrars);
templateData.Registrars = registrarsResult.rows.map(
(registrar) => registrar.serial
);
console.log(templateData);
const source = fs.readFileSync(
"static/templates/devices/drivers.html",
"utf8"
);
const template = handlebars.compile(source);
const resultT = template(templateData);
res.send(resultT);
client.release();
} catch (error) {
console.error(error);
templateData.ifDBError = true;
const source = fs.readFileSync(
"static/templates/devices/drivers.html",
"utf8"
);
const template = handlebars.compile(source);
const resultT = template(templateData);
res.send(resultT);
}
}
function update(req, res) {
res.sendFile(path.join(__dirname, "static/templates/devices/update.html"));
}
const port = 8081;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
// app.use((req, res, next) => {
// res.sendFile(path.join(__dirname, "static/templates/404.html"));
// });