diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/TeamController.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/TeamController.kt index c603979..66a2fd2 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/TeamController.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/TeamController.kt @@ -1,10 +1,18 @@ package net.halfbinary.scavengerhuntapi.controller +import io.swagger.v3.oas.annotations.Operation import jakarta.validation.Valid import net.halfbinary.scavengerhuntapi.model.HuntId +import net.halfbinary.scavengerhuntapi.model.ItemId +import net.halfbinary.scavengerhuntapi.model.TeamId +import net.halfbinary.scavengerhuntapi.model.converter.toResponse import net.halfbinary.scavengerhuntapi.model.request.TeamRequest +import net.halfbinary.scavengerhuntapi.model.response.PhotoResponse +import net.halfbinary.scavengerhuntapi.model.response.TeamItemResponse import net.halfbinary.scavengerhuntapi.model.response.TeamResponse +import net.halfbinary.scavengerhuntapi.service.TeamService import org.springframework.http.ResponseEntity +import org.springframework.security.core.Authentication import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping @@ -13,15 +21,44 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController -@RequestMapping("hunt/{id}/team") -class TeamController { +@RequestMapping("hunt/{huntId}/team") +class TeamController(private val teamService: TeamService) { @GetMapping - fun listHuntTeams(@PathVariable id: HuntId): ResponseEntity> { - TODO() + @Operation(summary = "List all teams for the specified hunt") + fun listHuntTeams(@PathVariable huntId: HuntId): ResponseEntity> { + return ResponseEntity.ok(teamService.getListOfTeamsForHunt(huntId).map { it.toResponse()}) } @PostMapping - fun createHuntTeam(@PathVariable id: HuntId, @Valid @RequestBody team: TeamRequest) { + @Operation(summary = "Create a new team for the specified hunt") + fun createHuntTeam(@PathVariable huntId: HuntId, @Valid @RequestBody team: TeamRequest) { + val teamResponse = teamService.createTeam(team.name) + teamService.addTeamToHunt(huntId, teamResponse.id) + } + + @GetMapping("/{teamId}") + fun getTeam(@PathVariable huntId: HuntId, @PathVariable teamId: TeamId): ResponseEntity { + return ResponseEntity.ok(teamService.getTeamFromHunt(huntId, teamId).toResponse()) + } + + @PostMapping("/{teamId}") + fun joinTeamForHunt(@PathVariable huntId: HuntId, @PathVariable teamId: TeamId, authentication: Authentication) { + teamService.joinTeam(teamId, authentication.name) + } + + @GetMapping("/{teamId}/item/{itemId}") + fun getItemsForTeam(@PathVariable huntId: HuntId, + @PathVariable teamId: TeamId, + @PathVariable itemId: ItemId): ResponseEntity { TODO() } + + @GetMapping("/{teamId}/item/{itemId}/photo") + fun getPhotosForTeam(@PathVariable huntId: HuntId, + @PathVariable teamId: TeamId, + @PathVariable itemId: ItemId): ResponseEntity { + TODO() + } + + } \ No newline at end of file diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/FoundStatus.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/FoundStatus.kt index 79caaa3..7e80c2c 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/FoundStatus.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/FoundStatus.kt @@ -1,6 +1,7 @@ package net.halfbinary.scavengerhuntapi.model enum class FoundStatus { + NOT_FOUND, SUBMITTED, APPROVED, REJECTED, diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/TypeAlias.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/TypeAlias.kt index 589453e..14dcd6e 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/TypeAlias.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/TypeAlias.kt @@ -7,4 +7,6 @@ typealias HuntId = UUID typealias HunterId = UUID typealias ItemId = UUID typealias TeamId = UUID -typealias RefreshId = UUID \ No newline at end of file +typealias RefreshId = UUID +typealias TeamHuntId = UUID +typealias PhotoId = UUID \ No newline at end of file diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/converter/TeamHuntConverter.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/converter/TeamHuntConverter.kt new file mode 100644 index 0000000..00d2624 --- /dev/null +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/converter/TeamHuntConverter.kt @@ -0,0 +1,16 @@ +package net.halfbinary.scavengerhuntapi.model.converter + +import net.halfbinary.scavengerhuntapi.model.domain.Team +import net.halfbinary.scavengerhuntapi.model.domain.TeamHunt +import net.halfbinary.scavengerhuntapi.model.record.TeamHuntRecord +import net.halfbinary.scavengerhuntapi.model.record.TeamRecord +import net.halfbinary.scavengerhuntapi.model.request.TeamRequest +import net.halfbinary.scavengerhuntapi.model.response.TeamResponse + +fun TeamHunt.toRecord(): TeamHuntRecord { + return TeamHuntRecord(id, teamId, huntId) +} + +fun TeamHuntRecord.toDomain(): TeamHunt { + return TeamHunt(id, teamId, huntId) +} \ No newline at end of file diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/TeamHunt.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/TeamHunt.kt new file mode 100644 index 0000000..6b402c3 --- /dev/null +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/TeamHunt.kt @@ -0,0 +1,12 @@ +package net.halfbinary.scavengerhuntapi.model.domain + +import net.halfbinary.scavengerhuntapi.model.HuntId +import net.halfbinary.scavengerhuntapi.model.TeamHuntId +import net.halfbinary.scavengerhuntapi.model.TeamId +import java.util.UUID + +data class TeamHunt( + val id: TeamHuntId = TeamHuntId.randomUUID(), + val teamId: TeamId, + val huntId: HuntId +) diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/record/TeamHuntRecord.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/record/TeamHuntRecord.kt index 32d4204..4f251e3 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/record/TeamHuntRecord.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/record/TeamHuntRecord.kt @@ -4,6 +4,7 @@ import jakarta.persistence.Entity import jakarta.persistence.Id import jakarta.persistence.Table import net.halfbinary.scavengerhuntapi.model.HuntId +import net.halfbinary.scavengerhuntapi.model.TeamHuntId import net.halfbinary.scavengerhuntapi.model.TeamId import java.util.* @@ -11,7 +12,7 @@ import java.util.* @Table(name = "team_hunt") data class TeamHuntRecord( @Id - val id: UUID, + val id: TeamHuntId, val teamId: TeamId, val huntId: HuntId ) diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/request/JoinTeamRequest.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/request/JoinTeamRequest.kt new file mode 100644 index 0000000..89447e4 --- /dev/null +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/request/JoinTeamRequest.kt @@ -0,0 +1,9 @@ +package net.halfbinary.scavengerhuntapi.model.request + +import jakarta.validation.constraints.NotBlank +import net.halfbinary.scavengerhuntapi.model.TeamId + +data class JoinTeamRequest( + @field:NotBlank + val teamId: TeamId +) diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/response/PhotoResponse.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/response/PhotoResponse.kt new file mode 100644 index 0000000..dfb0e68 --- /dev/null +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/response/PhotoResponse.kt @@ -0,0 +1,10 @@ +package net.halfbinary.scavengerhuntapi.model.response + +import net.halfbinary.scavengerhuntapi.model.PhotoId +import java.time.LocalDateTime + +data class PhotoResponse( + val id: PhotoId, + val hunterName: String, + val photoUploadDateTime: LocalDateTime +) diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/response/TeamItemResponse.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/response/TeamItemResponse.kt new file mode 100644 index 0000000..ef8ced0 --- /dev/null +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/response/TeamItemResponse.kt @@ -0,0 +1,11 @@ +package net.halfbinary.scavengerhuntapi.model.response + +import net.halfbinary.scavengerhuntapi.model.FoundStatus +import net.halfbinary.scavengerhuntapi.model.ItemId + +data class TeamItemResponse( + val id: ItemId, + val itemName: String, + val hunterName: String, + val itemFoundStatus: FoundStatus +) diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/HunterTeamRepository.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/HunterTeamRepository.kt new file mode 100644 index 0000000..46b375b --- /dev/null +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/HunterTeamRepository.kt @@ -0,0 +1,9 @@ +package net.halfbinary.scavengerhuntapi.repository + +import net.halfbinary.scavengerhuntapi.model.record.HunterTeamRecord +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository +import java.util.UUID + +@Repository +interface HunterTeamRepository : JpaRepository diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/TeamHuntRepository.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/TeamHuntRepository.kt new file mode 100644 index 0000000..4fc728b --- /dev/null +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/TeamHuntRepository.kt @@ -0,0 +1,28 @@ +package net.halfbinary.scavengerhuntapi.repository + +import net.halfbinary.scavengerhuntapi.model.HuntId +import net.halfbinary.scavengerhuntapi.model.TeamId +import net.halfbinary.scavengerhuntapi.model.record.HuntRecord +import net.halfbinary.scavengerhuntapi.model.record.TeamHuntRecord +import net.halfbinary.scavengerhuntapi.model.record.TeamRecord +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.stereotype.Repository +import java.util.* + +@Repository +interface TeamHuntRepository : JpaRepository { + @Query(""" + SELECT h.* FROM hunt h + INNER JOIN team_hunt th ON h.id = th.hunt_id + WHERE th.team_id = :teamId + """, nativeQuery = true) + fun findHuntsByTeamId(teamId: TeamId): List + + @Query(""" + SELECT t.* FROM team t + INNER JOIN team_hunt th ON t.id = th.team_id + WHERE th.hunt_id = :huntId + """, nativeQuery = true) + fun findTeamsByHuntId(huntId: HuntId): List +} \ No newline at end of file diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/TeamRepository.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/TeamRepository.kt index 8cf9575..31644d0 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/TeamRepository.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/TeamRepository.kt @@ -1,5 +1,6 @@ package net.halfbinary.scavengerhuntapi.repository +import net.halfbinary.scavengerhuntapi.model.HuntId import net.halfbinary.scavengerhuntapi.model.TeamId import net.halfbinary.scavengerhuntapi.model.record.TeamRecord import org.springframework.data.jpa.repository.JpaRepository diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/TeamService.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/TeamService.kt index cb5a86c..664f0f8 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/TeamService.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/TeamService.kt @@ -1,21 +1,55 @@ package net.halfbinary.scavengerhuntapi.service +import net.halfbinary.scavengerhuntapi.error.exception.NotFoundException import net.halfbinary.scavengerhuntapi.model.HuntId 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.Team +import net.halfbinary.scavengerhuntapi.model.domain.TeamHunt +import net.halfbinary.scavengerhuntapi.model.record.HunterTeamRecord +import net.halfbinary.scavengerhuntapi.model.record.TeamHuntRecord +import net.halfbinary.scavengerhuntapi.model.record.TeamRecord +import net.halfbinary.scavengerhuntapi.model.request.TeamRequest +import net.halfbinary.scavengerhuntapi.model.response.TeamResponse +import net.halfbinary.scavengerhuntapi.repository.HunterRepository +import net.halfbinary.scavengerhuntapi.repository.HunterTeamRepository +import net.halfbinary.scavengerhuntapi.repository.TeamHuntRepository +import net.halfbinary.scavengerhuntapi.repository.TeamRepository import org.springframework.stereotype.Service +import java.util.UUID @Service -class TeamService { +class TeamService( + private val teamRepository: TeamRepository, + private val teamHuntRepository: TeamHuntRepository, + private val hunterRepository: HunterRepository, + private val hunterTeamRepository: HunterTeamRepository, +) { fun getListOfTeamsForHunt(huntId: HuntId): List { - TODO() + return getTeamsForHunt(huntId) } fun createTeam(name: String): Team { - TODO() + return teamRepository.save(TeamRequest(name).toDomain().toRecord()).toDomain() } fun addTeamToHunt(huntId: HuntId, teamId: TeamId) { - TODO() + teamHuntRepository.save(TeamHunt(teamId = teamId, huntId = huntId).toRecord()).toDomain() + } + + fun getTeamFromHunt(huntId: HuntId, teamId: TeamId): Team { + return getTeamsForHunt(huntId) + .filter { it.id == teamId } + .elementAt(0) + } + + 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)) + } + + private fun getTeamsForHunt(huntId: HuntId): List { + return teamHuntRepository.findTeamsByHuntId(huntId).map { it.toDomain() } } } \ No newline at end of file