For Frontend practice
This commit is contained in:
@@ -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;
|
||||
Reference in New Issue
Block a user