From f3da7d1d20035fbebf8e88dc59e1a065e5ff64b5 Mon Sep 17 00:00:00 2001 From: Florian LEROUX Date: Mon, 15 Jan 2024 00:43:53 +0100 Subject: [PATCH 1/3] feat(#42): add restaurant users endpoint --- .../restaurant/restaurant.controller.ts | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/services/gateway/src/controller/restaurant/restaurant.controller.ts b/services/gateway/src/controller/restaurant/restaurant.controller.ts index 8f300176..13bfe491 100644 --- a/services/gateway/src/controller/restaurant/restaurant.controller.ts +++ b/services/gateway/src/controller/restaurant/restaurant.controller.ts @@ -11,6 +11,8 @@ import { Address, } from "@gateway/proto/restaurant_pb"; import { withCheck } from "@gateway/middleware/auth"; +import { getUser, getUserIdFromToken } from "@gateway/services/user.service"; +import { User } from "@gateway/proto/user_pb"; export const restaurantRoutes = Router(); @@ -28,6 +30,63 @@ restaurantRoutes.get("/api/restaurant/:id", (req: Request, res: Response) => { }); }); +restaurantRoutes.get("/api/restaurant/:id/users", async (req: Request, res: Response) => { + /* #swagger.parameters['id'] = { + in: 'path', + required: true, + type: 'string' + } + #swagger.parameters['authorization'] = { + in: 'header', + required: true, + type: 'string' + } + */ + // Auth check and :id check --- + const { authorization } = req.headers; + if (!authorization) return res.status(401).json({ message: "Unauthorized" }); + const token = authorization.split("Bearer ")[1]; + const userId = await getUserIdFromToken(token); + if (!userId) return res.status(401).json({ message: "Unauthorized" }); + const user = await getUser(userId); + if (!user) return res.status(401).json({ message: "Unauthorized" }); + + const role = user.getRole()?.getCode(); + if (role === undefined) return res.status(401).json({ message: "Unauthorized" }); + if (role !== "ADMIN" && role !== "MANAGER") return res.status(401).json({ message: "Unauthorized" }); + // ---------------------------- + + const { id } = req.params; + + try { + const restaurant = (await new Promise((resolve, reject) => { + restaurantServiceClient.getRestaurant(new RestaurantId().setId(id), (error, response) => { + if (error) reject(error); + else resolve(response.toObject()); + }); + })) as Restaurant.AsObject; + if (!restaurant) return res.status(404).json({ message: "Restaurant not found" }); + if (!restaurant.useridsList.includes(userId) || role !== "ADMIN") + return res.status(401).json({ message: "Unauthorized" }); + + const users = await Promise.all( + restaurant.useridsList.map(async (userId) => await getUser(userId).catch(() => undefined)), + ); // TODO (maybe): create user service method to get multiple users + + return res.status(200).json({ + usersList: (users.filter(Boolean) as User[]).map((u) => ({ + id: u.getId(), + email: u.getEmail(), + firstname: u.getFirstName(), + lastname: u.getLastName(), + role: u.getRole()?.toObject(), + })), // to match list responses + }); + } catch (error) { + return res.status(500).json({ error }); + } +}); + restaurantRoutes.get("/api/restaurant", (_: Request, res: Response) => { restaurantServiceClient.getRestaurants(new Empty(), (error, response) => { if (error) return res.status(500).send({ error }); From b29c16890a24fdaa98bfe750797864d68666bf65 Mon Sep 17 00:00:00 2001 From: Florian LEROUX Date: Mon, 15 Jan 2024 00:44:05 +0100 Subject: [PATCH 2/3] ref(bruno): update requests --- requests/restaurant/create restaurant.bru | 18 +++++++++--------- requests/restaurant/get restaurant users.bru | 15 +++++++++++++++ services/gateway/.gitignore | 3 +++ 3 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 requests/restaurant/get restaurant users.bru diff --git a/requests/restaurant/create restaurant.bru b/requests/restaurant/create restaurant.bru index 89adbff8..762b34f6 100644 --- a/requests/restaurant/create restaurant.bru +++ b/requests/restaurant/create restaurant.bru @@ -20,16 +20,16 @@ auth:bearer { body:json { { - - "name": "restaurant-name", + + "name": "Les champs", "description": "restaurant-desc", "address": { - "street": "restaurant-street", - "city": "restaurant-city", - "zipCode": "restaurant-postalCode", - "country": "restaurant-country", - "lat": 49.443, - "lng": 1.099 + "street": "9 rue des champs", + "city": "Saint Ouen de Thouberville", + "zipCode": "27310", + "country": "France", + "lat": 49.3573604, + "lng": 0.889712 }, "openingHoursList": [ "12h-14h", @@ -37,7 +37,7 @@ body:json { ], "phone": "restaurant-phone", "userIds": [ - "user-id-1", + "54ed8c99-ccc1-4ebb-8032-73f432ced687", "user-id-2" ] } diff --git a/requests/restaurant/get restaurant users.bru b/requests/restaurant/get restaurant users.bru new file mode 100644 index 00000000..3b420e22 --- /dev/null +++ b/requests/restaurant/get restaurant users.bru @@ -0,0 +1,15 @@ +meta { + name: get restaurant users + type: http + seq: 7 +} + +get { + url: {{baseUrl}}/api/restaurant/clre4oqjv000014eblvk1mkyw/users + body: none + auth: bearer +} + +auth:bearer { + token: {{token}} +} diff --git a/services/gateway/.gitignore b/services/gateway/.gitignore index 44a16cb0..8cd6c432 100644 --- a/services/gateway/.gitignore +++ b/services/gateway/.gitignore @@ -5,3 +5,6 @@ bin/ !*.env.example !*.env.docker src/proto/* + +.nyc_output/ +coverage/ From b62696abde9cdffc9e8012424f1859892c666d53 Mon Sep 17 00:00:00 2001 From: Florian LEROUX Date: Mon, 15 Jan 2024 00:44:43 +0100 Subject: [PATCH 3/3] Refactor stock controller routes --- .../src/controller/stock/stock.controller.ts | 94 ++++++++----------- 1 file changed, 40 insertions(+), 54 deletions(-) diff --git a/services/gateway/src/controller/stock/stock.controller.ts b/services/gateway/src/controller/stock/stock.controller.ts index 4673d780..25844714 100644 --- a/services/gateway/src/controller/stock/stock.controller.ts +++ b/services/gateway/src/controller/stock/stock.controller.ts @@ -36,11 +36,8 @@ export const stockRoutes = Router(); * Ingredient Routes */ -stockRoutes.get( - "/api/stock/supplier/:id", - withCheck({ role: ["MANAGER", "ADMIN"] }), - (req: Request, res: Response) => { - /* #swagger.parameters['id'] = { +stockRoutes.get("/api/stock/supplier/:id", withCheck({ role: ["MANAGER", "ADMIN"] }), (req: Request, res: Response) => { + /* #swagger.parameters['id'] = { in: 'path', required: true, type: 'integer' @@ -50,15 +47,14 @@ stockRoutes.get( required: true, type: 'string' } */ - const { id } = req.params; - const supplierRequest = new GetSupplierRequest().setId(Number(id)); + const { id } = req.params; + const supplierRequest = new GetSupplierRequest().setId(Number(id)); - stockServiceClient.getSupplier(supplierRequest, (error, response) => { - if (error) return res.status(500).send({ error }); - else return res.status(200).json(response.toObject()); - }); - }, -); + stockServiceClient.getSupplier(supplierRequest, (error, response) => { + if (error) return res.status(500).send({ error }); + else return res.status(200).json(response.toObject()); + }); +}); stockRoutes.get("/api/stock/supplier", withCheck({ role: ["MANAGER", "ADMIN"] }), (_: Request, res: Response) => { /* #swagger.parameters['authorization'] = { @@ -111,11 +107,8 @@ stockRoutes.get("/api/stock/ingredient", withCheck({ role: ["MANAGER", "ADMIN"] }); }); -stockRoutes.post( - "/api/stock/ingredient", - withCheck({ role: ["MANAGER", "ADMIN"] }), - (req: Request, res: Response) => { - /* #swagger.parameters['body'] = { +stockRoutes.post("/api/stock/ingredient", withCheck({ role: ["MANAGER", "ADMIN"] }), (req: Request, res: Response) => { + /* #swagger.parameters['body'] = { in: 'body', required: true, schema: { @@ -129,15 +122,14 @@ stockRoutes.post( type: 'string' } */ - const { name, description } = req.body; - const ingredientRequest = new CreateIngredientRequest().setName(name).setDescription(description); + const { name, description } = req.body; + const ingredientRequest = new CreateIngredientRequest().setName(name).setDescription(description); - stockServiceClient.createIngredient(ingredientRequest, (error, response) => { - if (error) return res.status(500).send({ error }); - else return res.status(201).json(response.toObject()); - }); - }, -); + stockServiceClient.createIngredient(ingredientRequest, (error, response) => { + if (error) return res.status(500).send({ error }); + else return res.status(201).json(response.toObject()); + }); +}); stockRoutes.put( "/api/stock/ingredient/:id", @@ -354,7 +346,8 @@ stockRoutes.post( if (!userId) return res.status(401).json({ message: "Unauthorized" }); // ---------------------------- - const { alertThreshold, quantity, productList, unitPrice, pricePerKilo, restaurantId, ingredientId, supplierId } = req.body; + const { alertThreshold, quantity, productList, unitPrice, pricePerKilo, restaurantId, ingredientId, supplierId } = + req.body; const ingredientRestaurant = new CreateIngredientRestaurantRequest() .setAlertThreshold(alertThreshold) .setQuantity(quantity) @@ -425,7 +418,8 @@ stockRoutes.put( if (!userId) return res.status(401).json({ message: "Unauthorized" }); // ---------------------------- const { id } = req.params; - const { alertThreshold, quantity, productList, unitPrice, pricePerKilo, restaurantId, ingredientId, supplierId } = req.body; + const { alertThreshold, quantity, productList, unitPrice, pricePerKilo, restaurantId, ingredientId, supplierId } = + req.body; const ingredientRestaurant = new UpdateIngredientRestaurantRequest() .setId(Number(id)) .setAlertThreshold(alertThreshold) @@ -526,11 +520,8 @@ stockRoutes.delete( * Supplier Routes */ -stockRoutes.get( - "/api/stock/supplier/:id", - withCheck({ role: ["MANAGER", "ADMIN"] }), - (req: Request, res: Response) => { - /* #swagger.parameters['id'] = { +stockRoutes.get("/api/stock/supplier/:id", withCheck({ role: ["MANAGER", "ADMIN"] }), (req: Request, res: Response) => { + /* #swagger.parameters['id'] = { in: 'path', required: true, type: 'integer' @@ -541,14 +532,13 @@ stockRoutes.get( type: 'string' } */ - const { id } = req.params; + const { id } = req.params; - stockServiceClient.getSupplier(new GetSupplierRequest().setId(Number(id)), (error, response) => { - if (error) return res.status(500).send({ error }); - else return res.status(200).json(response.toObject()); - }); - }, -); + stockServiceClient.getSupplier(new GetSupplierRequest().setId(Number(id)), (error, response) => { + if (error) return res.status(500).send({ error }); + else return res.status(200).json(response.toObject()); + }); +}); stockRoutes.get("/api/stock/supplier", withCheck({ role: ["MANAGER", "ADMIN"] }), (req: Request, res: Response) => { /* #swagger.parameters['authorization'] = { @@ -587,11 +577,8 @@ stockRoutes.post("/api/stock/supplier", withCheck({ role: ["MANAGER", "ADMIN"] } }); }); -stockRoutes.put( - "/api/stock/supplier/:id", - withCheck({ role: ["MANAGER", "ADMIN"] }), - (req: Request, res: Response) => { - /* #swagger.parameters['id'] = { +stockRoutes.put("/api/stock/supplier/:id", withCheck({ role: ["MANAGER", "ADMIN"] }), (req: Request, res: Response) => { + /* #swagger.parameters['id'] = { in: 'path', required: true, type: 'integer' @@ -610,16 +597,15 @@ stockRoutes.put( type: 'string' } */ - const { id } = req.params; - const { name, contact } = req.body; - const supplierRequest = new UpdateSupplierRequest().setId(Number(id)).setName(name).setContact(contact); + const { id } = req.params; + const { name, contact } = req.body; + const supplierRequest = new UpdateSupplierRequest().setId(Number(id)).setName(name).setContact(contact); - stockServiceClient.updateSupplier(supplierRequest, (error, response) => { - if (error) return res.status(500).send({ error }); - else return res.status(200).json(response.toObject()); - }); - }, -); + stockServiceClient.updateSupplier(supplierRequest, (error, response) => { + if (error) return res.status(500).send({ error }); + else return res.status(200).json(response.toObject()); + }); +}); stockRoutes.delete( "/api/stock/supplier/:id",