Improve centralized error handling

This commit is contained in:
richardtekula
2025-12-04 07:39:52 +01:00
parent 109cae1167
commit 35dfa07668
14 changed files with 266 additions and 336 deletions

View File

@@ -1,9 +1,9 @@
import { db } from '../config/database.js';
import { users } from '../db/schema.js';
import { eq } from 'drizzle-orm';
import { users, userEmailAccounts, emailAccounts } from '../db/schema.js';
import { eq, inArray } from 'drizzle-orm';
import { hashPassword, generateTempPassword } from '../utils/password.js';
import { logUserCreation, logRoleChange } from '../services/audit.service.js';
import { formatErrorResponse, ConflictError, NotFoundError } from '../utils/errors.js';
import { ConflictError, NotFoundError } from '../utils/errors.js';
import * as emailAccountService from '../services/email-account.service.js';
/**
@@ -11,7 +11,7 @@ import * as emailAccountService from '../services/email-account.service.js';
* Ak je poskytnutý email a emailPassword, automaticky sa fetchne JMAP account ID
* POST /api/admin/users
*/
export const createUser = async (req, res) => {
export const createUser = async (req, res, next) => {
const { username, email, emailPassword, firstName, lastName, role } = req.body;
const adminId = req.userId;
const ipAddress = req.ip || req.connection.remoteAddress;
@@ -100,8 +100,7 @@ export const createUser = async (req, res) => {
: 'Používateľ úspešne vytvorený. Email môže byť nastavený neskôr.',
});
} catch (error) {
const errorResponse = formatErrorResponse(error, process.env.NODE_ENV === 'development');
res.status(error.statusCode || 500).json(errorResponse);
return next(error);
}
};
@@ -109,7 +108,7 @@ export const createUser = async (req, res) => {
* Zoznam všetkých userov (admin only)
* GET /api/admin/users
*/
export const getAllUsers = async (req, res) => {
export const getAllUsers = async (req, res, next) => {
try {
const allUsers = await db
.select({
@@ -130,8 +129,7 @@ export const getAllUsers = async (req, res) => {
data: allUsers,
});
} catch (error) {
const errorResponse = formatErrorResponse(error, process.env.NODE_ENV === 'development');
res.status(error.statusCode || 500).json(errorResponse);
return next(error);
}
};
@@ -139,7 +137,7 @@ export const getAllUsers = async (req, res) => {
* Získanie konkrétneho usera (admin only)
* GET /api/admin/users/:userId
*/
export const getUser = async (req, res) => {
export const getUser = async (req, res, next) => {
const { userId } = req.params;
try {
@@ -176,8 +174,7 @@ export const getUser = async (req, res) => {
},
});
} catch (error) {
const errorResponse = formatErrorResponse(error, process.env.NODE_ENV === 'development');
res.status(error.statusCode || 500).json(errorResponse);
return next(error);
}
};
@@ -185,7 +182,7 @@ export const getUser = async (req, res) => {
* Zmena role usera (admin only)
* PATCH /api/admin/users/:userId/role
*/
export const changeUserRole = async (req, res) => {
export const changeUserRole = async (req, res, next) => {
const { userId } = req.params;
const { role } = req.body;
const adminId = req.userId;
@@ -228,8 +225,7 @@ export const changeUserRole = async (req, res) => {
message: 'Rola používateľa bola zmenená',
});
} catch (error) {
const errorResponse = formatErrorResponse(error, process.env.NODE_ENV === 'development');
res.status(error.statusCode || 500).json(errorResponse);
return next(error);
}
};
@@ -237,7 +233,7 @@ export const changeUserRole = async (req, res) => {
* Zmazanie usera (admin only)
* DELETE /api/admin/users/:userId
*/
export const deleteUser = async (req, res) => {
export const deleteUser = async (req, res, next) => {
const { userId } = req.params;
try {
@@ -263,14 +259,38 @@ export const deleteUser = async (req, res) => {
}
}
// Get user's email account IDs before deletion
const userEmailAccountLinks = await db
.select({ emailAccountId: userEmailAccounts.emailAccountId })
.from(userEmailAccounts)
.where(eq(userEmailAccounts.userId, userId));
const emailAccountIds = userEmailAccountLinks.map(link => link.emailAccountId);
// Delete user (cascades userEmailAccounts links)
await db.delete(users).where(eq(users.id, userId));
// Delete orphaned email accounts (no users linked)
// This will cascade delete contacts and emails
let deletedEmailAccounts = 0;
for (const emailAccountId of emailAccountIds) {
const [remainingLinks] = await db
.select({ count: db.$count(userEmailAccounts) })
.from(userEmailAccounts)
.where(eq(userEmailAccounts.emailAccountId, emailAccountId));
if (remainingLinks.count === 0) {
await db.delete(emailAccounts).where(eq(emailAccounts.id, emailAccountId));
deletedEmailAccounts++;
}
}
res.status(200).json({
success: true,
message: 'Používateľ bol zmazaný',
deletedEmailAccounts,
});
} catch (error) {
const errorResponse = formatErrorResponse(error, process.env.NODE_ENV === 'development');
res.status(error.statusCode || 500).json(errorResponse);
return next(error);
}
};