Skip to content
This repository was archived by the owner on Mar 16, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/backend/src/controllers/authController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { z } from "zod";
import { prisma } from "../../prisma";
import { generateToken } from "../utils/generateToken";
import { UserRole } from "../../generated/prisma/enums";
import { RegisterSchema, LoginSchema } from "../utils/authSchema";
import { RegisterSchema, LoginSchema } from "../validations/authSchema";
import crypto from "crypto";

class AuthController {
Expand Down
64 changes: 51 additions & 13 deletions apps/backend/src/controllers/driverController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import express from "express";
import { DriverService } from "../services/driverServices";
import { AuthRequest } from "../types/auth";
import { UserRole } from "../../generated/prisma/enums";
import {
CreateDriverSchema,
UpdateDriverSchema,
} from "../validations/driverSchema";
import { ZodError } from "zod";

/**
* @swagger
Expand Down Expand Up @@ -169,9 +174,14 @@ const getDriverById = async (req: AuthRequest, res: express.Response) => {
* properties:
* name:
* type: string
* minLength: 2
* maxLength: 100
* example: "Mario Hernández"
* license_number:
* type: string
* minLength: 3
* maxLength: 50
* pattern: "^[A-Z0-9-]+$"
* example: "TX-DL-001234"
* responses:
* 201:
Expand All @@ -181,7 +191,7 @@ const getDriverById = async (req: AuthRequest, res: express.Response) => {
* schema:
* $ref: '#/components/schemas/Driver'
* 400:
* description: Name and License Number are required
* description: Validation error
* 401:
* description: Not authorized
* 403:
Expand All @@ -200,20 +210,25 @@ const createDriver = async (req: AuthRequest, res: express.Response) => {
if (userRole !== UserRole.ADMIN)
return res.status(403).json({ error: "Only Admins can create drivers" });

const { name, license_number } = req.body;
if (!name || !license_number) {
return res
.status(400)
.json({ message: "Name and License Number are required" });
}
// Validación con Zod
const validatedData = CreateDriverSchema.parse(req.body);

const newDriver = await DriverService.create(
{ name, license_number },
companyId,
);
const newDriver = await DriverService.create(validatedData, companyId);

res.status(201).json(newDriver);
} catch (error: any) {
// Manejo de errores de Zod
if (error instanceof ZodError) {
return res.status(400).json({
error: "Validation failed",
issues: error.issues.map((issue) => ({
path: issue.path.join("."),
message: issue.message,
})),
});
}

// Manejo de errores del servicio
if (error.message === "LICENSE_EXISTS") {
return res.status(409).json({
message:
Expand All @@ -227,6 +242,7 @@ const createDriver = async (req: AuthRequest, res: express.Response) => {
"This driver exists but is inactive. Please reactivate them instead of creating a new one.",
});
}

console.error(error);
res.status(500).json({ error: "Error creating driver" });
}
Expand Down Expand Up @@ -257,9 +273,14 @@ const createDriver = async (req: AuthRequest, res: express.Response) => {
* properties:
* name:
* type: string
* minLength: 2
* maxLength: 100
* example: "Mario Hernández"
* license_number:
* type: string
* minLength: 3
* maxLength: 50
* pattern: "^[A-Z0-9-]+$"
* example: "TX-DL-001234"
* is_active:
* type: boolean
Expand All @@ -271,6 +292,8 @@ const createDriver = async (req: AuthRequest, res: express.Response) => {
* application/json:
* schema:
* $ref: '#/components/schemas/Driver'
* 400:
* description: Validation error
* 401:
* description: Not authorized
* 404:
Expand All @@ -287,25 +310,40 @@ const updateDriver = async (req: AuthRequest, res: express.Response) => {

if (!companyId) return res.status(401).json({ error: "Not authorized" });

const dataToUpdate = req.body;
// Validación con Zod
const validatedData = UpdateDriverSchema.parse(req.body);

const updatedDriver = await DriverService.update(
id as string,
dataToUpdate,
validatedData,
companyId,
);

res.status(200).json(updatedDriver);
} catch (error: any) {
// Manejo de errores de Zod
if (error instanceof ZodError) {
return res.status(400).json({
error: "Validation failed",
issues: error.issues.map((issue) => ({
path: issue.path.join("."),
message: issue.message,
})),
});
}

// Manejo de errores del servicio
if (error.message === "LICENSE_EXISTS") {
return res
.status(409)
.json({ message: "License number already in use by another driver." });
}

console.error(error);
if (error.message.includes("not found")) {
return res.status(404).json({ error: "Driver not found" });
}

res.status(500).json({
message: "Error updating driver",
error: error?.message,
Expand Down
53 changes: 51 additions & 2 deletions apps/backend/src/controllers/vehicleController.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { Request, Response } from "express";
import { VehicleService } from "../services/vehicleServices";
import { AuthRequest } from "../types/auth";
import {
CreateVehicleSchema,
UpdateVehicleSchema,
} from "../validations/vehicleSchema";
import { ZodError } from "zod";

/**
* @swagger
Expand Down Expand Up @@ -55,13 +60,19 @@ import { AuthRequest } from "../types/auth";
* properties:
* unit_number:
* type: string
* maxLength: 50
* example: "TRUCK-042"
* plate:
* type: string
* maxLength: 20
* pattern: "^[A-Z0-9-]+$"
* example: "TX-ABC-1234"
* is_active:
* type: boolean
* default: true
* driverId:
* type: string
* format: uuid
* responses:
* 201:
* description: Vehicle created successfully
Expand All @@ -75,6 +86,8 @@ import { AuthRequest } from "../types/auth";
* example: true
* data:
* $ref: '#/components/schemas/Vehicle'
* 400:
* description: Validation error
* 401:
* description: Not authorized
* content:
Expand All @@ -93,11 +106,25 @@ export const createVehicle = async (req: AuthRequest, res: Response) => {
const companyId = req.user?.companyId;
if (!companyId) return res.status(401).json({ error: "Not authorized" });

const vehicleData = { ...req.body, companyId };
// Validación con Zod
const validatedData = CreateVehicleSchema.parse(req.body);

const vehicleData = { ...validatedData, companyId };
const vehicle = await VehicleService.create(vehicleData);

res.status(201).json({ success: true, data: vehicle });
} catch (error: any) {
// Manejo de errores de Zod
if (error instanceof ZodError) {
return res.status(400).json({
error: "Validation failed",
issues: error.issues.map((issue) => ({
path: issue.path.join("."),
message: issue.message,
})),
});
}

console.error(error);
res.status(500).json({
success: false,
Expand Down Expand Up @@ -245,13 +272,19 @@ export const getVehicleById = async (req: AuthRequest, res: Response) => {
* properties:
* unit_number:
* type: string
* maxLength: 50
* example: "TRUCK-042-UPDATED"
* plate:
* type: string
* maxLength: 20
* pattern: "^[A-Z0-9-]+$"
* example: "TX-NEW-9999"
* is_active:
* type: boolean
* example: true
* driverId:
* type: string
* format: uuid
* responses:
* 200:
* description: Vehicle updated successfully
Expand All @@ -265,6 +298,8 @@ export const getVehicleById = async (req: AuthRequest, res: Response) => {
* example: true
* data:
* $ref: '#/components/schemas/Vehicle'
* 400:
* description: Validation error
* 401:
* description: Not authorized
* 404:
Expand All @@ -278,13 +313,27 @@ export const updateVehicle = async (req: AuthRequest, res: Response) => {
const companyId = req.user?.companyId;
if (!companyId) return res.status(401).json({ error: "Not authorized" });

// Validación con Zod
const validatedData = UpdateVehicleSchema.parse(req.body);

const updated = await VehicleService.update(
String(id),
companyId,
req.body,
validatedData,
);
res.json({ success: true, data: updated });
} catch (error: any) {
// Manejo de errores de Zod
if (error instanceof ZodError) {
return res.status(400).json({
error: "Validation failed",
issues: error.issues.map((issue) => ({
path: issue.path.join("."),
message: issue.message,
})),
});
}

res.status(500).json({ success: false, error: error.message });
}
};
Expand Down
47 changes: 47 additions & 0 deletions apps/backend/src/validations/driverSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { z } from "zod";

// Schema para crear un driver
export const CreateDriverSchema = z.object({
name: z
.string()
.min(1, "Name is required")
.min(2, "Name must be at least 2 characters")
.max(100, "Name must not exceed 100 characters")
.trim(),
license_number: z
.string()
.min(1, "License number is required")
.min(3, "License number must be at least 3 characters")
.max(50, "License number must not exceed 50 characters")
.trim()
.regex(
/^[A-Z0-9-]+$/i,
"License number can only contain letters, numbers, and hyphens",
),
is_active: z.boolean().optional().default(true),
});

// Schema para actualizar un driver
export const UpdateDriverSchema = z.object({
name: z
.string()
.min(2, "Name must be at least 2 characters")
.max(100, "Name must not exceed 100 characters")
.trim()
.optional(),
license_number: z
.string()
.min(3, "License number must be at least 3 characters")
.max(50, "License number must not exceed 50 characters")
.trim()
.regex(
/^[A-Z0-9-]+$/i,
"License number can only contain letters, numbers, and hyphens",
)
.optional(),
is_active: z.boolean().optional(),
});

// Exportar tipos inferidos
export type CreateDriverDTO = z.infer<typeof CreateDriverSchema>;
export type UpdateDriverDTO = z.infer<typeof UpdateDriverSchema>;
49 changes: 49 additions & 0 deletions apps/backend/src/validations/vehicleSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { z } from "zod";

// Schema para crear un driver
export const CreateVehicleSchema = z.object({
unit_number: z
.string()
.min(1, "Unit number must not be empty")
.max(50, "Unit number must not exceed 50 characters")
.trim()
.optional(),
plate: z
.string()
.min(1, "Plate must not be empty")
.max(20, "Plate must not exceed 20 characters")
.trim()
.regex(
/^[A-Z0-9-]+$/i,
"Plate can only contain letters, numbers, and hyphens",
)
.optional(),
is_active: z.boolean().optional().default(true),
driverId: z.uuid("Driver ID must be a valid UUID").optional(),
});

// Schema para actualizar un driver
export const UpdateVehicleSchema = z.object({
unit_number: z
.string()
.min(1, "Unit number must not be empty")
.max(50, "Unit number must not exceed 50 characters")
.trim()
.optional(),
plate: z
.string()
.min(1, "Plate must not be empty")
.max(20, "Plate must not exceed 20 characters")
.trim()
.regex(
/^[A-Z0-9-]+$/i,
"Plate can only contain letters, numbers, and hyphens",
)
.optional(),
is_active: z.boolean().optional(),
driverId: z.uuid("Driver ID must be a valid UUID").optional(),
});

// Exportar tipos inferidos
export type CreateVehicleDTO = z.infer<typeof CreateVehicleSchema>;
export type UpdateVehicleDTO = z.infer<typeof UpdateVehicleSchema>;
Loading