246 lines
5.5 KiB
JavaScript
246 lines
5.5 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const pool = require('../db');
|
|
const { moveByPosition, isMissingPositionColumn } = require("../helpers/positionMove");
|
|
|
|
const clean = (value) => value === "" ? null : value;
|
|
|
|
const normalizeCost = (value) => {
|
|
if (value === undefined || value === null || value === "") return null;
|
|
return String(value).replace(",", ".");
|
|
};
|
|
|
|
const mapDomainError = (err, fallbackMessage) => {
|
|
let message = fallbackMessage;
|
|
let status = 500;
|
|
|
|
if (err.code === "WARN_DATA_TRUNCATED") {
|
|
status = 400;
|
|
message = "Ungueltiges Preisformat";
|
|
}
|
|
|
|
if (err.code === "ER_DUP_ENTRY") {
|
|
status = 400;
|
|
message = "Domain existiert bereits";
|
|
}
|
|
|
|
return { status, message };
|
|
};
|
|
|
|
// GET ALL DOMAINS
|
|
router.get('/', async (req, res) => {
|
|
try {
|
|
let rows;
|
|
|
|
try {
|
|
[rows] = await pool.query(`
|
|
SELECT
|
|
d.id,
|
|
d.domain_name,
|
|
d.provider,
|
|
d.ip_address,
|
|
d.yearly_cost,
|
|
d.notes,
|
|
d.position,
|
|
r.name AS resource_name
|
|
FROM domains d
|
|
LEFT JOIN resource_ips ip ON d.ip_address = ip.ip
|
|
LEFT JOIN resources r ON ip.resource_id = r.id
|
|
ORDER BY COALESCE(d.position, d.id) ASC, d.domain_name ASC
|
|
`);
|
|
} catch (err) {
|
|
if (!isMissingPositionColumn(err)) throw err;
|
|
|
|
[rows] = await pool.query(`
|
|
SELECT
|
|
d.id,
|
|
d.domain_name,
|
|
d.provider,
|
|
d.ip_address,
|
|
d.yearly_cost,
|
|
d.notes,
|
|
r.name AS resource_name
|
|
FROM domains d
|
|
LEFT JOIN resource_ips ip ON d.ip_address = ip.ip
|
|
LEFT JOIN resources r ON ip.resource_id = r.id
|
|
ORDER BY d.domain_name ASC
|
|
`);
|
|
}
|
|
|
|
res.json(rows);
|
|
|
|
} catch (err) {
|
|
console.error("GET domains error:", err);
|
|
res.status(500).json({ error: "DB error" });
|
|
}
|
|
});
|
|
|
|
|
|
// GET SINGLE DOMAIN
|
|
router.get('/:id', async (req, res) => {
|
|
try {
|
|
const [rows] = await pool.query(
|
|
`SELECT * FROM domains WHERE id = ?`,
|
|
[req.params.id]
|
|
);
|
|
|
|
if (rows.length === 0) {
|
|
return res.status(404).json({ error: "Domain not found" });
|
|
}
|
|
|
|
res.json(rows[0]);
|
|
|
|
} catch (err) {
|
|
console.error("GET domain error:", err);
|
|
res.status(500).json({ error: "DB error" });
|
|
}
|
|
});
|
|
|
|
|
|
// CREATE DOMAIN
|
|
|
|
|
|
router.post('/', async (req, res) => {
|
|
try {
|
|
const domainName = req.body.domain_name ? String(req.body.domain_name).trim() : "";
|
|
|
|
if (!domainName) {
|
|
return res.status(400).json({ error: "Domain darf nicht leer sein" });
|
|
}
|
|
|
|
let result;
|
|
|
|
try {
|
|
const [[positionRow]] = await pool.query(
|
|
"SELECT COALESCE(MAX(position), 0) + 1 AS nextPosition FROM domains"
|
|
);
|
|
|
|
[result] = await pool.query(
|
|
`INSERT INTO domains
|
|
(domain_name, provider, ip_address, yearly_cost, notes, position)
|
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
[
|
|
domainName,
|
|
clean(req.body.provider),
|
|
clean(req.body.ip_address),
|
|
normalizeCost(req.body.yearly_cost),
|
|
clean(req.body.notes),
|
|
positionRow.nextPosition
|
|
]
|
|
);
|
|
} catch (err) {
|
|
if (!isMissingPositionColumn(err)) throw err;
|
|
|
|
[result] = await pool.query(
|
|
`INSERT INTO domains
|
|
(domain_name, provider, ip_address, yearly_cost, notes)
|
|
VALUES (?, ?, ?, ?, ?)`,
|
|
[
|
|
domainName,
|
|
clean(req.body.provider),
|
|
clean(req.body.ip_address),
|
|
normalizeCost(req.body.yearly_cost),
|
|
clean(req.body.notes)
|
|
]
|
|
);
|
|
}
|
|
|
|
|
|
|
|
res.json({
|
|
message: "Domain created",
|
|
id: result.insertId
|
|
});
|
|
|
|
}catch (err) {
|
|
|
|
console.error("CREATE domain error:", err);
|
|
|
|
const { status, message } = mapDomainError(err, "Domain konnte nicht gespeichert werden");
|
|
|
|
res.status(status).json({
|
|
error: message
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// UPDATE DOMAIN
|
|
router.put('/:id', async (req, res) => {
|
|
try {
|
|
const domainName = req.body.domain_name ? String(req.body.domain_name).trim() : "";
|
|
|
|
if (!domainName) {
|
|
return res.status(400).json({ error: "Domain darf nicht leer sein" });
|
|
}
|
|
|
|
await pool.query(
|
|
`UPDATE domains SET
|
|
domain_name = ?,
|
|
provider = ?,
|
|
ip_address = ?,
|
|
yearly_cost = ?,
|
|
notes = ?
|
|
WHERE id = ?`,
|
|
[
|
|
domainName,
|
|
clean(req.body.provider),
|
|
clean(req.body.ip_address),
|
|
normalizeCost(req.body.yearly_cost),
|
|
clean(req.body.notes),
|
|
req.params.id
|
|
]
|
|
);
|
|
|
|
res.json({ message: "Domain updated" });
|
|
|
|
} catch (err) {
|
|
console.error("UPDATE domain error:", err);
|
|
const { status, message } = mapDomainError(err, "Domain konnte nicht gespeichert werden");
|
|
res.status(status).json({ error: message });
|
|
}
|
|
});
|
|
|
|
router.post('/:id/move', async (req, res) => {
|
|
try {
|
|
const { direction } = req.body
|
|
|
|
const result = await moveByPosition({
|
|
db: pool,
|
|
table: "domains",
|
|
id: req.params.id,
|
|
direction,
|
|
selectQuery: "SELECT id FROM domains ORDER BY position, domain_name, id",
|
|
missingColumnMessage: "Position-Spalte in domains fehlt noch",
|
|
notFoundMessage: "Domain nicht gefunden",
|
|
});
|
|
|
|
res.status(result.status).json(result.body);
|
|
|
|
} catch (err) {
|
|
console.error("MOVE domain error:", err);
|
|
res.status(500).json({ error: "Reihenfolge konnte nicht geaendert werden" })
|
|
}
|
|
});
|
|
|
|
|
|
// DELETE DOMAIN
|
|
router.delete('/:id', async (req, res) => {
|
|
try {
|
|
await pool.query(
|
|
`DELETE FROM domains WHERE id = ?`,
|
|
[req.params.id]
|
|
);
|
|
|
|
res.json({ message: "Domain deleted" });
|
|
|
|
} catch (err) {
|
|
console.error("DELETE domain error:", err);
|
|
res.status(500).json({ error: "Domain konnte nicht geloescht werden" });
|
|
}
|
|
});
|
|
|
|
|
|
module.exports = router;
|