diff --git a/src/.env.example b/.env.example similarity index 100% rename from src/.env.example rename to .env.example diff --git a/TODO b/TODO index 4233707..941b83f 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,5 @@ Todo: ☐ В *service отлавливать ошибки через try catch ☐ SALT из контроллера передается в сервис параметром. Для чего? Почему соль нельзя в сервисе считать из конфига? Нарушение паттерна? Можно перетащить в сервис!!! - ☐ В DTO добавить валидацию - ☐ кол-во коментов динамически https://stackoverflow.com/questions/48389112/mongodb-best-practice-to-count-related-documents + ✔ В DTO добавить валидацию @done(24-10-12 13:12) + ✔ кол-во коментов динамически https://stackoverflow.com/questions/48389112/mongodb-best-practice-to-count-related-documents @done(24-10-12 13:12) diff --git a/src/shared/modules/offer/default-offer-service.ts b/src/shared/modules/offer/default-offer-service.ts index d23d916..2195f37 100644 --- a/src/shared/modules/offer/default-offer-service.ts +++ b/src/shared/modules/offer/default-offer-service.ts @@ -57,7 +57,21 @@ export class DefaultOfferService implements OfferService { } async findById(offerId: string): Promise { - return await this.offerModel.findById(offerId).populate(['userId']).exec(); + const [reviews] = await this.reviewModel.aggregate([ + { $match: { offerId } }, + { $count: 'reviewsCount' }, + ]); + + const result = await this.offerModel + .findById(offerId) + .populate(['userId']) + .exec(); + + if (result) { + Object.assign(result, { reviewsCount: reviews.reviewsCount }); + } + + return result; } async findPremiumByCity( @@ -119,16 +133,10 @@ export class DefaultOfferService implements OfferService { .exec(); } - async updateRating(offerId: string): Promise { - ///// Очень сомневаюсь в правильности - const [{ averageRating }] = await this.reviewModel.aggregate([ - { $match: { offerId } }, - { $group: { _id: null, averageRating: { $avg: '$rating' } } }, - ]); - - return this.offerModel - .findByIdAndUpdate(offerId, [{ rating: averageRating }], { new: true }) - .populate(['userId']) - .exec(); + async updateRating( + offerId: string, + rating: number + ): Promise { + return this.offerModel.findByIdAndUpdate(offerId, { rating }).exec(); } } diff --git a/src/shared/modules/offer/offer-service.interface.ts b/src/shared/modules/offer/offer-service.interface.ts index f9e7b7b..68d9c1d 100644 --- a/src/shared/modules/offer/offer-service.interface.ts +++ b/src/shared/modules/offer/offer-service.interface.ts @@ -20,6 +20,9 @@ export interface OfferService extends DocumentExists { offerId: string, isFavorite: number ): Promise; - updateRating(offerId: string): Promise; + updateRating( + offerId: string, + rating: number + ): Promise; findFavorites(): Promise; } diff --git a/src/shared/modules/offer/offer.http b/src/shared/modules/offer/offer.http index 0b4aa65..959d405 100644 --- a/src/shared/modules/offer/offer.http +++ b/src/shared/modules/offer/offer.http @@ -3,7 +3,7 @@ GET http://localhost:4000/offers HTTP/1.1 ### -GET http://localhost:4000/offers/67069067990eba53b6c2b130 HTTP/1.1 +GET http://localhost:4000/offers/670530d901266b562fbdc0ef HTTP/1.1 ### POST http://localhost:4000/offers/ HTTP/1.1 diff --git a/src/shared/modules/review/default-review-service.ts b/src/shared/modules/review/default-review-service.ts index 31ad9fb..747670e 100644 --- a/src/shared/modules/review/default-review-service.ts +++ b/src/shared/modules/review/default-review-service.ts @@ -1,7 +1,9 @@ import { Logger } from '#libs/logger/logger.interface.js'; +import { OfferService } from '#modules/offer/offer-service.interface.js'; import { Component } from '#types/component.enum.js'; import { types } from '@typegoose/typegoose'; import { inject, injectable } from 'inversify'; +import mongoose from 'mongoose'; import { CreateReviewDto } from './dto/create-review-dto.js'; import { ReviewEntity } from './review-entity.js'; import { @@ -14,17 +16,29 @@ export class DefaultReviewService implements ReviewService { constructor( @inject(Component.Logger) private readonly logger: Logger, @inject(Component.ReviewModel) - private readonly reviewModel: types.ModelType + private readonly reviewModel: types.ModelType, + @inject(Component.OfferService) + private readonly offerService: OfferService ) {} + async calculateAverageRating(offerId: string): Promise { + const [review] = await this.reviewModel.aggregate>([ + { $match: { offerId: new mongoose.Types.ObjectId(offerId) } }, + { $group: { _id: null, averageRating: { $avg: '$rating' } } }, + ]); + return +review.averageRating.toFixed(1); + } + async create( offerId: string, dto: CreateReviewDto ): Promise { const result = await this.reviewModel.create({ ...dto, offerId }); - this.logger.info('New review created'); + const averageRating = await this.calculateAverageRating(offerId); - return result; + this.offerService.updateRating(offerId, averageRating); + this.logger.info('New review created'); + return result.populate('userId'); } async findByOfferId(offerId: string): Promise { diff --git a/src/shared/modules/review/review.http b/src/shared/modules/review/review.http index 485a4bc..afb69c9 100644 --- a/src/shared/modules/review/review.http +++ b/src/shared/modules/review/review.http @@ -6,10 +6,10 @@ POST http://localhost:4000/reviews/670530d901266b562fbdc0ef HTTP/1.1 Content-Type: application/json { - "offerId": "67069067990eba53b6c2b130", + "offerId": "670530d901266b562fbdc0ef", "date": "2024-08-10T08:11:23.283Z", "userId": "6704f9003df41d32ec047a0e", "comment": "test sdhfskdhfks", - "rating": 4 + "rating": 1.3 }