Skip to content

Commit

Permalink
Merge pull request #314 from Benson-Ogheneochuko/feat/create-product
Browse files Browse the repository at this point in the history
fix: fixed conflict
  • Loading branch information
incredible-phoenix246 authored Jul 25, 2024
2 parents 924d396 + 568e65e commit c8d5af8
Show file tree
Hide file tree
Showing 6 changed files with 358 additions and 65 deletions.
41 changes: 40 additions & 1 deletion src/controllers/ProductController.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Request, Response } from "express";
import { ProductService } from "../services/product.services"; // Adjust the import path as necessary
import { ProductDTO } from "../models";

export class ProductController {
private productService: ProductService;
Expand Down Expand Up @@ -482,7 +483,45 @@ export class ProductController {
* message:
* type: string
*/
async createProduct(req: Request, res: Response) {}
async createProduct(req: Request, res: Response) {
try {
const { user } = req;
const { sanitizedData } = req.body;

if (!user) {
return res.status(401).json({
status: "unsuccessful",
status_code: 401,
message: "Unauthorized User",
});
}

const productDTO = new ProductDTO(sanitizedData);
await productDTO.validate();

const product = await this.productService.createProduct({
...sanitizedData,
user,
});

const { user: _, ...productWithoutUser } = product;

return res.status(201).json({
status: "success",
status_code: 201,
message: "Product created successfully",
data: { productWithoutUser },
});
} catch (error) {
// console.error('Error creating product:', error)
return res.status(500).json({
status: "unsuccessful",
status_code: 500,
message: "Internal server error",
error: error instanceof Error ? error.message : "Unknown error",
});
}
}

/**
* @swagger
Expand Down
16 changes: 16 additions & 0 deletions src/middleware/product.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Request, Response, NextFunction } from "express";

import { body, validationResult } from "express-validator";
// Middleware to validate and sanitize product details
export const validateProductDetails = [
body("name").trim().escape(),
body("description").trim().escape(),
body("category").trim().escape(),
(req: Request, res: Response, next: NextFunction) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
},
];
40 changes: 40 additions & 0 deletions src/models/product.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from "typeorm";
import { User } from "./user";
import ExtendedBaseEntity from "./extended-base-entity";
import {
IsString,
IsNumber,
IsPositive,
MinLength,
validateOrReject,
IsNotEmpty,
} from "class-validator";

/**
* @swagger
Expand Down Expand Up @@ -51,3 +59,35 @@ export class Product extends ExtendedBaseEntity {
@ManyToOne(() => User, (user) => user.products)
user: User;
}

export class ProductDTO {
@IsString({ message: "Name must be a string" })
@IsNotEmpty({ message: "Name must not be empty" })
@MinLength(1, { message: "Name must not be empty" })
name: string;

@IsString({ message: "Description must be a string" })
@IsNotEmpty({ message: "Description must not be empty" })
@MinLength(1, { message: "Description must not be empty" })
description: string;

@IsNumber({}, { message: "Price must be a number" })
@IsPositive({ message: "Price must be positive" })
price: number;

@IsString({ message: "Category must be a string" })
@IsNotEmpty({ message: "Category must not be empty" })
@MinLength(1, { message: "Category must not be empty" })
category: string;

async validate() {
await validateOrReject(this, {
validationError: { target: false, value: true },
skipMissingProperties: false,
});
}

constructor(data: Partial<ProductDTO>) {
Object.assign(this, data);
}
}
19 changes: 13 additions & 6 deletions src/routes/product.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import express from "express";
import ProductController from "../controllers/ProductController";
import { authMiddleware } from "../middleware";
import { validateProductDetails } from "../middleware/product";

const productRouter = express.Router();
const productController = new ProductController();
Expand Down Expand Up @@ -88,12 +89,18 @@ productRouter.get(
"/",
authMiddleware,
productController.getProductPagination.bind(productController),

productRouter.get(
"/:product_id",
authMiddleware,
productController.fetchProductById,
),
);

productRouter.get(
"/:product_id",
authMiddleware,
productController.fetchProductById,
);
productRouter
.route("/")
.post(
validateProductDetails,
authMiddleware,
productController.createProduct.bind(productController),
);
export { productRouter };
12 changes: 10 additions & 2 deletions src/services/product.services.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Product } from "../models/product";
import { IProduct } from "../types";
import AppDataSource from "../data-source";
import { ProductDTO } from "../models/product";

export class ProductService {
getPaginatedProducts(
Expand Down Expand Up @@ -55,9 +56,16 @@ export class ProductService {
throw new Error(err.message);
}
}
async getOneProduct(id: string): Promise<Product> {
const product = await this.productRepository.findOneBy({ id });

public async createProduct(
productDetails: Partial<ProductDTO>,
): Promise<Product> {
const product = this.productRepository.create(productDetails);
return await this.productRepository.save(product);
}

public async getOneProduct(id: string): Promise<Product> {
const product = await this.productRepository.findOne({ where: { id } });
return product;
}
}
Loading

0 comments on commit c8d5af8

Please sign in to comment.