From 74391f8a46d1f4b7edc099538262a6b592013aa8 Mon Sep 17 00:00:00 2001 From: aarbit Date: Mon, 18 May 2026 17:10:52 -0500 Subject: [PATCH] Adds Team members list endpoint and Hunt details update endpoint --- .../scavengerhuntapi/controller/HuntController.kt | 10 ++++++++++ .../scavengerhuntapi/controller/TeamController.kt | 8 ++++++++ .../model/converter/HunterConverter.kt | 5 +++++ .../model/request/HuntUpdateRequest.kt | 10 ++++++++++ .../model/response/HunterSummaryResponse.kt | 8 ++++++++ .../scavengerhuntapi/service/HuntService.kt | 13 +++++++++++++ .../scavengerhuntapi/service/TeamService.kt | 7 +++++++ 7 files changed, 61 insertions(+) create mode 100644 src/main/kotlin/net/halfbinary/scavengerhuntapi/model/request/HuntUpdateRequest.kt create mode 100644 src/main/kotlin/net/halfbinary/scavengerhuntapi/model/response/HunterSummaryResponse.kt diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/HuntController.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/HuntController.kt index 0c40172..1626792 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/HuntController.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/HuntController.kt @@ -9,11 +9,13 @@ import net.halfbinary.scavengerhuntapi.model.converter.toDomain import net.halfbinary.scavengerhuntapi.model.converter.toResponse import net.halfbinary.scavengerhuntapi.model.request.HuntCreateRequest import net.halfbinary.scavengerhuntapi.model.request.HuntStatus +import net.halfbinary.scavengerhuntapi.model.request.HuntUpdateRequest import net.halfbinary.scavengerhuntapi.model.response.HuntResponse import net.halfbinary.scavengerhuntapi.service.HuntService import org.springframework.http.ResponseEntity import org.springframework.security.access.prepost.PreAuthorize import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PatchMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody @@ -52,6 +54,14 @@ class HuntController(private val huntService: HuntService) { return ResponseEntity.ok(huntService.createHunt(huntRequest.toDomain()).toResponse()) } + @PreAuthorize("hasRole('ADMIN')") + @Tag(name = "Admin") + @PatchMapping("/{id}") + @Operation(summary = "Updates details of the specified Hunt") + fun updateHunt(@PathVariable("id") huntId: HuntId, @RequestBody body: HuntUpdateRequest): ResponseEntity { + return ResponseEntity.ok(huntService.updateHunt(huntId, body).toResponse()) + } + @PreAuthorize("hasRole('ADMIN')") @Tag(name = "Admin") @GetMapping("/hunter/{hunterId}") diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/TeamController.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/TeamController.kt index bb1ca5d..f9edf2e 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/TeamController.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/TeamController.kt @@ -7,7 +7,9 @@ import net.halfbinary.scavengerhuntapi.model.ItemId import net.halfbinary.scavengerhuntapi.model.PhotoId import net.halfbinary.scavengerhuntapi.model.TeamId import net.halfbinary.scavengerhuntapi.model.converter.toResponse +import net.halfbinary.scavengerhuntapi.model.converter.toSummaryResponse import net.halfbinary.scavengerhuntapi.model.request.TeamRequest +import net.halfbinary.scavengerhuntapi.model.response.HunterSummaryResponse import net.halfbinary.scavengerhuntapi.model.response.PhotoResponse import net.halfbinary.scavengerhuntapi.model.response.TeamItemResponse import net.halfbinary.scavengerhuntapi.model.response.TeamResponse @@ -47,6 +49,12 @@ class TeamController(private val teamService: TeamService, private val photoServ return ResponseEntity.ok(teamService.getTeamFromHunt(huntId, teamId).toResponse()) } + @GetMapping("/{teamId}/hunter") + @Operation(summary = "Get all Hunters for the specified Team in the specified Hunt") + fun getHuntersForTeam(@PathVariable huntId: HuntId, @PathVariable teamId: TeamId): ResponseEntity> { + return ResponseEntity.ok(teamService.getHuntersForTeam(huntId, teamId).map { it.toSummaryResponse() }) + } + @GetMapping("/{teamId}/item/{itemId}") @Operation(summary = "Get found/not found status about the Item for the specified Team, Hunt, and Item") fun getItemForTeam(@PathVariable huntId: HuntId, diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/converter/HunterConverter.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/converter/HunterConverter.kt index c82ac14..d529d8d 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/converter/HunterConverter.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/converter/HunterConverter.kt @@ -3,6 +3,7 @@ package net.halfbinary.scavengerhuntapi.model.converter import net.halfbinary.scavengerhuntapi.model.domain.Hunter import net.halfbinary.scavengerhuntapi.model.record.HunterRecord import net.halfbinary.scavengerhuntapi.model.request.HunterSignupRequest +import net.halfbinary.scavengerhuntapi.model.response.HunterSummaryResponse fun HunterSignupRequest.toDomain(): Hunter { return Hunter( @@ -19,4 +20,8 @@ fun Hunter.toRecord(): HunterRecord { fun HunterRecord.toDomain(): Hunter { return Hunter(id, email, name, password, isAdmin) +} + +fun Hunter.toSummaryResponse(): HunterSummaryResponse { + return HunterSummaryResponse(id, name) } \ No newline at end of file diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/request/HuntUpdateRequest.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/request/HuntUpdateRequest.kt new file mode 100644 index 0000000..186d17a --- /dev/null +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/request/HuntUpdateRequest.kt @@ -0,0 +1,10 @@ +package net.halfbinary.scavengerhuntapi.model.request + +import java.time.LocalDateTime + +data class HuntUpdateRequest( + val title: String?, + val startDateTime: LocalDateTime?, + val endDateTime: LocalDateTime?, + val isTerminated: Boolean? +) diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/response/HunterSummaryResponse.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/response/HunterSummaryResponse.kt new file mode 100644 index 0000000..003bba8 --- /dev/null +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/response/HunterSummaryResponse.kt @@ -0,0 +1,8 @@ +package net.halfbinary.scavengerhuntapi.model.response + +import net.halfbinary.scavengerhuntapi.model.HunterId + +data class HunterSummaryResponse( + val id: HunterId, + val name: String +) \ No newline at end of file diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HuntService.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HuntService.kt index e268c21..9dcf57c 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HuntService.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HuntService.kt @@ -11,6 +11,7 @@ import net.halfbinary.scavengerhuntapi.model.domain.Hunt import net.halfbinary.scavengerhuntapi.model.domain.HuntItem import net.halfbinary.scavengerhuntapi.model.domain.Item import net.halfbinary.scavengerhuntapi.model.request.HuntStatus +import net.halfbinary.scavengerhuntapi.model.request.HuntUpdateRequest import net.halfbinary.scavengerhuntapi.model.request.ItemUpdateRequest import net.halfbinary.scavengerhuntapi.repository.HuntItemRepository import net.halfbinary.scavengerhuntapi.repository.HuntRepository @@ -68,6 +69,18 @@ class HuntService( return huntRepository.save(hunt.toRecord()).toDomain() } + fun updateHunt(huntId: HuntId, request: HuntUpdateRequest): Hunt { + val existing = huntRepository.findByIdOrNull(huntId) + ?: throw NotFoundException("No hunt with id $huntId found") + val updated = existing.copy( + title = request.title ?: existing.title, + startDateTime = request.startDateTime ?: existing.startDateTime, + endDateTime = request.endDateTime ?: existing.endDateTime, + isTerminated = request.isTerminated ?: existing.isTerminated + ) + return huntRepository.save(updated).toDomain() + } + fun getItemsForHunt(huntId: HuntId, email: String): List { val hunt = huntRepository.findByIdOrNull(huntId)?.toDomain() ?: throw NotFoundException("No hunt with id $huntId found") val hunter = hunterService.getHunterByEmail(email) diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/TeamService.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/TeamService.kt index baefbf2..9ec2343 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/TeamService.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/TeamService.kt @@ -6,6 +6,7 @@ import net.halfbinary.scavengerhuntapi.model.HunterId import net.halfbinary.scavengerhuntapi.model.TeamId import net.halfbinary.scavengerhuntapi.model.converter.toDomain import net.halfbinary.scavengerhuntapi.model.converter.toRecord +import net.halfbinary.scavengerhuntapi.model.domain.Hunter import net.halfbinary.scavengerhuntapi.model.domain.Team import net.halfbinary.scavengerhuntapi.model.domain.TeamHunt import net.halfbinary.scavengerhuntapi.model.record.HunterTeamRecord @@ -54,6 +55,12 @@ class TeamService( return hunterTeamRepository.findByTeamId(teamId).map { it.hunterId }.toSet() } + fun getHuntersForTeam(huntId: HuntId, teamId: TeamId): List { + getTeamFromHunt(huntId, teamId) + val hunterIds = getHunterIdsForTeam(teamId) + return hunterRepository.findAllById(hunterIds).map { it.toDomain() } + } + fun joinTeam(teamId: TeamId, email: String) { val hunter = hunterRepository.findByEmail(email) ?: throw NotFoundException("No hunter with email $email found") hunterTeamRepository.save(HunterTeamRecord(UUID.randomUUID(), hunter.id, teamId))