Improve error handling and ordering flows
This commit is contained in:
+165
-32
@@ -2,11 +2,59 @@ const express = require('express');
|
||||
const router = express.Router();
|
||||
const pool = require('../db');
|
||||
|
||||
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 };
|
||||
};
|
||||
|
||||
const isMissingPositionColumn = (error) =>
|
||||
error && error.code === "ER_BAD_FIELD_ERROR" && String(error.sqlMessage || "").includes("position");
|
||||
|
||||
|
||||
// GET ALL DOMAINS
|
||||
router.get('/', async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.query(`
|
||||
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,
|
||||
@@ -18,8 +66,9 @@ router.get('/', async (req, res) => {
|
||||
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
|
||||
ORDER BY d.domain_name ASC
|
||||
`);
|
||||
}
|
||||
|
||||
res.json(rows);
|
||||
|
||||
@@ -56,22 +105,48 @@ router.get('/:id', async (req, res) => {
|
||||
|
||||
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" });
|
||||
}
|
||||
|
||||
const { domain_name, provider, ip_address, yearly_cost, notes } = req.body;
|
||||
let result;
|
||||
|
||||
const [result] = await pool.query(
|
||||
`INSERT INTO domains
|
||||
(domain_name, provider, ip_address, yearly_cost, notes)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
[
|
||||
domain_name,
|
||||
provider,
|
||||
ip_address,
|
||||
yearly_cost || null,
|
||||
notes
|
||||
]
|
||||
);
|
||||
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)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -84,20 +159,11 @@ notes
|
||||
|
||||
console.error("CREATE domain error:", err);
|
||||
|
||||
let message="Database error"
|
||||
const { status, message } = mapDomainError(err, "Domain konnte nicht gespeichert werden");
|
||||
|
||||
if(err.code==="WARN_DATA_TRUNCATED"){
|
||||
message="Invalid price format (use 1.99)"
|
||||
}
|
||||
|
||||
if(err.code==="ER_DUP_ENTRY"){
|
||||
message="Domain already exists"
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
error: message,
|
||||
details: err.sqlMessage
|
||||
})
|
||||
res.status(status).json({
|
||||
error: message
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -106,7 +172,11 @@ details: err.sqlMessage
|
||||
// UPDATE DOMAIN
|
||||
router.put('/:id', async (req, res) => {
|
||||
try {
|
||||
const { domain_name, provider, ip_address, yearly_cost, notes } = req.body;
|
||||
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
|
||||
@@ -116,14 +186,77 @@ router.put('/:id', async (req, res) => {
|
||||
yearly_cost = ?,
|
||||
notes = ?
|
||||
WHERE id = ?`,
|
||||
[domain_name, provider, ip_address, yearly_cost, notes, req.params.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);
|
||||
res.status(500).json({ error: "DB error" });
|
||||
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
|
||||
|
||||
if (direction !== "up" && direction !== "down") {
|
||||
return res.status(400).json({ error: "Ungueltige Richtung" })
|
||||
}
|
||||
|
||||
let rows
|
||||
|
||||
try {
|
||||
await pool.query(
|
||||
"UPDATE domains SET position = id WHERE position IS NULL"
|
||||
)
|
||||
|
||||
;[rows] = await pool.query(
|
||||
"SELECT id, domain_name FROM domains ORDER BY position, domain_name, id"
|
||||
)
|
||||
} catch (err) {
|
||||
if (isMissingPositionColumn(err)) {
|
||||
return res.status(400).json({ error: "Position-Spalte in domains fehlt noch" })
|
||||
}
|
||||
throw err
|
||||
}
|
||||
|
||||
const index = rows.findIndex(row => row.id == req.params.id)
|
||||
|
||||
if (index === -1) {
|
||||
return res.status(404).json({ error: "Domain nicht gefunden" })
|
||||
}
|
||||
|
||||
const swapIndex = direction === "up" ? index - 1 : index + 1
|
||||
|
||||
if (swapIndex < 0 || swapIndex >= rows.length) {
|
||||
return res.json({ success: true })
|
||||
}
|
||||
|
||||
const moved = rows.splice(index, 1)[0]
|
||||
rows.splice(swapIndex, 0, moved)
|
||||
|
||||
for(let i = 0; i < rows.length; i++){
|
||||
await pool.query(
|
||||
"UPDATE domains SET position = ? WHERE id = ?",
|
||||
[i + 1, rows[i].id]
|
||||
)
|
||||
}
|
||||
|
||||
res.json({ success: true })
|
||||
|
||||
} catch (err) {
|
||||
console.error("MOVE domain error:", err);
|
||||
res.status(500).json({ error: "Reihenfolge konnte nicht geaendert werden" })
|
||||
}
|
||||
});
|
||||
|
||||
@@ -140,7 +273,7 @@ router.delete('/:id', async (req, res) => {
|
||||
|
||||
} catch (err) {
|
||||
console.error("DELETE domain error:", err);
|
||||
res.status(500).json({ error: "DB error" });
|
||||
res.status(500).json({ error: "Domain konnte nicht geloescht werden" });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user