Skip to content
This repository has been archived by the owner on Feb 4, 2024. It is now read-only.

Product categories #238

Merged
merged 11 commits into from
Apr 7, 2022
5 changes: 5 additions & 0 deletions restapi/products/Product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export const product = new Schema(
type: String,
required: false,
},
category: {
type:String,
required: true,
enum: ['Clothes', 'Decoration', 'Electronics', 'Miscellaneous']
}
},
{
versionKey: false,
Expand Down
28 changes: 28 additions & 0 deletions restapi/products/ProductController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,31 @@ export const updateProduct: RequestHandler = async (req, res) => {
res.status(403).json();
}
};

export const filterAndOrderBy: RequestHandler = async (req, res) => {
let mode = req.params.mode;
const category = req.params.category;
let products;

if (
category !== "Clothes" &&
category !== "Decoration" &&
category !== "Electronics" &&
category !== "Miscellaneous"
) {
if (mode !== "asc" && mode !== "desc") {
products = await productModel.find();
} else {
products = await productModel.find().sort({ price: mode });
}
} else {
if (mode !== "asc" && mode !== "desc") {
products = await productModel.find({ category: category });
} else {
products = await productModel
.find({ category: category })
.sort({ price: mode });
}
}
return res.json(products);
};
6 changes: 4 additions & 2 deletions restapi/products/ProductRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import express, { Request, Response, Router } from "express";
import express, { Router } from "express";
import multer from "../utils/multer";
import * as ProdctController from "./ProductController";

import multer from "../utils/multer";

const api: Router = express.Router();

api.get("/products", ProdctController.getProducts);

api.get("/products/findByCode/:code", ProdctController.getProduct);

api.get('/products/filter&order/:category&:mode', ProdctController.filterAndOrderBy)

api.post("/products", multer.single("image"), ProdctController.createProduct);

api.post("/products/delete/:code", ProdctController.deleteProduct);
Expand Down
12 changes: 9 additions & 3 deletions restapi/products/product.http
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
GET {{url}}/products/list

###
GET {{url}}/products/findByCode/1
GET {{url}}/products/findByCode/0007

###
POST {{url}}/products/create
Expand All @@ -21,9 +21,15 @@ Content-Type: application/json
DELETE {{url}}/products/delete/1

###
POST {{url}}/products/update/1347
POST {{url}}/products/update/0045
Content-Type: application/json

{
"name": "Camiseta del Sporting chacho"
"category": "Miscellaneous"
}

###
GET {{url}}/products/order/desc

###
GET {{url}}/products/filter&order/Electronics&asc
1 change: 1 addition & 0 deletions restapi/tests/orders.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ describe("orders", () => {
"Do you wanna show your friends that you are THE GREATEST IMPOSTER? Then this shirt is for you!",
stock: 1,
image: "0001.png",
category: "Clothes",
},
],
date: new Date(),
Expand Down
86 changes: 78 additions & 8 deletions restapi/tests/products.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ describe("prodcuts", () => {
name: "Super SUS T-Shirt",
price: 9.5,
image: "0001.png",
category: "Clothes",
})
);
});
Expand All @@ -91,6 +92,7 @@ describe("prodcuts", () => {
price: 0.99,
description: "Another test product",
stock: 0,
category: "Clothes",
});
expect(response.statusCode).toBe(403);
});
Expand All @@ -110,6 +112,7 @@ describe("prodcuts", () => {
price: 0.99,
description: "Another test product",
stock: 0,
category: "Clothes",
});
expect(response.statusCode).toBe(200);
expect(response.body.name).toBe("testProduct");
Expand All @@ -128,6 +131,7 @@ describe("prodcuts", () => {
price: 0.99,
description: "A failure insert test product",
stock: 0,
category: "Clothes",
});
expect(response.statusCode).toBe(409);
});
Expand All @@ -144,30 +148,49 @@ describe("prodcuts", () => {
expect(response.statusCode).toBe(412);
});

it("Can't create a product with incorrect or missing category", async () => {
let userToken = await getToken();
const response: Response = await request(app)
.post("/products")
.set("token", userToken)
.set("email", "test")
.send({
code: uuidv4(),
name: "testFailProduct",
price: 0.99,
description: "A failure insert test product",
stock: 0,
category: "Nothing",
});
expect(response.statusCode).toBe(412);
});

it("Can update a product correctly", async () => {
let userToken = await getToken();
const response: Response = await request(app)
.post("/products/update/" + productCode)
.set("token", userToken)
.set("email", "test")
.send({
stock: 1000,
stock: 10,
});
expect(response.statusCode).toBe(200);
expect(response.body.stock).toBe(1000);
expect(response.body.stock).toBe(10);
});

it("Can't update a product without being admin or manager", async () => {
const token: Response = await request(app).post("/users/requestToken/").send({
email: "test1",
password: "test",
});
const token: Response = await request(app)
.post("/users/requestToken/")
.send({
email: "test1",
password: "test",
});
const response: Response = await request(app)
.post("/products/update/" + productCode)
.set("token", token.body)
.set("email", "test1")
.send({
stock: 1000,
stock: 10,
});
expect(response.statusCode).toBe(403);
});
Expand All @@ -176,7 +199,7 @@ describe("prodcuts", () => {
const response: Response = await request(app)
.post("/products/update/" + productCode)
.send({
stock: 1000,
stock: 10,
});
expect(response.statusCode).toBe(403);
});
Expand All @@ -197,6 +220,53 @@ describe("prodcuts", () => {
.send();
expect(response.statusCode).toBe(403);
});

/*
Testing filtering and ordering products
*/
it("Can filter by category", async () => {
const response: Response = await request(app)
.get("/products/filter&order/Electronics&A")
.send();
expect(response.statusCode).toBe(200);
expect(response.body).toEqual(
expect.arrayContaining([
expect.objectContaining({ category: "Electronics" }),
])
);
});

it("Can filter by category and order by price", async () => {
const response: Response = await request(app)
.get("/products/filter&order/Electronics&asc")
.send();
expect(response.statusCode).toBe(200);
expect(response.body).toEqual(
expect.arrayContaining([
expect.objectContaining({ category: "Electronics" }),
])
);
expect(response.body[0].price).toBe(20.99);
});

it("Can order by price", async () => {
const response: Response = await request(app)
.get("/products/filter&order/Category&asc")
.send();
expect(response.statusCode).toBe(200);
expect(response.body[0].price).toBe(1.99);
});

it("Check normal order when 'wrong' input", async () => {
const response: Response = await request(app)
.get("/products/filter&order/a&a")
.send();
expect(response.statusCode).toBe(200);
expect(response.body[0].price).toBe(12.95);
expect(response.body[0].code).toBe("1234");
expect(response.body[1].price).toBe(9.5);
expect(response.body[1].code).toBe("0001");
});
});

async function getToken() {
Expand Down
29 changes: 6 additions & 23 deletions restapi/utils/PDFHelper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { orderModel } from "../orders/Order";
import { userModel } from "../users/User";
import { sendInvoiceEmail } from "./emailSender";

const fs = require("fs");
const PDFGenerator = require("pdfkit");
Expand All @@ -11,7 +11,7 @@ export const createPDF = async (code: string) => {
const orderFound = await orderModel.findOne({
orderCode: code,
});
const user = await userModel.findOne({ email: orderFound.userEmail });
/*const user = await userModel.findOne({ email: orderFound.userEmail });
const invoiceData = {
addresses: {
shipping: {
Expand All @@ -29,27 +29,17 @@ export const createPDF = async (code: string) => {
};

const ig = new InvoiceGenerator(invoiceData);
ig.generate();

/*var html = fs.readFileSync(process.cwd() + "/utils/template.html", "utf-8");
ig.generate();*/
var html = fs.readFileSync(process.cwd() + "/utils/template.html", "utf-8");
const parse = require("node-html-parser").parse;

const options: CreateOptions = {
format: "A4",
orientation: "portrait",
};

const orderFound = await orderModel.findOne({
orderCode: code,
});

const root = parse(html);
const body = root.querySelector("body");
let aux =
'<header class="clearfix">' +
'<div id="company">' +
'<h2 class="name">DeDe</h2>' +
'<div><a href="mailto:[email protected]">[email protected]</a></div>' +
'<div><a href="mailto:[email protected]">[email protected]</a></div><br><br>' +
"</div> </div>" +
"</header>" +
"<main>" +
Expand Down Expand Up @@ -146,12 +136,5 @@ export const createPDF = async (code: string) => {

body.insertAdjacentHTML("beforeend", aux);

pdf
.create(root.toString(), options)
.toFile("./pdf/" + orderFound.orderCode + ".pdf", function (err, res) {
if (err) console.log(err);
else {
sendInvoiceEmail(orderFound.userEmail, orderFound.orderCode);
}
});*/
sendInvoiceEmail(orderFound.userEmail, orderFound.orderCode, root.toString());
};
20 changes: 12 additions & 8 deletions restapi/utils/emailSender.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

const nodemailer = require("nodemailer");
const { v4: uuidv4 } = require("uuid");
const fs = require("fs");
Expand All @@ -12,31 +11,36 @@ sgMail.setApiKey(

export const sendInvoiceEmail: Function = (
email: string,
orderCode: string
orderCode: string,
message: string
) => {
const pathToAttachment = `${__dirname}/pdf/` + orderCode + ".pdf";
const attachment = fs.readFileSync(pathToAttachment).toString("base64");
/*const pathToAttachment = `${__dirname}/pdf/` + orderCode + ".pdf";
const attachment = fs.readFileSync(pathToAttachment).toString("base64");*/

const mailOptions = {
to: email,
from: process.env.AUTH_EMAIL,
subject: "DeDe Order Invoice",
html:
"<p>Thank you for trusting in DeDe and buying with us.<br><br>Here you have the receipt of your purchase." +
"<br><br>We hope to see you soon :)</p>",
attachments: [
"<br><br>We hope to see you soon :)</p><br><br><br><br><br>" +
message,
/*attachments: [
{
content: attachment,
filename: orderCode + ".pdf",
type: "application/pdf",
disposition: "attachment",
},
],
],*/
};
sgMail.send(mailOptions);
};

export const sendVerificationEmail: Function = async (email: string, uniqueString: string) => {
export const sendVerificationEmail: Function = async (
email: string,
uniqueString: string
) => {
const currentUrl = "http://localhost:5000";

const mailOptions = {
Expand Down
Loading