diff --git a/server/src/config/config.js b/server/src/config/config.js index 325f198..bccd039 100644 --- a/server/src/config/config.js +++ b/server/src/config/config.js @@ -1,8 +1,8 @@ -const config = { - redis: { - port: process.env.REDIS_PORT, - host: process.env.REDIS_HOST - } -} +// const config = { +// redis: { +// port: process.env.REDIS_PORT, +// host: process.env.REDIS_HOST +// } +// } -module.exports = config \ No newline at end of file +// module.exports = config \ No newline at end of file diff --git a/server/src/controllers/comment.controller.js b/server/src/controllers/comment.controller.js index 92be1bb..b714d0a 100644 --- a/server/src/controllers/comment.controller.js +++ b/server/src/controllers/comment.controller.js @@ -2,70 +2,70 @@ const { Sequelize } = require("sequelize") const Comment = require("../models/comment.model") +const Tour = require("../models/tour.model") const Op = Sequelize.Op class CommentController { createComment = async (req, res, next) => { - try { - const { tour_id, content, user_id, parent_comment_id } = req.body; - const comment = await Comment.create({ - tour_id, content, user_id, parent_comment_id - }); + try { + const { tour_id, content, user_id, parent_comment_id } = req.body; + const comment = await Comment.create({ + tour_id, content, user_id, parent_comment_id + }); - let rightValue; - if (parent_comment_id) { - // reply comment - const parent_comment = await Comment.findOne({ where: { comment_id: parent_comment_id }}); - if (!parent_comment) return res.status(404).json({ message: "Not found parent comment!" }); + let rightValue; + if (parent_comment_id) { + // reply comment + const parent_comment = await Comment.findOne({ where: { comment_id: parent_comment_id }}); + if (!parent_comment) return res.status(404).json({ message: "Not found parent comment!" }); - console.log(`parent_comment:::`, parent_comment) + console.log(`parent_comment:::`, parent_comment) - rightValue = parent_comment.comment_right; + rightValue = parent_comment.comment_right; - // update many comments - await Comment.update({ - comment_right: Sequelize.literal('comment_right + 2') - },{ - where: { - tour_id: tour_id, - comment_right: { [Sequelize.Op.gte]: rightValue } - } - }); - - await Comment.update({ - comment_left: Sequelize.literal('comment_left + 2') + // update many comments + await Comment.update({ + comment_right: Sequelize.literal('comment_right + 2') },{ where: { tour_id: tour_id, - comment_left: { [Sequelize.Op.gt]: rightValue } + comment_right: { [Sequelize.Op.gte]: rightValue } } - }); - } else { - const maxRightValue = await Comment.findOne({ - where: { - tour_id: tour_id - }, - attributes: [[Sequelize.fn('MAX', Sequelize.col('comment_right')), 'maxRight']] - }); + }); - rightValue = maxRightValue && maxRightValue.dataValues.maxRight !== null ? maxRightValue.dataValues.maxRight + 1 : 1; - } + await Comment.update({ + comment_left: Sequelize.literal('comment_left + 2') + },{ + where: { + tour_id: tour_id, + comment_left: { [Sequelize.Op.gt]: rightValue } + } + }); + } else { + const maxRightValue = await Comment.findOne({ + where: { + tour_id: tour_id + }, + attributes: [[Sequelize.fn('MAX', Sequelize.col('comment_right')), 'maxRight']] + }); - // insert to comment - comment.comment_left = rightValue; - comment.comment_right = rightValue + 1; - - await comment.save(); - return res.status(200).json({ - message: "You comment tour successfully!", - comment: comment - }); - } catch (error) { - return res.status(500).json({ message: error.message }); - } -}; + rightValue = maxRightValue && maxRightValue.dataValues.maxRight !== null ? maxRightValue.dataValues.maxRight + 1 : 1; + } + + // insert to comment + comment.comment_left = rightValue; + comment.comment_right = rightValue + 1; + await comment.save(); + return res.status(200).json({ + message: "You comment tour successfully!", + comment: comment + }); + } catch (error) { + return res.status(500).json({ message: error.message }); + } + }; getCommentsByParentId = async (req, res, next) => { try { @@ -73,9 +73,11 @@ class CommentController { let comments; if (parent_comment_id) { - const parent = await Comment.findOne({ where: { parent_comment_id: parent_comment_id }}); + const parent = await Comment.findOne({ where: { comment_id: parent_comment_id }}); if (!parent) return res.status(404).json({ message: "Not found comment for tour!"}); + console.log(`parent:::`, parent) + comments = await Comment.findAll({ where: { tour_id: tour_id, @@ -90,8 +92,7 @@ class CommentController { } else { comments = await Comment.findAll({ where: { - tour_id: tour_id, - parent_comment_id: parent_comment_id + tour_id: tour_id }, attributes: ['comment_left', 'comment_right', 'content', 'parent_comment_id'], order: [['comment_left', 'ASC']], limit, @@ -107,6 +108,60 @@ class CommentController { return res.status(500).json({ message: error.message }) } } + + deleteComment = async (req, res, next) => { + try { + const { tour_id, comment_id } = req.body + + const tour = await Tour.findOne({ where: { tour_id: tour_id }}) + if (!tour) return res.status(404).json({ message: "Not found tour for deleting comment!" }) + + const comment = await Comment.findOne({ where: { comment_id: comment_id }}) + if (!comment) return res.status(404).json({ message: "Not found comment!" }) + + // 1. Define left & right value of comment + const leftValue = comment.comment_left + const rightValue = comment.comment_right + + // 2. Calc width + const width = rightValue - leftValue + 1 + + // 3. Delete all child comments + await Comment.destroy({ + where: { + tour_id: tour_id, + comment_left: { [Op.gte]: leftValue }, + comment_left: { [Op.lte]: rightValue } + } + }) + + // 4. Update right & left + await Comment.update({ + comment_right: Sequelize.literal(`comment_right - ${width}`)}, { + where: { + tour_id: tour_id, + comment_right: { [Op.gt]: rightValue } + } + } + ) + + await Comment.update({ + comment_left: Sequelize.literal(`comment_left - ${width}`)}, { + where: { + tour_id: tour_id, + comment_left: { [Op.gt]: rightValue } + } + } + ) + + return res.status(200).json({ + message: "Delete comment successfully!", + comment: await Comment.findOne({ where: { comment_id: comment_id }}) + }) + } catch (error) { + return res.status(500).json({ message: error.message }) + } + } } module.exports = new CommentController() \ No newline at end of file diff --git a/server/src/controllers/payment.controller.js b/server/src/controllers/payment.controller.js index a53895d..3784056 100644 --- a/server/src/controllers/payment.controller.js +++ b/server/src/controllers/payment.controller.js @@ -17,8 +17,7 @@ const { findVoucherById } = require('../services/voucher.service'); const tmnCode = process.env.vnp_TmnCode; const secretKey = process.env.vnp_HashSecret; let url = process.env.vnp_Url; -const returnUrl = process.env.vnp_ReturnUrl; // cai nay ong de link giao dien thanh cong nha vi du: -// https:localhost:3000/success_payment +const returnUrl = process.env.vnp_ReturnUrl; // cai nay ong de link giao dien thanh cong nha vi du: https:localhost:3000/success_payment class PaymentController { /** @@ -123,6 +122,10 @@ class PaymentController { } } + payDirectly = async (req, res, next) => { + + } + getResultPayment = async (req, res, next) => { try { const vnp_Params = req.query; diff --git a/server/src/controllers/review.controller.js b/server/src/controllers/review.controller.js new file mode 100644 index 0000000..545f337 --- /dev/null +++ b/server/src/controllers/review.controller.js @@ -0,0 +1,89 @@ +'use strict' + +const cloudinary = require("../utils/cloudinary") +const { NotFoundError } = require("../core/error.response") +const Review = require("../models/review.model") +const { findTourById } = require("../services/tour.service") +const { findUserById } = require("../services/user.service") +const Comment = require("../models/comment.model") + +class ReviewController { + creatReview = async (req, res, next) => { + try { + const { + user_id, + tour_id, + is_comment, + content, + parent_comment_id, + number_rate + } = req.fields; + console.log(`:::`, req.fields) + + const user = await findUserById(user_id); + if (!user) throw new NotFoundError("Not found user!"); + + // check tour is ordered by user ? + + const tour = await findTourById(tour_id); + if (!tour) throw new NotFoundError("Not found tour for reviewing!"); + + const list_image = []; + let i = 0; + while(req.files[`image[${i}]`]) { + const path_image = req.files[`image[${i}]`].path + const image = await cloudinary.uploader.upload(path_image) + list_image.push(image.secure_url) + i++; + } + + const new_comment = is_comment ? ( await Comment.create({ + content, + parent_comment_id, + image: list_image.length > 0 ? JSON.stringify(list_image) : null + }) ) : null; + + const tour_review = await Review.findOne({ where: { tour_id: tour_id }}); + if (!tour_review) { + const new_review = await Review.create({ + user_id, + tour_id, + comment_id: new_comment ? new_comment.comment_id : null, + rating_1: number_rate == 1 ? 1 : 0, + rating_2: number_rate == 2 ? 1 : 0, + rating_3: number_rate == 3 ? 1 : 0, + rating_4: number_rate == 4 ? 1 : 0, + rating_5: number_rate == 5 ? 1 : 0, + count: 1, + average_rate: number_rate + }) + + return res.status(200).json({ + message: "Review tour successfully!", + new_review: new_review + }) + } else { + tour_review.rating_1 = number_rate == 1 ? tour_review.rating_1++ : tour_review.rating_1; + tour_review.rating_2 = number_rate == 2 ? tour_review.rating_2++ : tour_review.rating_2; + tour_review.rating_3 = number_rate == 3 ? tour_review.rating_3++ : tour_review.rating_3; + tour_review.rating_4 = number_rate == 4 ? tour_review.rating_4++ : tour_review.rating_4; + tour_review.rating_5 = number_rate == 5 ? tour_review.rating_5++ : tour_review.rating_5; + const av = (tour_review.average_rate * tour_review.count + number_rate) / (tour_review.count + 1); + console.log(`av:::`, av) + return res.status(200).json({ message: "OK"}) + tour_review.average_rate = (tour_review.average_rate * tour_review.count + number_rate) / (tour_review.count + 1); + tour_review.count++; + await tour_review.save(); + + return res.status(200).json({ + message: "Review tour successfully!", + new_review: tour_review + }) + } + } catch (error) { + return res.status(500).json({ message: error.message }) + } + } +} + +module.exports = new ReviewController() \ No newline at end of file diff --git a/server/src/controllers/voucher.controller.js b/server/src/controllers/voucher.controller.js index 247d59c..cefe7de 100644 --- a/server/src/controllers/voucher.controller.js +++ b/server/src/controllers/voucher.controller.js @@ -1,10 +1,11 @@ 'use strict' +const { NotFoundError } = require("../core/error.response") +const Order = require("../models/order.model") const Voucher = require("../models/voucher.model") const cloudinary = require("../utils/cloudinary") const Sequelize = require("sequelize") const Op = Sequelize.Op -const cron = require("node-cron") class VoucherController { @@ -59,6 +60,22 @@ class VoucherController { } } + getVoucherByOrderId = async (req, res, next) => { + try { + const order_id = req.params; + const order = await Order.findByPk(order_id, { include: Voucher }) + if (!order) throw new NotFoundError("Not found order!") + + return res.status(200).json({ + message: "Get vouchers of order successfully!", + vouchers: order.Voucher + }) + + } catch (error) { + return res.status(500).json({ message: error.message }); + } + } + getAllVouchers = async (req, res, next) => { try { const all_vouchers = await Voucher.findAll({ diff --git a/server/src/models/comment.model.js b/server/src/models/comment.model.js index 84eef3a..3f48f45 100644 --- a/server/src/models/comment.model.js +++ b/server/src/models/comment.model.js @@ -14,6 +14,10 @@ Comment.init({ type: DataTypes.TEXT, allowNull: false }, + image: { + type: DataTypes.TEXT, + allowNull: true + }, comment_left: { type: DataTypes.INTEGER, allowNull: false, diff --git a/server/src/models/review.model.js b/server/src/models/review.model.js index e69de29..f551aa2 100644 --- a/server/src/models/review.model.js +++ b/server/src/models/review.model.js @@ -0,0 +1,52 @@ +'use strict' + +const { DataTypes, Model } = require("sequelize") +const sequelize = require("../database/index") +const Comment = require("./comment.model") + +class Review extends Model {} +Review.init({ + review_id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + rating_1: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: 0 + }, + rating_2: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: 0 + }, + rating_3: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: 0 + }, + rating_4: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: 0 + }, + rating_5: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: 0 + }, + average_rate: { + type: DataTypes.DECIMAL(3, 1), + allowNull: false, + defaultValue: 0.0 + }, + count: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: 0 + } +}, { sequelize, modelName: "review" }) + +Review.hasMany(Comment, { foreignKey: "review_id" }) +module.exports = Review \ No newline at end of file diff --git a/server/src/models/tour.model.js b/server/src/models/tour.model.js index b71a44c..bebe3d7 100644 --- a/server/src/models/tour.model.js +++ b/server/src/models/tour.model.js @@ -6,6 +6,7 @@ const sequelize = require("../database/index") const { StatusTour } = require("../common/status"); const OrderItem = require("./order_item.model"); const Comment = require("./comment.model"); +const Review = require("./review.model"); class Tour extends Model {} Tour.init({ @@ -91,5 +92,6 @@ Tour.init({ Tour.hasMany(OrderItem, { foreignKey: "tour_id" }) Tour.hasMany(Comment, { foreignKey: "tour_id" }) +Tour.hasMany(Review, { foreignKey: "tour_id" }) module.exports = Tour \ No newline at end of file diff --git a/server/src/models/user.model.js b/server/src/models/user.model.js index e2d4209..0786370 100644 --- a/server/src/models/user.model.js +++ b/server/src/models/user.model.js @@ -9,6 +9,7 @@ const Wishlist = require("./wishlist.model"); const Message = require("./message.model"); const GroupMember = require("./group_member.model"); const Cart = require("./cart.model"); +const Review = require("./review.model"); const role_user = { ADMIN: 'admin', @@ -90,5 +91,6 @@ User.hasMany(GroupMember, { foreignKey: "user_id"}) User.hasOne(Cart, { foreignKey: "user_id"}) User.hasMany(Order, { foreignKey: 'user_id' }); User.hasMany(Comment, { foreignKey: "user_id"}) +User.hasMany(Review, { foreignKey: "user_id" }) module.exports = User; \ No newline at end of file diff --git a/server/src/models/voucher_order.model.js b/server/src/models/voucher_order.model.js index b2c9f1b..e62a93d 100644 --- a/server/src/models/voucher_order.model.js +++ b/server/src/models/voucher_order.model.js @@ -1,30 +1,20 @@ 'use strict' -const { DataTypes } = require("sequelize") +const { DataTypes, Model } = require("sequelize") const sequelize = require("../database/index") const Order = require("./order.model") const Voucher = require("./voucher.model") -const OrderVoucher = sequelize.define('order_voucher', { - order_id: { +class VoucherOrder extends Model {}; +VoucherOrder.init({ + id: { type: DataTypes.INTEGER, - allowNull: false, - references: { - model: Order, - key: 'order_id' - } - }, - voucher_id: { - type: DataTypes.INTEGER, - allowNull: false, - references: { - model: Voucher, - key: 'voucher_id' - } + primaryKey: true, + autoIncrement: true } -}) +}, { sequelize, modelName: "voucher_order" }) -Order.belongsToMany(Voucher, { through: OrderVoucher }) -Voucher.belongsToMany(Order, { through: OrderVoucher }) +Order.belongsToMany(Voucher, { through: VoucherOrder, foreignKey: "order_id" }) +Voucher.belongsToMany(Order, { through: VoucherOrder, foreignKey: "voucher_id" }) -module.exports = OrderVoucher \ No newline at end of file +module.exports = VoucherOrder \ No newline at end of file diff --git a/server/src/routes/comment/index.js b/server/src/routes/comment/index.js index c868c06..cbeb6d8 100644 --- a/server/src/routes/comment/index.js +++ b/server/src/routes/comment/index.js @@ -7,5 +7,6 @@ const commentController = require("../../controllers/comment.controller") router.post("/", asyncHandler(commentController.createComment)) router.get("/", asyncHandler(commentController.getCommentsByParentId)) +router.delete("/", asyncHandler(commentController.deleteComment)) module.exports = router \ No newline at end of file diff --git a/server/src/routes/index.js b/server/src/routes/index.js index 2c33f1a..bc92dbf 100644 --- a/server/src/routes/index.js +++ b/server/src/routes/index.js @@ -15,5 +15,7 @@ router.use('/api/v1/user/cart', require("./cart")) router.use('/api/v1/user/payment', require("./payment")) router.use('/api/v1/tour', require("./tour")) router.use('/api/v1/voucher', require("./voucher")) +router.use('/api/v1/review', require("./review")) +router.use('/api/v1/order', require("./order")) module.exports = router \ No newline at end of file diff --git a/server/src/routes/order/index.js b/server/src/routes/order/index.js index 2896394..3a0eb87 100644 --- a/server/src/routes/order/index.js +++ b/server/src/routes/order/index.js @@ -5,4 +5,7 @@ const router = express.Router() const { asyncHandler } = require('../../auth/checkAuth') const orderController = require("../../controllers/order.controller") +router.post("/", asyncHandler(orderController.createOrderByTourId)) +router.post("/:order_id/applyVoucher", asyncHandler(orderController.applyVoucherToOrder)) + module.exports = router \ No newline at end of file diff --git a/server/src/routes/review/index.js b/server/src/routes/review/index.js new file mode 100644 index 0000000..e346dad --- /dev/null +++ b/server/src/routes/review/index.js @@ -0,0 +1,12 @@ +'use strict' + +const express = require("express") +const router = express.Router() +const { asyncHandler } = require('../../auth/checkAuth') +const reviewController = require("../../controllers/review.controller") +const formidableMiddleware = require('express-formidable'); + +router.use(formidableMiddleware()); +router.post("/", asyncHandler(reviewController.creatReview)) + +module.exports = router \ No newline at end of file diff --git a/server/src/services/comment.service.js b/server/src/services/comment.service.js new file mode 100644 index 0000000..41523a4 --- /dev/null +++ b/server/src/services/comment.service.js @@ -0,0 +1,58 @@ +'use strict' + +const { NotFoundError } = require("../core/error.response"); +const Comment = require("../models/comment.model") + +const createComment = async ({ tour_id, user_id, content, parent_comment_id }) => { + const comment = await Comment.create({ + tour_id, content, user_id, parent_comment_id + }); + + let rightValue; + if (parent_comment_id) { + // reply comment + const parent_comment = await Comment.findOne({ where: { comment_id: parent_comment_id }}); + if (!parent_comment) throw new NotFoundError("Not found parent_commeent"); + + rightValue = parent_comment.comment_right; + + // update many comments + await Comment.update({ + comment_right: Sequelize.literal('comment_right + 2') + },{ + where: { + tour_id: tour_id, + comment_right: { [Sequelize.Op.gte]: rightValue } + } + }); + + await Comment.update({ + comment_left: Sequelize.literal('comment_left + 2') + },{ + where: { + tour_id: tour_id, + comment_left: { [Sequelize.Op.gt]: rightValue } + } + }); + } else { + const maxRightValue = await Comment.findOne({ + where: { + tour_id: tour_id + }, + attributes: [[Sequelize.fn('MAX', Sequelize.col('comment_right')), 'maxRight']] + }); + + rightValue = maxRightValue && maxRightValue.dataValues.maxRight !== null ? maxRightValue.dataValues.maxRight + 1 : 1; + } + + // insert to comment + comment.comment_left = rightValue; + comment.comment_right = rightValue + 1; + + await comment.save(); + return comment; +} + +module.exports = { + createComment +} \ No newline at end of file diff --git a/server/src/services/order.service.js b/server/src/services/order.service.js index 32def85..162e22e 100644 --- a/server/src/services/order.service.js +++ b/server/src/services/order.service.js @@ -1,5 +1,6 @@ 'use strict' +const Order = require("../models/order.model") const OrderItem = require("../models/order_item.model") const findOrderItem = async (cart_id, tour_id) => { @@ -11,6 +12,14 @@ const findOrderItem = async (cart_id, tour_id) => { }) } +const findOrderById = async (order_id) => { + return await Order.findOne({ + where: { + order_id: order_id + } + }) +} module.exports = { - findOrderItem + findOrderItem, + findOrderById } \ No newline at end of file diff --git a/server/src/services/voucher.service.js b/server/src/services/voucher.service.js index 6138875..5a15fbc 100644 --- a/server/src/services/voucher.service.js +++ b/server/src/services/voucher.service.js @@ -11,7 +11,12 @@ const findVoucherById = async (id) => { return await Voucher.findOne({ where: { voucher_id: id }}) } +const findVoucherByCode = async (code) => { + return await Voucher.findOne({ where: { code_voucher: code }}) +} + module.exports = { updateNumberVoucher, - findVoucherById + findVoucherById, + findVoucherByCode } \ No newline at end of file diff --git a/server/src/utils/httpStatusCode.js b/server/src/utils/httpStatusCode.js index fbeaa6d..2d1a2a7 100644 --- a/server/src/utils/httpStatusCode.js +++ b/server/src/utils/httpStatusCode.js @@ -1,4 +1,4 @@ module.exports = { - StatusCodes: require('./statusCodes'), + StatusCodes: require('./statusCode'), ReasonPhrases: require('./reasonPhrases') } \ No newline at end of file