diff --git a/app.js b/app.js index fd112be..75c6f1a 100644 --- a/app.js +++ b/app.js @@ -4,6 +4,7 @@ import userRoute from "./src/routes/user.route.js"; import adminRoute from "./src/routes/admin.route.js"; import rootRoute from "./src/routes/root.route.js"; import authRoute from "./src/routes/auth.route.js"; +import reviewRoute from "./src/routes/review.route.js"; import touristAttractionRoute from "./src/routes/touristAttraction.route.js"; import cors from 'cors'; import swaggerRoute from "./src/routes/swagger/swagger.route.js" @@ -33,6 +34,7 @@ app.use(express.json()); app.use("/admin", adminRoute); app.use("/user", userRoute); app.use("/auth", authRoute); +app.use("/reviews", reviewRoute); app.use("/touristAttraction", touristAttractionRoute); app.use("/", rootRoute); app.use("/docs", swaggerRoute); diff --git a/src/controller/review.controller.js b/src/controller/review.controller.js new file mode 100644 index 0000000..0ab2761 --- /dev/null +++ b/src/controller/review.controller.js @@ -0,0 +1,58 @@ +import reviewService from "../services/review.service.js"; +import jwt from'jsonwebtoken'; +import bcrypt from 'bcrypt'; + +const createReview = async (req, res) => { + try { + const {rating} = req.body; + const {TouristAttractionId} = req.params; + + if (!rating) { + return res.status(400).json({ error: "Please provide rating" }); + + } + let token = req.headers.authorization; + token = token.replace('Bearer ', ''); + const decoded = jwt.verify(token, process.env.SECRET_JWT_KEY); + const userId = decoded.id; + + const reviewData = { userId, TouristAttractionId, rating }; + const review = await reviewService.createReview(reviewData); + + res.status(201).json(review); + } catch (error) { + return res.status(500).json({ error: error.message }); + } +}; + +const getUserReviews = async (req, res) => { + try { + let token = req.headers.authorization; + token = token.replace('Bearer ', ''); + const decoded = jwt.verify(token, process.env.SECRET_JWT_KEY); + const userId = decoded.id; + + const reviews = await reviewService.getUserReviews(userId); + res.status(200).json(reviews); + } catch (error) { + return res.status(500).json({ error: error.message }); + } +}; + +const deleteReview = async (req, res) => { + try { + const { reviewId } = req.params; + const review = await reviewService.deleteReview(reviewId); + + if (!review) { + return res.status(404).json({ error: "Review not found" }); + } + + res.status(200).json({ message: "Review deleted successfully" }); + } catch (error) { + return res.status(500).json({ error: error.message }); + } +}; + + +export default { createReview, getUserReviews, deleteReview }; diff --git a/src/models/Review.js b/src/models/Review.js new file mode 100644 index 0000000..892ed17 --- /dev/null +++ b/src/models/Review.js @@ -0,0 +1,24 @@ +import mongoose from 'mongoose'; + +const ReviewSchema = new mongoose.Schema({ + userId: { + type: String, + ref: 'User', + required: true + }, + TouristAttractionId: { + type: String, + ref: 'TouristAttraction', + required: true + }, + rating: { + type: Number, + required: true, + min: 1, + max: 5 + }, + +}); + +const Review = mongoose.model("Review", ReviewSchema); +export default Review; diff --git a/src/routes/review.route.js b/src/routes/review.route.js new file mode 100644 index 0000000..3454c09 --- /dev/null +++ b/src/routes/review.route.js @@ -0,0 +1,15 @@ +import express from 'express'; +import reviewController from '../controller/review.controller.js'; +import { validToken } from "../middlewares/jwt.token.middleware.js"; + +const route = express.Router(); + +route.post('/:TouristAttractionId', validToken, reviewController.createReview); + +route.get('/user', validToken, reviewController.getUserReviews); + +route.delete('/:reviewId', validToken, reviewController.deleteReview); + +// route.get('/tourist-attraction/:TouristAttractionId', reviewController.getReviewsByTouristAttractionId); + +export default route; diff --git a/src/routes/swagger/swagger.js b/src/routes/swagger/swagger.js index 875afa6..3be0dbc 100644 --- a/src/routes/swagger/swagger.js +++ b/src/routes/swagger/swagger.js @@ -611,6 +611,168 @@ export default { }, }, }, + "/reviews/{TouristAttractionId}": { + post: { + summary: "Cria uma nova avaliação", + description: "Cria uma nova avaliação para uma atração turística específica", + operationId: "createReview", + parameters: [ + { + name: "TouristAttractionId", + in: "path", + required: true, + description: "ID da atração turística", + schema: { + type: "string", + }, + }, + ], + requestBody: { + required: true, + content: { + "application/json": { + schema: { + type: "object", + properties: { + rating: { + type: "number", + description: "Classificação da atração turística", + minimum: 1, + maximum: 5, + }, + }, + required: ["rating"], + }, + examples: { + review: { + summary: "Exemplo de avaliação", + value: { + rating: 4, + }, + }, + }, + }, + }, + }, + responses: { + 201: { + description: "Avaliação criada com sucesso", + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/Review", + }, + }, + }, + }, + 400: { + description: "Dados inválidos", + }, + }, + security: [ + { + bearerAuth: [], + }, + ], + }, + }, + // "/reviews/tourist-attraction/{TouristAttractionId}": { + // get: { + // summary: "Obtém avaliações por atração turística", + // description: "Obtém todas as avaliações para uma atração turística específica", + // operationId: "getReviewsByTouristAttractionId", + // parameters: [ + // { + // name: "TouristAttractionId", + // in: "path", + // required: true, + // description: "ID da atração turística", + // schema: { + // type: "string", + // }, + // }, + // ], + // responses: { + // 200: { + // description: "Lista de avaliações", + // content: { + // "application/json": { + // schema: { + // type: "array", + // items: { + // $ref: "#/components/schemas/Review", + // }, + // }, + // }, + // }, + // }, + // 404: { + // description: "Avaliações não encontradas", + // }, + // }, + // }, + // }, + "/reviews/user": { + get: { + summary: "Obtém avaliações do usuário", + description: "Obtém todas as avaliações feitas pelo usuário autenticado", + operationId: "getUserReviews", + responses: { + 200: { + description: "Lista de avaliações do usuário", + content: { + "application/json": { + schema: { + type: "array", + items: { + $ref: "#/components/schemas/Review", + }, + }, + }, + }, + }, + 401: { + description: "Token não fornecido ou inválido", + }, + }, + security: [ + { + bearerAuth: [], + }, + ], + }, + }, + "/reviews/{reviewId}": { + delete: { + summary: "Deleta uma avaliação", + description: "Deleta uma avaliação específica pelo ID", + operationId: "deleteReview", + parameters: [ + { + name: "reviewId", + in: "path", + required: true, + description: "ID da avaliação", + schema: { + type: "string", + }, + }, + ], + responses: { + 200: { + description: "Avaliação deletada com sucesso", + }, + 404: { + description: "Avaliação não encontrada", + }, + }, + security: [ + { + bearerAuth: [], + }, + ], + }, + }, }, components: { securitySchemes: { @@ -690,6 +852,26 @@ export default { }, }, }, + Review: { + type: "object", + properties: { + userId: { + type: "string", + description: "ID do usuário que fez a avaliação", + }, + TouristAttractionId: { + type: "string", + description: "ID da atração turística avaliada", + }, + rating: { + type: "number", + description: "Classificação da atração turística", + minimum: 1, + maximum: 5, + }, + }, + required: ["userId", "TouristAttractionId", "rating"], + }, }, }, }, diff --git a/src/routes/user.route.js b/src/routes/user.route.js index 58d9886..fae6028 100644 --- a/src/routes/user.route.js +++ b/src/routes/user.route.js @@ -10,7 +10,6 @@ route.get('/:id', validId, validUser, userController.findById); route.patch('/', validToken, userController.updateLoggedUser); route.delete('/', validToken, userController.deleteUser); - // route.get('/', validToken, userController.findAll); // route.get('/:id', validId, validUser, validToken, userController.findById); // route.patch("/:id", validId, validUser, validToken, userController.update); diff --git a/src/services/review.service.js b/src/services/review.service.js new file mode 100644 index 0000000..c3ff132 --- /dev/null +++ b/src/services/review.service.js @@ -0,0 +1,17 @@ +import Review from "../models/Review.js"; + +const createReview = (reviewData) => Review.create(reviewData); + +const getReviewsByTouristAttractionId = (TouristAttractionId) => + Review.find({ TouristAttractionId }); + +const getUserReviews = (userId) => Review.find({ userId }); + +const deleteReview = (reviewId) => Review.findByIdAndDelete(reviewId); + +export default { + createReview, + getReviewsByTouristAttractionId, + getUserReviews, + deleteReview, +}; \ No newline at end of file