From f89fa35c016001b5ed528e80b002a893dab50e4e Mon Sep 17 00:00:00 2001 From: Santiago Villarreal Arley <115122095+Villarley@users.noreply.github.com> Date: Tue, 19 Aug 2025 20:26:04 -0600 Subject: [PATCH] Revert " Enables Open Comments on BuyerRequests" --- src/app.module.ts | 4 - .../entities/buyer-request.entity.ts | 4 - src/modules/comments/comments.module.ts | 12 --- .../controllers/comments.controller.ts | 38 ---------- .../comments/dto/create-comment.dto.ts | 8 -- .../comments/dto/update-comment.dto.ts | 4 - .../comments/entities/comment.entity.ts | 29 ------- .../comments/services/comments.service.ts | 66 ---------------- .../tests/comments.controller.spec.ts | 20 ----- .../comments/tests/comments.service.spec.ts | 18 ----- src/modules/users/entities/user.entity.ts | 4 - test/comments.e2e-spec.ts | 76 ------------------- test/factories/buyer-request.factory.ts | 23 ------ test/factories/user.factory.ts | 37 --------- 14 files changed, 343 deletions(-) delete mode 100644 src/modules/comments/comments.module.ts delete mode 100644 src/modules/comments/controllers/comments.controller.ts delete mode 100644 src/modules/comments/dto/create-comment.dto.ts delete mode 100644 src/modules/comments/dto/update-comment.dto.ts delete mode 100644 src/modules/comments/entities/comment.entity.ts delete mode 100644 src/modules/comments/services/comments.service.ts delete mode 100644 src/modules/comments/tests/comments.controller.spec.ts delete mode 100644 src/modules/comments/tests/comments.service.spec.ts delete mode 100644 test/comments.e2e-spec.ts delete mode 100644 test/factories/buyer-request.factory.ts delete mode 100644 test/factories/user.factory.ts diff --git a/src/app.module.ts b/src/app.module.ts index da6dd55..d6aa1a5 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -17,7 +17,6 @@ import { OrdersModule } from './modules/orders/orders.module'; import { BuyerRequestsModule } from './modules/buyer-requests/buyer-requests.module'; import { OffersModule } from './modules/offers/offers.module'; import { SupabaseModule } from './modules/supabase/supabase.module'; -import { CommentsModule } from './modules/comments/comments.module'; // Entities import { User } from './modules/users/entities/user.entity'; @@ -37,7 +36,6 @@ import { CouponUsage } from './modules/coupons/entities/coupon-usage.entity'; import { BuyerRequest } from './modules/buyer-requests/entities/buyer-request.entity'; import { Offer } from './modules/offers/entities/offer.entity'; import { OfferAttachment } from './modules/offers/entities/offer-attachment.entity'; -import { Comment } from './modules/comments/entities/comment.entity'; @Module({ imports: [ @@ -65,7 +63,6 @@ import { Comment } from './modules/comments/entities/comment.entity'; BuyerRequest, Offer, OfferAttachment, - Comment, ], synchronize: process.env.NODE_ENV !== 'production', logging: process.env.NODE_ENV === 'development', @@ -84,7 +81,6 @@ import { Comment } from './modules/comments/entities/comment.entity'; BuyerRequestsModule, OffersModule, SupabaseModule, - CommentsModule, ], }) export class AppModule {} diff --git a/src/modules/buyer-requests/entities/buyer-request.entity.ts b/src/modules/buyer-requests/entities/buyer-request.entity.ts index 4eb836c..291ae68 100644 --- a/src/modules/buyer-requests/entities/buyer-request.entity.ts +++ b/src/modules/buyer-requests/entities/buyer-request.entity.ts @@ -11,7 +11,6 @@ import { } from 'typeorm'; import { User } from '../../users/entities/user.entity'; import { Offer } from '../../offers/entities/offer.entity'; -import { Comment } from '@/modules/comments/entities/comment.entity'; export enum BuyerRequestStatus { OPEN = 'open', @@ -67,9 +66,6 @@ export class BuyerRequest { @OneToMany(() => Offer, (offer: Offer) => offer.buyerRequest) offers: Offer[]; - @OneToMany(() => Comment, (comment: Comment) => comment.buyerRequest) - comments: Comment[]; - @CreateDateColumn({ name: 'created_at' }) createdAt: Date; diff --git a/src/modules/comments/comments.module.ts b/src/modules/comments/comments.module.ts deleted file mode 100644 index cfdba5a..0000000 --- a/src/modules/comments/comments.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Module } from '@nestjs/common'; -import { CommentsService } from './services/comments.service'; -import { CommentsController } from './controllers/comments.controller'; -import { TypeOrmModule } from '@nestjs/typeorm'; -import { Comment } from './entities/comment.entity'; - -@Module({ - imports: [TypeOrmModule.forFeature([Comment])], - controllers: [CommentsController], - providers: [CommentsService], -}) -export class CommentsModule {} diff --git a/src/modules/comments/controllers/comments.controller.ts b/src/modules/comments/controllers/comments.controller.ts deleted file mode 100644 index a47cdfa..0000000 --- a/src/modules/comments/controllers/comments.controller.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete, UseGuards, ParseIntPipe, Req, Query } from '@nestjs/common'; -import { CommentsService } from '../services/comments.service'; -import { CreateCommentDto } from '../dto/create-comment.dto'; -import { JwtAuthGuard, RolesGuard } from '@/modules/auth'; -import { Request } from 'express'; -import { Roles } from '@/modules/shared/decorators/roles.decorator'; - -@Controller('comments') -export class CommentsController { - constructor(private readonly commentsService: CommentsService) {} - - @Post('/buyer-request/:id/comments') - @UseGuards(JwtAuthGuard) - async create( - @Param('id', ParseIntPipe) id: number, - @Body() createCommentDto: CreateCommentDto, - @Req() req: Request - ) { - const user = req.user as { id: number }; - return this.commentsService.create(id, user.id, createCommentDto); - } - - @Get('/buyer-request/:id/comments') - async getAll( - @Param('id', ParseIntPipe) id: number, - @Query('page', ParseIntPipe) page: number = 1 - ) { - return this.commentsService.findAllForBuyerRequest(id, page); - } - - @Delete('/comments/:id') - @UseGuards(JwtAuthGuard, RolesGuard) - @Roles('admin', 'buyer') - remove(@Param('id', ParseIntPipe) id: number, @Req() req: Request) { - const user = req.user as { id: number }; - return this.commentsService.remove(id, user.id); - } -} diff --git a/src/modules/comments/dto/create-comment.dto.ts b/src/modules/comments/dto/create-comment.dto.ts deleted file mode 100644 index c70413b..0000000 --- a/src/modules/comments/dto/create-comment.dto.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { IsNotEmpty, IsString, MinLength } from 'class-validator'; - -export class CreateCommentDto { - @IsString() - @IsNotEmpty() - @MinLength(1) - text: string; -} diff --git a/src/modules/comments/dto/update-comment.dto.ts b/src/modules/comments/dto/update-comment.dto.ts deleted file mode 100644 index 00d45a8..0000000 --- a/src/modules/comments/dto/update-comment.dto.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PartialType } from '@nestjs/swagger'; -import { CreateCommentDto } from './create-comment.dto'; - -export class UpdateCommentDto extends PartialType(CreateCommentDto) {} diff --git a/src/modules/comments/entities/comment.entity.ts b/src/modules/comments/entities/comment.entity.ts deleted file mode 100644 index 789b4d6..0000000 --- a/src/modules/comments/entities/comment.entity.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Column, Entity, PrimaryGeneratedColumn, CreateDateColumn, ManyToOne, JoinColumn } from 'typeorm'; -import { BuyerRequest } from '@/modules/buyer-requests/entities/buyer-request.entity'; -import { User } from '@/modules/users/entities/user.entity'; - -@Entity('comments') -export class Comment { - @PrimaryGeneratedColumn() - id: number; - - @Column() - buyerRequestId: number; - - @Column() - userId: number; - - @Column({ type: 'text' }) - text: string; - - @CreateDateColumn({ type: 'timestamp' }) - createdAt: Date; - - @ManyToOne(() => BuyerRequest, (buyerRequest) => buyerRequest.comments, { onDelete: 'CASCADE' }) - @JoinColumn({ name: 'buyerRequestId' }) - buyerRequest: BuyerRequest; - - @ManyToOne(() => User, (user) => user.comments, { onDelete: 'CASCADE', eager: true }) - @JoinColumn({ name: 'userId' }) - user: User; -} diff --git a/src/modules/comments/services/comments.service.ts b/src/modules/comments/services/comments.service.ts deleted file mode 100644 index c9577d0..0000000 --- a/src/modules/comments/services/comments.service.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { ForbiddenException, Injectable, NotFoundException } from '@nestjs/common'; -import { CreateCommentDto } from '../dto/create-comment.dto'; -import { UpdateCommentDto } from '../dto/update-comment.dto'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; -import { Comment } from '../entities/comment.entity'; - -@Injectable() -export class CommentsService { - constructor( - @InjectRepository(Comment) - private readonly commentRepository: Repository, - ) {} - - async create(buyerRequestId: number, userId: number, createCommentDto: CreateCommentDto) { - const comment = this.commentRepository.create({ - buyerRequestId, - userId, - ...createCommentDto, - }); - return this.commentRepository.save(comment); - } - - async findAllForBuyerRequest(buyerRequestId: number, page: number = 1, limit: number = 20) { - const [comments, total] = await this.commentRepository.findAndCount({ - where: { buyerRequestId }, - order: { createdAt: 'DESC' }, - skip: (page - 1) * limit, - take: limit, - }); - - return { - results: comments, - meta: { - total, - page, - limit, - lastPage: Math.ceil(total / limit), - }, - }; - } - - findOne(id: number) { - return `This action returns a #${id} comment`; - } - - update(id: number, updateCommentDto: UpdateCommentDto) { - return `This action updates a #${id} comment`; - } - - async remove(commentId: number, userId: number): Promise { - const comment = await this.commentRepository.findOne({ - where: { id: commentId }, - }); - - if (!comment) { - throw new NotFoundException('Comment not found'); - } - - if (comment.userId !== userId) { - throw new ForbiddenException('You can only delete your own comment'); - } - - await this.commentRepository.remove(comment); - } -} diff --git a/src/modules/comments/tests/comments.controller.spec.ts b/src/modules/comments/tests/comments.controller.spec.ts deleted file mode 100644 index b3ae635..0000000 --- a/src/modules/comments/tests/comments.controller.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { CommentsController } from '../controllers/comments.controller'; -import { CommentsService } from '../services/comments.service'; - -describe('CommentsController', () => { - let controller: CommentsController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [CommentsController], - providers: [CommentsService], - }).compile(); - - controller = module.get(CommentsController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/src/modules/comments/tests/comments.service.spec.ts b/src/modules/comments/tests/comments.service.spec.ts deleted file mode 100644 index b65ac06..0000000 --- a/src/modules/comments/tests/comments.service.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { CommentsService } from '../services/comments.service'; - -describe('CommentsService', () => { - let service: CommentsService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [CommentsService], - }).compile(); - - service = module.get(CommentsService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/src/modules/users/entities/user.entity.ts b/src/modules/users/entities/user.entity.ts index eb000db..f191c38 100644 --- a/src/modules/users/entities/user.entity.ts +++ b/src/modules/users/entities/user.entity.ts @@ -10,7 +10,6 @@ import { Order } from '../../orders/entities/order.entity'; import { UserRole } from '../../auth/entities/user-role.entity'; import { Notification } from '../../notifications/entities/notification.entity'; import { Wishlist } from '../../wishlist/entities/wishlist.entity'; -import { Comment } from '@/modules/comments/entities/comment.entity'; @Entity('users') export class User { @@ -38,9 +37,6 @@ export class User { @OneToMany(() => Wishlist, (wishlist) => wishlist.user) wishlist: Wishlist[]; - @OneToMany(() => Comment, (comment) => comment.user) - comments: Comment[]; - @CreateDateColumn() createdAt: Date; diff --git a/test/comments.e2e-spec.ts b/test/comments.e2e-spec.ts deleted file mode 100644 index ba2a069..0000000 --- a/test/comments.e2e-spec.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { INestApplication, ValidationPipe } from '@nestjs/common'; -import request from 'supertest'; -import { AppModule } from '../src/app.module'; -import { createTestUser } from './factories/user.factory'; -import { createBuyerRequest } from './factories/buyer-request.factory'; -import { getConnection } from 'typeorm'; - -describe('Comments Module (e2e)', () => { - let app: INestApplication; - let userA: any; - let userB: any; - let buyerRequestId: number; - let commentId: number; - - beforeAll(async () => { - const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [AppModule], - }).compile(); - - app = moduleFixture.createNestApplication(); - app.useGlobalPipes(new ValidationPipe({ whitelist: true })); - await app.init(); - - // Create users with wallet-based auth - userA = await createTestUser(app); - userB = await createTestUser(app); - - const buyerRequest = await createBuyerRequest(app, userA.cookie); - buyerRequestId = buyerRequest.id; - }); - - afterAll(async () => { - await getConnection().dropDatabase(); - await app.close(); - }); - - it('✅ should allow authenticated user to post a comment', async () => { - const res = await request(app.getHttpServer()) - .post(`/api/v1/buyer-requests/${buyerRequestId}/comments`) - .set('Cookie', userA.cookie) - .send({ text: 'Is this still available?' }); - - expect(res.status).toBe(201); - expect(res.body.data).toHaveProperty('id'); - expect(res.body.data.text).toBe('Is this still available?'); - - commentId = res.body.data.id; - }); - - it('❌ should fail to post comment when unauthenticated', async () => { - const res = await request(app.getHttpServer()) - .post(`/api/v1/buyer-requests/${buyerRequestId}/comments`) - .send({ text: 'Can I help?' }); - - expect(res.status).toBe(401); - }); - - it('❌ should not allow non-owner to delete comment', async () => { - const res = await request(app.getHttpServer()) - .delete(`/api/v1/comments/${commentId}`) - .set('Cookie', userB.cookie); - - expect(res.status).toBe(403); - }); - - it('✅ should fetch all comments for a buyer request', async () => { - const res = await request(app.getHttpServer()) - .get(`/api/v1/buyer-requests/${buyerRequestId}/comments`); - - expect(res.status).toBe(200); - expect(Array.isArray(res.body.data)).toBe(true); - expect(res.body.meta).toHaveProperty('total'); - expect(res.body.meta).toHaveProperty('page'); - }); -}); diff --git a/test/factories/buyer-request.factory.ts b/test/factories/buyer-request.factory.ts deleted file mode 100644 index 362307e..0000000 --- a/test/factories/buyer-request.factory.ts +++ /dev/null @@ -1,23 +0,0 @@ -import request from 'supertest'; -import { INestApplication } from '@nestjs/common'; - -let requestCounter = 0; - -export async function createBuyerRequest(app: INestApplication, cookie: string, overrides = {}) { - requestCounter++; - - const res = await request(app.getHttpServer()) - .post('/api/v1/buyer-requests') - .set('Cookie', cookie) - .send({ - title: `Test Request ${requestCounter}`, - description: 'Test description', - budgetMin: 100, - budgetMax: 200, - categoryId: 1, - expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), - ...overrides, - }); - - return res.body.data || res.body; -} diff --git a/test/factories/user.factory.ts b/test/factories/user.factory.ts deleted file mode 100644 index 85f78dd..0000000 --- a/test/factories/user.factory.ts +++ /dev/null @@ -1,37 +0,0 @@ -import request from 'supertest'; -import { INestApplication } from '@nestjs/common'; -import { Keypair } from 'stellar-sdk'; - -let userCounter = 0; - -export async function createTestUser(app: INestApplication, overrides = {}) { - userCounter++; - - const keypair = Keypair.random(); - const walletAddress = keypair.publicKey(); - const message = `StarShop Authentication Challenge - ${walletAddress} - ${Date.now()}`; - const signatureBuffer = keypair.sign(Buffer.from(message, 'utf8')); - const signature = signatureBuffer.toString('base64'); - - const registerRes = await request(app.getHttpServer()) - .post('/api/v1/auth/register') - .send({ - walletAddress, - signature, - message, - name: `User ${userCounter}`, - email: `user${userCounter}@test.com`, - ...overrides, - }); - - const cookies = registerRes.headers['set-cookie']; - const tokenCookie = Array.isArray(cookies) ? cookies.find((c) => c.startsWith('token=')) : undefined; - - return { - user: registerRes.body.data.user, - walletAddress, - message, - signature, - cookie: tokenCookie, - }; -}