From 34e6c794bcfa3a18f72369440b66f2b578c01e38 Mon Sep 17 00:00:00 2001 From: Halo11112222 Date: Wed, 15 Apr 2026 15:37:56 +0800 Subject: [PATCH 1/2] feat: implement soft delete for bounties - Add deletedAt filter to findOne, get, findAll, and search queries - Add remove() method that sets deletedAt timestamp instead of hard delete - Ensures deleted bounties don't appear in any listings --- backend/src/bounty/bounty.service.ts | 29 +++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/backend/src/bounty/bounty.service.ts b/backend/src/bounty/bounty.service.ts index 3085997..3926ab3 100644 --- a/backend/src/bounty/bounty.service.ts +++ b/backend/src/bounty/bounty.service.ts @@ -35,7 +35,7 @@ export class BountyService { async findOne(id: string) { const bounty = await this.prisma.bounty.findUnique({ - where: { id }, + where: { id, deletedAt: null }, include: { creator: true, assignee: true, @@ -47,7 +47,7 @@ export class BountyService { async get(id: string) { const bounty = await this.prisma.bounty.findUnique({ - where: { id }, + where: { id, deletedAt: null }, include: { creator: true, assignee: true }, }); if (!bounty) throw new NotFoundException('Bounty not found'); @@ -65,7 +65,7 @@ export class BountyService { const page = filters.page ?? 0; const size = filters.size ?? 20; - const where: any = {}; + const where: any = { deletedAt: null }; // Default to OPEN status if no status filter provided if (filters.status) { @@ -108,7 +108,7 @@ export class BountyService { } : {}; - const where: any = {}; + const where: any = { deletedAt: null }; if (Object.keys(text).length) where.AND = [text]; if (guildId) where.guildId = guildId; @@ -522,4 +522,23 @@ export class BountyService { }; } } -} + + /** + * Soft delete a bounty (sets deletedAt timestamp) + * Only the creator can delete their own bounty + */ + async remove(id: string, userId: string) { + const bounty = await this.prisma.bounty.findUnique({ + where: { id, deletedAt: null }, + }); + if (!bounty) throw new NotFoundException('Bounty not found'); + if (bounty.creatorId !== userId) + throw new ForbiddenException('Only creator can delete bounty'); + + return this.prisma.bounty.update({ + where: { id }, + data: { deletedAt: new Date() }, + }); + } + +} \ No newline at end of file From c6735477b4271845b4aea86753c8342329cd1637 Mon Sep 17 00:00:00 2001 From: Halo11112222 Date: Wed, 15 Apr 2026 15:39:18 +0800 Subject: [PATCH 2/2] feat: add DELETE /bounties/:id endpoint - Adds soft delete endpoint that calls service.remove() - Requires JWT auth (only creator can delete) --- backend/src/bounty/bounty.controller.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/backend/src/bounty/bounty.controller.ts b/backend/src/bounty/bounty.controller.ts index 4b61985..58867de 100644 --- a/backend/src/bounty/bounty.controller.ts +++ b/backend/src/bounty/bounty.controller.ts @@ -157,4 +157,15 @@ export class BountyController { ) { return this.service.reviewWork(id, dto, req.user.userId); } -} + + /** + * Soft delete a bounty + * DELETE /bounties/:id + */ + @UseGuards(JwtAuthGuard) + @Delete(':id') + async remove(@Param('id') id: string, @Request() req: any) { + return this.service.remove(id, req.user.userId); + } + +} \ No newline at end of file