Skip to content

Commit

Permalink
Merge pull request #7 from FoxMalder-coder/module5-task2
Browse files Browse the repository at this point in the history
  • Loading branch information
keksobot authored Oct 30, 2024
2 parents 07a1a2c + 68fd647 commit 1afcdf0
Show file tree
Hide file tree
Showing 17 changed files with 195 additions and 7 deletions.
25 changes: 22 additions & 3 deletions specification/specification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ info:

tags:
- name: offers
description: Действия с объявлениями.
description: Действия с предложениями.
- name: comments
description: Действия с комментариями.
- name: users
Expand Down Expand Up @@ -62,8 +62,27 @@ paths:
tags:
- users
summary: Загрузка аватара
description: Загружает изображение аватара пользователя. Изображение
аватара должно быть в формате `png` или `jpg`.
description: Загружает изображение аватара пользователя. Изображение аватара должно быть в формате `png` или `jpg`.

/users/{userId}/favorites:
get:
tags:
- users
summary: Возвращает избранные предложения
description: Возвращает предложения, добавленные в избранное. Доступен только авторизованным пользователям.

/users/{userId}/favorites/{offerId}:
post:
tags:
- users
summary: Добавление в избранное
description: Добавляет предложение в избранное. Доступен только авторизованным пользователям.

delete:
tags:
- users
summary: Удаление из избранного
description: Удаляет предложение из избранного. Доступен только авторизованным пользователям.


components:
Expand Down
2 changes: 0 additions & 2 deletions src/cli/commands/command.constant.ts

This file was deleted.

4 changes: 3 additions & 1 deletion src/cli/commands/import.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { Logger } from '../../shared/libs/logger/logger.interface.js';
import { DefaultOfferService, OfferModel, OfferService } from '../../shared/modules/offer/index.js';
import { DefaultUserService, UserModel, UserService } from '../../shared/modules/user/index.js';
import { Offer } from '../../shared/types/index.js';
import { DEFAULT_DB_PORT, DEFAULT_USER_PASSWORD } from './command.constant.js';
import { Command } from './command.interface.js';

const DEFAULT_DB_PORT = '27017';
const DEFAULT_USER_PASSWORD = '123456';

export class ImportCommand implements Command {
private userService: UserService;
private offerService: OfferService;
Expand Down
2 changes: 2 additions & 0 deletions src/main.rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import { Component } from './shared/const.js';
import { RESTApplication } from './rest/rest.application.js';
import { createUserContainer } from './shared/modules/user/index.js';
import { createOfferContainer } from './shared/modules/offer/index.js';
import { createCommentContainer } from './shared/modules/comments/index.js';

async function bootstrap() {
const container = Container.merge(
createRestApplicationContainer(),
createUserContainer(),
createOfferContainer(),
createCommentContainer(),
);

const application = container.get<RESTApplication>(Component.RestApplication);
Expand Down
7 changes: 7 additions & 0 deletions src/shared/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,11 @@ export const Component = {
UserModel: Symbol.for('UserModel'),
OfferService: Symbol.for('OfferService'),
OfferModel: Symbol.for('OfferModel'),
CommentService: Symbol.for('CommentService'),
CommentModel: Symbol.for('CommentModel'),
} as const;

export enum SortType {
Down = -1,
Up = 1,
}
9 changes: 9 additions & 0 deletions src/shared/modules/comments/comment-service.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { DocumentType } from '@typegoose/typegoose';
import { CommentEntity } from './comment.entity.js';
import { CreateCommentDto } from './dto/create-comment.dto.js';

export interface CommentService {
create(dto: CreateCommentDto): Promise<DocumentType<CommentEntity>>;
findByOfferId(offerId: string): Promise<DocumentType<CommentEntity>[]>;
deleteByOfferId(offerId: string): Promise<number | null>;
}
15 changes: 15 additions & 0 deletions src/shared/modules/comments/comment.container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Container } from 'inversify';
import { Component } from '../../const.js';
import { CommentService } from './comment-service.interface.js';
import { DefaultCommentService } from './default-comment.service.js';
import { types } from '@typegoose/typegoose';
import { CommentEntity, CommentModel } from './comment.entity.js';

export function createCommentContainer() {
const commentContainer = new Container();

commentContainer.bind<CommentService>(Component.CommentService).to(DefaultCommentService).inSingletonScope();
commentContainer.bind<types.ModelType<CommentEntity>>(Component.CommentModel).toConstantValue(CommentModel);

return commentContainer;
}
35 changes: 35 additions & 0 deletions src/shared/modules/comments/comment.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { defaultClasses, getModelForClass, modelOptions, prop, Ref } from '@typegoose/typegoose';
import { OfferEntity } from '../offer/index.js';
import { UserEntity } from '../user/index.js';

// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
export interface CommentEntity extends defaultClasses.Base { }

@modelOptions({
schemaOptions: {
collection: 'comments',
timestamps: true,
}
})
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
export class CommentEntity extends defaultClasses.TimeStamps {
@prop({ trim: true, required: true })
public text: string;

@prop({
ref: OfferEntity,
required: true
})
public offerId: Ref<OfferEntity>;

@prop({
ref: UserEntity,
required: true,
})
public userId: Ref<UserEntity>;

@prop({ required: true })
public rating: number;
}

export const CommentModel = getModelForClass(CommentEntity);
27 changes: 27 additions & 0 deletions src/shared/modules/comments/default-comment.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { DocumentType, types } from '@typegoose/typegoose';
import { inject, injectable } from 'inversify';
import { CommentService } from './comment-service.interface.js';
import { CreateCommentDto } from './dto/create-comment.dto.js';
import { CommentEntity } from './comment.entity.js';
import { Component } from '../../const.js';

@injectable()
export class DefaultCommentService implements CommentService {
constructor(
@inject(Component.CommentModel) private readonly commentModel: types.ModelType<CommentEntity>
) { }

public async create(dto: CreateCommentDto): Promise<DocumentType<CommentEntity>> {
const comment = await this.commentModel.create(dto);
return comment.populate('userId');
}

public async findByOfferId(offerId: string): Promise<DocumentType<CommentEntity>[]> {
return this.commentModel.find({ offerId }).populate('userId').exec();
}

public async deleteByOfferId(offerId: string): Promise<number> {
const result = await this.commentModel.deleteMany({ offerId }).exec();
return result.deletedCount;
}
}
6 changes: 6 additions & 0 deletions src/shared/modules/comments/dto/create-comment.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export class CreateCommentDto {
public offerId: string;
public text: string;
public rating: number;
public userId: string;
}
4 changes: 4 additions & 0 deletions src/shared/modules/comments/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { CommentService } from './comment-service.interface.js';
export { CommentEntity, CommentModel } from './comment.entity.js';
export { DefaultCommentService } from './default-comment.service.js';
export { createCommentContainer } from './comment.container.js';
27 changes: 26 additions & 1 deletion src/shared/modules/offer/default-offer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import { OfferEntity } from './offer.entity.js';
import { DocumentType, types } from '@typegoose/typegoose';
import { OfferService } from './offer-service.interface.js';
import { CreateOfferDto } from './dto/create-offer.dto.js';
import { UpdateOfferDto } from './dto/update-offer.dto.js';
import { SortType } from '../../const.js';
import { City } from '../../types/index.js';

const DEFAULT_PREMIUM_COUNT = 3;

@injectable()
export class DefaultOfferService implements OfferService {
Expand All @@ -21,6 +26,26 @@ export class DefaultOfferService implements OfferService {
}

public async findById(offerId: string): Promise<DocumentType<OfferEntity> | null> {
return this.offerModel.findById(offerId).exec();
return this.offerModel.findById(offerId).populate('userId').exec();
}

public async find(): Promise<DocumentType<OfferEntity>[]> {
return this.offerModel.find().populate('userId').exec();
}

public async deleteById(offerId: string): Promise<DocumentType<OfferEntity> | null> {
return this.offerModel.findByIdAndDelete(offerId).exec();
}

public async updateById(offerId: string, dto: UpdateOfferDto): Promise<DocumentType<OfferEntity> | null> {
return this.offerModel.findByIdAndUpdate(offerId, dto, { new: true }).populate('userId').exec();
}

public async exists(documentId: string): Promise<boolean> {
return (await this.offerModel.exists({ _id: documentId })) !== null;
}

public async findPremiumByCity(city: City): Promise<DocumentType<OfferEntity>[] | null> {
return this.offerModel.find({ city }).sort({ createdAt: SortType.Down }).limit(DEFAULT_PREMIUM_COUNT).populate('userId').exec();
}
}
21 changes: 21 additions & 0 deletions src/shared/modules/offer/dto/update-offer.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { City, Location, OfferType } from '../../../types/index.js';

export class UpdateOfferDto {
public title?: string;
public description?: string;
public postDate?: Date;
public city?: City;
public preview?: string;
public images?: string[];
public isPremium?: boolean;
public isFavorite?: boolean;
public type?: OfferType;
public rooms?: number;
public guests?: number;
public price?: number;
public facilities?: string[];
public userId?: string;
public location?: Location;
public rating?: number;
public commentCount?: number;
}
7 changes: 7 additions & 0 deletions src/shared/modules/offer/offer-service.interface.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { DocumentType } from '@typegoose/typegoose';
import { CreateOfferDto } from './dto/create-offer.dto.js';
import { OfferEntity } from './offer.entity.js';
import { UpdateOfferDto } from './dto/update-offer.dto.js';
import { City } from '../../types/index.js';

export interface OfferService {
create(dto: CreateOfferDto): Promise<DocumentType<OfferEntity>>;
find(): Promise<DocumentType<OfferEntity>[] | null>;
findById(offerId: string): Promise<DocumentType<OfferEntity> | null>;
findPremiumByCity(city: City): Promise<DocumentType<OfferEntity>[] | null>;
deleteById(offerId: string): Promise<DocumentType<OfferEntity> | null>;
updateById(offerId: string, dto: UpdateOfferDto): Promise<DocumentType<OfferEntity> | null>;
exists(documentId: string): Promise<boolean>;
}
5 changes: 5 additions & 0 deletions src/shared/modules/user/default-user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CreateUserDto } from './dto/create-user.dto.js';
import { inject, injectable } from 'inversify';
import { Component } from '../../const.js';
import { Logger } from '../../libs/logger/logger.interface.js';
import { UpdateUserDto } from './dto/update-user.dto.js';

@injectable()
export class DefaultUserService implements UserService {
Expand Down Expand Up @@ -36,4 +37,8 @@ export class DefaultUserService implements UserService {

return this.create(dto, salt);
}

public async updateById(userId: string, dto: UpdateUserDto): Promise<DocumentType<UserEntity> | null> {
return this.userModel.findByIdAndUpdate(userId, dto, { new: true }).exec();
}
}
4 changes: 4 additions & 0 deletions src/shared/modules/user/dto/update-user.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export class UpdateUserDto {
public name?: string;
public avatar?: string;
}
2 changes: 2 additions & 0 deletions src/shared/modules/user/user-service.interface.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { DocumentType } from '@typegoose/typegoose';
import { UserEntity } from './user.entity.js';
import { CreateUserDto } from './dto/create-user.dto.js';
import { UpdateUserDto } from './dto/update-user.dto.js';

export interface UserService {
create(dto: CreateUserDto, salt: string): Promise<DocumentType<UserEntity>>;
findByEmail(email: string): Promise<DocumentType<UserEntity> | null>;
findOrCreate(dto: CreateUserDto, salt: string): Promise<DocumentType<UserEntity>>;
updateById(userId: string, dto: UpdateUserDto): Promise<DocumentType<UserEntity> | null>;
}

0 comments on commit 1afcdf0

Please sign in to comment.