Migrar backend a PostgreSQL + Node.js/Express con nuevas funcionalidades
Backend (water-api/): - Crear API REST completa con Express + TypeScript - Implementar autenticación JWT con refresh tokens - CRUD completo para: projects, concentrators, meters, gateways, devices, users, roles - Agregar validación con Zod para todas las entidades - Implementar webhooks para The Things Stack (LoRaWAN) - Agregar endpoint de lecturas con filtros y resumen de consumo - Implementar carga masiva de medidores via Excel (.xlsx) Frontend: - Crear cliente HTTP con manejo automático de JWT y refresh - Actualizar todas las APIs para usar nuevo backend - Agregar sistema de autenticación real (login, logout, me) - Agregar selector de tipo (LORA, LoRaWAN, Grandes) en concentradores y medidores - Agregar campo Meter ID en medidores - Crear modal de carga masiva para medidores - Agregar página de consumo con gráficas y filtros - Corregir carga de proyectos independiente de datos existentes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
222
water-api/src/controllers/role.controller.ts
Normal file
222
water-api/src/controllers/role.controller.ts
Normal file
@@ -0,0 +1,222 @@
|
||||
import { Response } from 'express';
|
||||
import { AuthenticatedRequest } from '../middleware/auth.middleware';
|
||||
import * as roleService from '../services/role.service';
|
||||
import { CreateRoleInput, UpdateRoleInput } from '../validators/role.validator';
|
||||
|
||||
/**
|
||||
* GET /roles
|
||||
* List all roles (all authenticated users)
|
||||
*/
|
||||
export async function getAllRoles(
|
||||
_req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> {
|
||||
try {
|
||||
const roles = await roleService.getAll();
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Roles retrieved successfully',
|
||||
data: roles,
|
||||
});
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Failed to retrieve roles';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /roles/:id
|
||||
* Get a single role by ID with user count (all authenticated users)
|
||||
*/
|
||||
export async function getRoleById(
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> {
|
||||
try {
|
||||
const roleId = parseInt(req.params.id, 10);
|
||||
|
||||
if (isNaN(roleId)) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error: 'Invalid role ID',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const role = await roleService.getById(roleId);
|
||||
|
||||
if (!role) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
error: 'Role not found',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Role retrieved successfully',
|
||||
data: role,
|
||||
});
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Failed to retrieve role';
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /roles
|
||||
* Create a new role (admin only)
|
||||
*/
|
||||
export async function createRole(
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> {
|
||||
try {
|
||||
const data = req.body as CreateRoleInput;
|
||||
|
||||
const role = await roleService.create({
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
permissions: data.permissions as Record<string, unknown> | undefined,
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: 'Role created successfully',
|
||||
data: role,
|
||||
});
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Failed to create role';
|
||||
|
||||
if (message === 'Role name already exists') {
|
||||
res.status(409).json({
|
||||
success: false,
|
||||
error: message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /roles/:id
|
||||
* Update a role (admin only)
|
||||
*/
|
||||
export async function updateRole(
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> {
|
||||
try {
|
||||
const roleId = parseInt(req.params.id, 10);
|
||||
|
||||
if (isNaN(roleId)) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error: 'Invalid role ID',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const data = req.body as UpdateRoleInput;
|
||||
|
||||
const role = await roleService.update(roleId, {
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
permissions: data.permissions as Record<string, unknown> | undefined,
|
||||
});
|
||||
|
||||
if (!role) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
error: 'Role not found',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Role updated successfully',
|
||||
data: role,
|
||||
});
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Failed to update role';
|
||||
|
||||
if (message === 'Role name already exists') {
|
||||
res.status(409).json({
|
||||
success: false,
|
||||
error: message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /roles/:id
|
||||
* Delete a role (admin only, only if no users assigned)
|
||||
*/
|
||||
export async function deleteRole(
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> {
|
||||
try {
|
||||
const roleId = parseInt(req.params.id, 10);
|
||||
|
||||
if (isNaN(roleId)) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error: 'Invalid role ID',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const deleted = await roleService.deleteRole(roleId);
|
||||
|
||||
if (!deleted) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
error: 'Role not found',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Role deleted successfully',
|
||||
});
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Failed to delete role';
|
||||
|
||||
// Handle case where users are assigned to the role
|
||||
if (message.includes('Cannot delete role')) {
|
||||
res.status(409).json({
|
||||
success: false,
|
||||
error: message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: message,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user