mirror of
https://github.com/andwati/order-service.git
synced 2026-11-03 09:42:14 +00:00
feat: implement authentication and product management services with validation schemas
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { AuthService } from "../services/auth.service";
|
||||
|
||||
export class AuthController {
|
||||
static async register(req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
|
||||
const user = await AuthService.register(email, password);
|
||||
|
||||
res.status(201).json(user);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
static async login(req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
|
||||
const result = await AuthService.login(email, password);
|
||||
|
||||
res.status(200).json(result);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { ProductService } from "../services/product.service";
|
||||
|
||||
export class ProductController {
|
||||
static async create(req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const product = await ProductService.create(req.body);
|
||||
res.status(201).json(product);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
static async list(_req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const products = await ProductService.list();
|
||||
res.status(200).json(products);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
static async update(req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const product = await ProductService.update(id, req.body);
|
||||
res.status(200).json(product);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import bcrypt from "bcrypt";
|
||||
import { UserModel } from "../models/user.model";
|
||||
import { signToken } from "../utils/jwt";
|
||||
|
||||
const SALT_ROUNDS = 10;
|
||||
|
||||
export class AuthService {
|
||||
static async register(email: string, password: string) {
|
||||
const existing = await UserModel.findOne({ email });
|
||||
if (existing) {
|
||||
throw { statusCode: 409, message: "Email already registered" };
|
||||
}
|
||||
|
||||
const passwordHash = await bcrypt.hash(password, SALT_ROUNDS);
|
||||
|
||||
const user = await UserModel.create({
|
||||
email,
|
||||
passwordHash,
|
||||
role: "customer",
|
||||
});
|
||||
|
||||
return {
|
||||
id: user._id,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
};
|
||||
}
|
||||
|
||||
static async login(email: string, password: string) {
|
||||
const user = await UserModel.findOne({ email });
|
||||
if (!user) {
|
||||
throw { statusCode: 401, message: "Invalid credentials" };
|
||||
}
|
||||
|
||||
const valid = await bcrypt.compare(password, user.passwordHash);
|
||||
if (!valid) {
|
||||
throw { statusCode: 401, message: "Invalid credentials" };
|
||||
}
|
||||
|
||||
const token = signToken({
|
||||
sub: user._id,
|
||||
role: user.role,
|
||||
});
|
||||
|
||||
return { token };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { ProductModel } from "../models/product.model";
|
||||
|
||||
export class ProductService {
|
||||
static async create(data: { name: string; price: number; stock: number }) {
|
||||
const product = await ProductModel.create(data);
|
||||
return product;
|
||||
}
|
||||
|
||||
static async list() {
|
||||
return ProductModel.find().lean();
|
||||
}
|
||||
|
||||
static async update(
|
||||
id: string,
|
||||
data: Partial<{ name: string; price: number; stock: number }>,
|
||||
) {
|
||||
const product = await ProductModel.findByIdAndUpdate(
|
||||
id,
|
||||
{ $set: data },
|
||||
{ new: true },
|
||||
);
|
||||
|
||||
if (!product) {
|
||||
throw { statusCode: 404, message: "Product not found" };
|
||||
}
|
||||
|
||||
return product;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const registerSchema = z.object({
|
||||
body: z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(8),
|
||||
}),
|
||||
});
|
||||
|
||||
export const loginSchema = z.object({
|
||||
body: z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(1),
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const createOrderSchema = z.object({
|
||||
body: z.object({
|
||||
items: z
|
||||
.array(
|
||||
z.object({
|
||||
productId: z.string().uuid(),
|
||||
quantity: z.number().int().positive(),
|
||||
}),
|
||||
)
|
||||
.min(1),
|
||||
}),
|
||||
});
|
||||
|
||||
export const orderIdParamSchema = z.object({
|
||||
params: z.object({
|
||||
id: z.string().uuid(),
|
||||
}),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user