From aae7f9f1e5f396248b635cfe2407e26095aa9da0 Mon Sep 17 00:00:00 2001 From: iwanplayhalo Date: Tue, 7 Oct 2025 17:56:29 -0400 Subject: [PATCH 1/5] implemented soft delete team with hard deletion of reservations --- src/modules/team/team.controller.ts | 38 +++++++++++++++++++++++++++++ src/modules/team/team.module.ts | 3 ++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/modules/team/team.controller.ts b/src/modules/team/team.controller.ts index f84d2c86..02f148b1 100644 --- a/src/modules/team/team.controller.ts +++ b/src/modules/team/team.controller.ts @@ -9,6 +9,7 @@ import { Param, Patch, Post, + Delete, Query, UseFilters, ValidationPipe, @@ -16,6 +17,7 @@ import { import { InjectRepository, Repository } from "common/objection"; import { Team, TeamEntity } from "entities/team.entity"; import { User } from "entities/user.entity"; +import { Reservation } from "entities/reservation.entity"; import { Hackathon } from "entities/hackathon.entity"; import { ApiProperty, ApiTags, OmitType, PartialType } from "@nestjs/swagger"; import { Role, Roles } from "common/gcp"; @@ -92,6 +94,8 @@ export class TeamController { private readonly teamRepo: Repository, @InjectRepository(User) private readonly userRepo: Repository, + @InjectRepository(Reservation) + private readonly reservationRepo: Repository, ) {} @Get("/") @@ -462,4 +466,38 @@ export class TeamController { const updatedTeam = await this.teamRepo.patchOne(id, updateData).exec(); return updatedTeam; } + + @Delete(":id") + @Roles(Role.NONE) + @ApiDoc({ + summary: "Soft delete a team", + params: [ + { + name: "id", + description: "ID must be set to a team's ID", + }, + ], + response: { + ok: { type: TeamEntity }, + }, + auth: Role.TEAM, + }) + async deleteOne(@Param("id") id: string) { + const existingTeam = await this.teamRepo.findOne(id).exec(); + if (!existingTeam) { + throw new NotFoundException("Team not found"); + } + if (!existingTeam.isActive) { + throw new BadRequestException("Team is already inactive"); + } + // Delete all reservations associated with team + await this.reservationRepo + .findAll() + .raw() + .where("teamId", id) + .delete(); + + const team = await this.teamRepo.patchOne(id, { isActive: false }).exec(); + return team; + } } diff --git a/src/modules/team/team.module.ts b/src/modules/team/team.module.ts index 60890356..f8a8cf2a 100644 --- a/src/modules/team/team.module.ts +++ b/src/modules/team/team.module.ts @@ -4,9 +4,10 @@ import { Team } from "entities/team.entity"; import { User } from "entities/user.entity"; import { TeamController } from "./team.controller"; import { Hackathon } from "entities/hackathon.entity"; +import { Reservation } from "entities/reservation.entity"; @Module({ - imports: [ObjectionModule.forFeature([Team, User, Hackathon])], + imports: [ObjectionModule.forFeature([Team, User, Hackathon, Reservation])], controllers: [TeamController], }) export class TeamModule {} From 92685435205b99e14713fdd08b1674b579c19a77 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 04:29:53 +0000 Subject: [PATCH 2/5] chore(deps): update actions/setup-node action to v6 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7f26598b..73e90983 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v5 - name: Setup Node.js - uses: actions/setup-node@v5 + uses: actions/setup-node@v6 with: node-version: '24' cache: 'yarn' From db2a878bca0c1078b9a2c0f023cab142bfd874d6 Mon Sep 17 00:00:00 2001 From: praptik01 Date: Fri, 17 Oct 2025 20:43:39 -0400 Subject: [PATCH 3/5] set up delete service --- src/modules/photo/photo.controller.ts | 40 +++++++++++++++++++++++++-- src/modules/photo/photo.service.ts | 5 ++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/modules/photo/photo.controller.ts b/src/modules/photo/photo.controller.ts index fa0b977a..68f95306 100644 --- a/src/modules/photo/photo.controller.ts +++ b/src/modules/photo/photo.controller.ts @@ -1,12 +1,15 @@ import { BadRequestException, + Body, Controller, + Delete, Get, InternalServerErrorException, + Param, Post, - UseInterceptors, + Query, Req, - Body, + UseInterceptors, UnauthorizedException, } from "@nestjs/common"; import { Request } from "express"; @@ -103,4 +106,37 @@ export class PhotoController { throw new InternalServerErrorException("Failed to fetch photos"); } } + + @Delete(":photoId") + @Roles(Role.NONE) + @ApiDoc({ + summary: "Delete a photo", + params: [{ name: "photoId" }], + query: [ + { + name: "originalName", + description: "Original filename including the extension", + }, + ], + response: { noContent: true }, + }) + async deletePhoto( + @Param("photoId") photoId: string, + @Query("originalName") originalName: string, + ): Promise { + if (!photoId) { + throw new BadRequestException("photoId is required"); + } + + if (!originalName) { + throw new BadRequestException("originalName is required"); + } + + try { + await this.photoService.deletePhoto(photoId, originalName); + } catch (error) { + console.error("Error deleting photo:", error); + throw new InternalServerErrorException("Failed to delete photo"); + } + } } diff --git a/src/modules/photo/photo.service.ts b/src/modules/photo/photo.service.ts index 04a499ed..3875aa35 100644 --- a/src/modules/photo/photo.service.ts +++ b/src/modules/photo/photo.service.ts @@ -62,4 +62,9 @@ export class PhotoService { : new Date(), })); } + deletePhoto(photoId: string, originalName: string) { + return this.photoBucket + .file(this.getPhotoFileName(photoId, originalName)) + .delete({ ignoreNotFound: true }); + } } From a254a3ff3ddec1fd30db8f3de9d34f7b9694fccd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 Oct 2025 01:42:52 +0000 Subject: [PATCH 4/5] fix(deps): update dependency googleapis to v164 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c6ea0183..2b4600ef 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "fast-xml-parser": "^5.2.3", "firebase": "^12.0.0", "firebase-admin": "^13.0.2", - "googleapis": "^161.0.0", + "googleapis": "^164.0.0", "handlebars": "^4.7.8", "jsonwebtoken": "^9.0.2", "jwt-decode": "^4.0.0", diff --git a/yarn.lock b/yarn.lock index 9b9b8125..b05c4b07 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4498,10 +4498,10 @@ googleapis-common@^8.0.0: qs "^6.7.0" url-template "^2.0.8" -googleapis@^161.0.0: - version "161.0.0" - resolved "https://registry.npmjs.org/googleapis/-/googleapis-161.0.0.tgz" - integrity sha512-JZy2cWMxgUF8E09KHzplI+z+FVG8NWDB/bsf4xevt9Um4bInb0X1qaG9qpDn49DHT5HsU0mOp3EOBGb8+AdE3Q== +googleapis@^164.0.0: + version "164.0.0" + resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-164.0.0.tgz#22945308a3b3cba938f762fd710fb761db2f6a82" + integrity sha512-aR2larBEvu6+HVC4Puu87T41/OA3WjVw2tQRYAMKit2kC95daFacIoDF70DeC4p9M/H5eZSalBJV1FOypR808A== dependencies: google-auth-library "^10.2.0" googleapis-common "^8.0.0" From df01cbdcdd473918d3ec3f3dccdcbbf44e6af9f1 Mon Sep 17 00:00:00 2001 From: Kanishk Sachdev Date: Sun, 19 Oct 2025 23:45:44 -0400 Subject: [PATCH 5/5] reservation fixes --- src/modules/team/team.controller.ts | 46 ++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/src/modules/team/team.controller.ts b/src/modules/team/team.controller.ts index 02f148b1..6fb8652a 100644 --- a/src/modules/team/team.controller.ts +++ b/src/modules/team/team.controller.ts @@ -360,6 +360,39 @@ export class TeamController { } const team = await this.teamRepo.patchOne(id, data).exec(); + + // Check if all members have been removed - if so, soft delete the team + const updatedMembers = [ + team.member1, + team.member2, + team.member3, + team.member4, + team.member5, + ].filter(Boolean); + + if (updatedMembers.length === 0) { + // No members left - soft delete team and all associated reservations + console.log( + `All members removed from team ${id}, auto soft-deleting team and reservations`, + ); + + const deletedReservationsCount = await this.reservationRepo + .findAll() + .raw() + .where("teamId", id) + .delete(); + + console.log( + `Deleted ${deletedReservationsCount} reservations for team ${id}`, + ); + + const deletedTeam = await this.teamRepo + .patchOne(id, { isActive: false }) + .exec(); + + return deletedTeam; + } + return team; } @@ -470,7 +503,7 @@ export class TeamController { @Delete(":id") @Roles(Role.NONE) @ApiDoc({ - summary: "Soft delete a team", + summary: "Soft delete a team and remove all associated reservations", params: [ { name: "id", @@ -490,13 +523,18 @@ export class TeamController { if (!existingTeam.isActive) { throw new BadRequestException("Team is already inactive"); } - // Delete all reservations associated with team - await this.reservationRepo + + // Delete all reservations associated with team before soft-deleting + const deletedReservationsCount = await this.reservationRepo .findAll() .raw() .where("teamId", id) .delete(); - + + console.log( + `Deleted ${deletedReservationsCount} reservations for team ${id}`, + ); + const team = await this.teamRepo.patchOne(id, { isActive: false }).exec(); return team; }