For Frontend practice

This commit is contained in:
magdo
2026-03-21 20:39:18 +01:00
parent 8b8c08be1b
commit ad1e783472
68 changed files with 3817 additions and 0 deletions
@@ -0,0 +1,10 @@
class UserDTO {
constructor(user) {
this.id = user.id;
this.name = user.name;
this.email = user.email;
this.createdAt = user.createdAt;
}
}
module.exports = UserDTO;
@@ -0,0 +1,37 @@
const jwt = require("jsonwebtoken");
const env = require("../../config/env");
class AuthService {
constructor() {
this.cookieName = env.cookieName;
}
signToken(payload) {
return jwt.sign(payload, env.jwtSecret, { expiresIn: env.jwtExpiresIn });
}
verifyToken(token) {
return jwt.verify(token, env.jwtSecret);
}
cookieOptions() {
return {
httpOnly: true,
sameSite: "lax",
secure: env.cookieSecure,
path: "/",
maxAge: 7 * 24 * 60 * 60 * 1000
};
}
clearCookieOptions() {
return {
httpOnly: true,
sameSite: "lax",
secure: env.cookieSecure,
path: "/"
};
}
}
module.exports = AuthService;
@@ -0,0 +1,13 @@
const bcrypt = require("bcryptjs");
class PasswordService {
async hash(rawPassword) {
return bcrypt.hash(rawPassword, 10);
}
async compare(rawPassword, hash) {
return bcrypt.compare(rawPassword, hash);
}
}
module.exports = PasswordService;
@@ -0,0 +1,9 @@
class CreateOrderCommand {
constructor(payload) {
this.customer_name = payload.customer_name;
this.customer_email = payload.customer_email;
this.items = payload.items;
}
}
module.exports = CreateOrderCommand;
@@ -0,0 +1,11 @@
class CreateOrderCommandHandler {
constructor(shopRepository) {
this.shopRepository = shopRepository;
}
async handle(command) {
return this.shopRepository.createOrder(command);
}
}
module.exports = CreateOrderCommandHandler;
@@ -0,0 +1,12 @@
class CreateProductCommand {
constructor(payload) {
this.category_id = payload.category_id;
this.name = payload.name;
this.description = payload.description;
this.price = payload.price;
this.image_url = payload.image_url;
this.stock = payload.stock;
}
}
module.exports = CreateProductCommand;
@@ -0,0 +1,11 @@
class CreateProductCommandHandler {
constructor(shopRepository) {
this.shopRepository = shopRepository;
}
async handle(command) {
return this.shopRepository.createProduct(command);
}
}
module.exports = CreateProductCommandHandler;
@@ -0,0 +1,3 @@
class GetCategoriesQuery {}
module.exports = GetCategoriesQuery;
@@ -0,0 +1,11 @@
class GetCategoriesQueryHandler {
constructor(shopRepository) {
this.shopRepository = shopRepository;
}
async handle() {
return this.shopRepository.findCategories();
}
}
module.exports = GetCategoriesQueryHandler;
@@ -0,0 +1,3 @@
class GetProductsQuery {}
module.exports = GetProductsQuery;
@@ -0,0 +1,11 @@
class GetProductsQueryHandler {
constructor(shopRepository) {
this.shopRepository = shopRepository;
}
async handle() {
return this.shopRepository.findProducts();
}
}
module.exports = GetProductsQueryHandler;
@@ -0,0 +1,8 @@
class LoginUserCommand {
constructor(payload) {
this.email = payload.email;
this.password = payload.password;
}
}
module.exports = LoginUserCommand;
@@ -0,0 +1,37 @@
const PasswordService = require("../../Services/PasswordService");
const UserDTO = require("../../DTO/UserDTO");
class LoginUserCommandHandler {
constructor(userRepository, authService) {
this.userRepository = userRepository;
this.authService = authService;
this.passwordService = new PasswordService();
}
async handle(command) {
if (!command.email || !command.password) {
const error = new Error("email and password are required");
error.statusCode = 400;
throw error;
}
const user = await this.userRepository.findByEmail(command.email);
if (!user) {
const error = new Error("Invalid credentials");
error.statusCode = 401;
throw error;
}
const isValid = await this.passwordService.compare(command.password, user.passwordHash);
if (!isValid) {
const error = new Error("Invalid credentials");
error.statusCode = 401;
throw error;
}
const token = this.authService.signToken({ userId: user.id, email: user.email });
return { user: new UserDTO(user), token };
}
}
module.exports = LoginUserCommandHandler;
@@ -0,0 +1,7 @@
class LogoutUserCommand {
constructor(payload) {
this.userId = payload.userId;
}
}
module.exports = LogoutUserCommand;
@@ -0,0 +1,11 @@
class LogoutUserCommandHandler {
async handle(command) {
if (!command.userId) {
const error = new Error("Unauthorized");
error.statusCode = 401;
throw error;
}
}
}
module.exports = LogoutUserCommandHandler;
@@ -0,0 +1,9 @@
class RegisterUserCommand {
constructor(payload) {
this.name = payload.name;
this.email = payload.email;
this.password = payload.password;
}
}
module.exports = RegisterUserCommand;
@@ -0,0 +1,37 @@
const PasswordService = require("../../Services/PasswordService");
const UserDTO = require("../../DTO/UserDTO");
class RegisterUserCommandHandler {
constructor(userRepository, authService) {
this.userRepository = userRepository;
this.authService = authService;
this.passwordService = new PasswordService();
}
async handle(command) {
if (!command.name || !command.email || !command.password) {
const error = new Error("name, email and password are required");
error.statusCode = 400;
throw error;
}
const existing = await this.userRepository.findByEmail(command.email);
if (existing) {
const error = new Error("Email already in use");
error.statusCode = 409;
throw error;
}
const passwordHash = await this.passwordService.hash(command.password);
const user = await this.userRepository.create({
name: command.name,
email: command.email,
passwordHash
});
const token = this.authService.signToken({ userId: user.id, email: user.email });
return { user: new UserDTO(user), token };
}
}
module.exports = RegisterUserCommandHandler;
@@ -0,0 +1,7 @@
class GetCurrentUserQuery {
constructor(payload) {
this.userId = payload.userId;
}
}
module.exports = GetCurrentUserQuery;
@@ -0,0 +1,26 @@
const UserDTO = require("../../DTO/UserDTO");
class GetCurrentUserQueryHandler {
constructor(userRepository) {
this.userRepository = userRepository;
}
async handle(query) {
if (!query.userId) {
const error = new Error("Unauthorized");
error.statusCode = 401;
throw error;
}
const user = await this.userRepository.findById(query.userId);
if (!user) {
const error = new Error("User not found");
error.statusCode = 404;
throw error;
}
return new UserDTO(user);
}
}
module.exports = GetCurrentUserQueryHandler;