diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/config/JwtUtil.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/config/JwtUtil.kt index 3886bd5..d09a17c 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/config/JwtUtil.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/config/JwtUtil.kt @@ -5,7 +5,7 @@ import io.jsonwebtoken.Jwts import jakarta.annotation.PostConstruct import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component -import java.util.Date +import java.util.* import javax.crypto.SecretKey import javax.crypto.spec.SecretKeySpec diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/HuntController.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/HuntController.kt index dbd54de..0c40172 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/HuntController.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/HuntController.kt @@ -11,16 +11,19 @@ import net.halfbinary.scavengerhuntapi.model.request.HuntCreateRequest import net.halfbinary.scavengerhuntapi.model.request.HuntStatus import net.halfbinary.scavengerhuntapi.model.response.HuntResponse import net.halfbinary.scavengerhuntapi.service.HuntService -import net.halfbinary.scavengerhuntapi.service.HunterService import org.springframework.http.ResponseEntity import org.springframework.security.access.prepost.PreAuthorize -import org.springframework.security.core.Authentication -import org.springframework.web.bind.annotation.* -import java.time.LocalDateTime +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("hunt") -class HuntController(private val huntService: HuntService, private val hunterService: HunterService) { +class HuntController(private val huntService: HuntService) { @GetMapping("/{id}") @Operation(summary = "Gets the specified hunt information") @@ -29,24 +32,12 @@ class HuntController(private val huntService: HuntService, private val hunterSer } @PreAuthorize("hasRole('ADMIN')") @Tag(name = "Admin") - @GetMapping() + @GetMapping @Operation(summary = "Gets all Hunts") fun getAllHunts(@RequestParam status: HuntStatus?): ResponseEntity> { return ResponseEntity.ok(huntService.getAllHunts(status).map { it.toResponse() }) } - @GetMapping("/ongoing") - @Operation(summary = "Gets list of all currently running Hunts (filtered by the calling hunter)") - fun getOngoingHunts(authentication: Authentication, @RequestParam status: HuntStatus?): ResponseEntity> { - val email = authentication.name - val isAdmin = hunterService.getHunterByEmail(email).isAdmin - return if(isAdmin) { - ResponseEntity.ok(huntService.getAllHunts(HuntStatus.ONGOING).map { it.toResponse() }) - } else { - ResponseEntity.ok(huntService.getHuntsByEmail(email, status).map { it.toResponse() }) - } - } - @GetMapping("/unstarted") @Operation(summary = "Gets list of all upcoming Hunts") fun getUnstartedHunts(): ResponseEntity> { @@ -55,7 +46,7 @@ class HuntController(private val huntService: HuntService, private val hunterSer @PreAuthorize("hasRole('ADMIN')") @Tag(name = "Admin") - @PostMapping() + @PostMapping @Operation(summary = "Creates a new Hunt") fun createHunt(@Valid @RequestBody huntRequest: HuntCreateRequest): ResponseEntity { return ResponseEntity.ok(huntService.createHunt(huntRequest.toDomain()).toResponse()) diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/HunterController.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/HunterController.kt new file mode 100644 index 0000000..d548abf --- /dev/null +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/HunterController.kt @@ -0,0 +1,51 @@ +package net.halfbinary.scavengerhuntapi.controller + +import io.swagger.v3.oas.annotations.Operation +import net.halfbinary.scavengerhuntapi.model.HuntId +import net.halfbinary.scavengerhuntapi.model.TeamId +import net.halfbinary.scavengerhuntapi.model.converter.toResponse +import net.halfbinary.scavengerhuntapi.model.request.HuntStatus +import net.halfbinary.scavengerhuntapi.model.response.HuntResponse +import net.halfbinary.scavengerhuntapi.model.response.TeamResponse +import net.halfbinary.scavengerhuntapi.service.HuntService +import net.halfbinary.scavengerhuntapi.service.HunterService +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 +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/hunter") +class HunterController(private val hunterService: HunterService, + private val huntService: HuntService, + private val teamService: TeamService) { + + @GetMapping("/hunt/ongoing") + @Operation(summary = "Gets list of all currently running Hunts (filtered by the calling hunter)") + fun getOngoingHunts(authentication: Authentication, @RequestParam status: HuntStatus?): ResponseEntity> { + val email = authentication.name + val isAdmin = hunterService.getHunterByEmail(email).isAdmin + return if(isAdmin) { + ResponseEntity.ok(huntService.getAllHunts(HuntStatus.ONGOING).map { it.toResponse() }) + } else { + ResponseEntity.ok(huntService.getHuntsByEmail(email, status).map { it.toResponse() }) + } + } + + @PostMapping("/hunt/{huntId}/team/{teamId}") + @Operation(summary = "Joins Hunter to specified Team for specified Hunt") + fun joinTeamForHunt(@PathVariable huntId: HuntId, @PathVariable teamId: TeamId, authentication: Authentication) { + teamService.joinTeam(teamId, authentication.name) + } + + @GetMapping("/hunt/{huntId}/team") + @Operation(summary = "Gets the Team for the Hunter for the specified Hunt") + fun getHunterHuntTeam(@PathVariable huntId: HuntId, authentication: Authentication): ResponseEntity { + TODO("Get the Team information for the Hunt for the Hunter (AKA the user)") + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/ItemController.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/ItemController.kt index 1549ffd..965b001 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/ItemController.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/ItemController.kt @@ -3,20 +3,17 @@ 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.HunterId import net.halfbinary.scavengerhuntapi.model.ItemId -import net.halfbinary.scavengerhuntapi.model.TeamHuntId -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.ItemRequest -import net.halfbinary.scavengerhuntapi.model.response.HuntResponse import net.halfbinary.scavengerhuntapi.model.response.ItemResponse import net.halfbinary.scavengerhuntapi.service.HuntService import org.springframework.http.ResponseEntity -import org.springframework.security.access.prepost.PreAuthorize -import org.springframework.web.bind.annotation.* +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("hunt/{huntId}/item") @@ -24,18 +21,18 @@ class ItemController(private val huntService: HuntService) { @GetMapping fun getItemsForHunt(@PathVariable huntId: HuntId): ResponseEntity> { - TODO() + TODO("List the Items related to the specified Hunt") } @GetMapping("/{itemId}") fun getItem(@PathVariable huntId: HuntId, @PathVariable itemId: ItemId): ResponseEntity { - TODO() + TODO("Get detailed information about the specified Item for the specified Hunt") } @PostMapping @Operation(summary = "Adds new Item to specified Hunt") fun addItemToHunt(@PathVariable huntId: HuntId, @Valid @RequestBody body: ItemRequest) { - TODO() + TODO("Add a new item to the specified Hunt") } } \ No newline at end of file diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/TeamController.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/TeamController.kt index 66a2fd2..e1bfe9f 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/TeamController.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/TeamController.kt @@ -4,6 +4,7 @@ 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.PhotoId import net.halfbinary.scavengerhuntapi.model.TeamId import net.halfbinary.scavengerhuntapi.model.converter.toResponse import net.halfbinary.scavengerhuntapi.model.request.TeamRequest @@ -11,6 +12,7 @@ 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.core.io.InputStreamSource import org.springframework.http.ResponseEntity import org.springframework.security.core.Authentication import org.springframework.web.bind.annotation.GetMapping @@ -18,7 +20,9 @@ import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController +import org.springframework.web.multipart.MultipartFile @RestController @RequestMapping("hunt/{huntId}/team") @@ -41,24 +45,43 @@ class TeamController(private val teamService: TeamService) { 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, + fun getItemForTeam(@PathVariable huntId: HuntId, @PathVariable teamId: TeamId, @PathVariable itemId: ItemId): ResponseEntity { - TODO() + TODO("Get found/not found status and photo information about the Item for the specified Team, Hunt, and Item") } @GetMapping("/{teamId}/item/{itemId}/photo") - fun getPhotosForTeam(@PathVariable huntId: HuntId, + fun getItemPhotos(@PathVariable huntId: HuntId, @PathVariable teamId: TeamId, - @PathVariable itemId: ItemId): ResponseEntity { - TODO() + @PathVariable itemId: ItemId): ResponseEntity> { + TODO("Get list of photo information for the specified Team, Hunt, and Item") } + @GetMapping("/{teamId}/item/{itemId}/photo/{photoId}") + fun getPhotoInfo(@PathVariable huntId: HuntId, + @PathVariable teamId: TeamId, + @PathVariable itemId: ItemId, + @PathVariable photoId: PhotoId): ResponseEntity { + TODO("Get photo information for the specified Team, Hunt, Item, and Photo") + } + + @GetMapping("/{teamId}/item/{itemId}/photo/{photoId}/file") + fun getPhoto(@PathVariable huntId: HuntId, + @PathVariable teamId: TeamId, + @PathVariable itemId: ItemId, + @PathVariable photoId: PhotoId): ResponseEntity { + TODO("Get the binary image information for the specified Team, Hunt, Item, and Photo") + } + + @PostMapping("/{teamId}/item/{itemId}/photo") + fun submitPhoto(@PathVariable huntId: HuntId, + @PathVariable teamId: TeamId, + @PathVariable itemId: ItemId, + authentication: Authentication, + @RequestParam file: MultipartFile): ResponseEntity { + TODO("Save photo information in the Photo table so that it relates to the specified Team, Hunt, Hunter, and Item, and store the binary file") + } } \ No newline at end of file diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/error/exception/LoginFailedException.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/error/exception/LoginFailedException.kt index 08e6447..05b9968 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/error/exception/LoginFailedException.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/error/exception/LoginFailedException.kt @@ -1,3 +1,3 @@ package net.halfbinary.scavengerhuntapi.error.exception -class LoginFailedException(): RuntimeException("The email and password combination is not correct.") \ No newline at end of file +class LoginFailedException : RuntimeException("The email and password combination is not correct.") \ 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 index 00d2624..12e9711 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/converter/TeamHuntConverter.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/converter/TeamHuntConverter.kt @@ -1,11 +1,7 @@ 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) diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/Team.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/Team.kt index dc620f9..fb35534 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/Team.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/Team.kt @@ -1,7 +1,7 @@ package net.halfbinary.scavengerhuntapi.model.domain import net.halfbinary.scavengerhuntapi.model.TeamId -import java.util.UUID +import java.util.* data class Team( val id: TeamId = UUID.randomUUID(), diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/TeamHunt.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/TeamHunt.kt index 6b402c3..4d53440 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/TeamHunt.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/TeamHunt.kt @@ -3,7 +3,6 @@ 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(), diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/record/FoundRecord.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/record/FoundRecord.kt index 033dcd2..9a1ab81 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/record/FoundRecord.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/record/FoundRecord.kt @@ -3,7 +3,11 @@ package net.halfbinary.scavengerhuntapi.model.record import jakarta.persistence.Entity import jakarta.persistence.Id import jakarta.persistence.Table -import net.halfbinary.scavengerhuntapi.model.* +import net.halfbinary.scavengerhuntapi.model.FoundId +import net.halfbinary.scavengerhuntapi.model.FoundStatus +import net.halfbinary.scavengerhuntapi.model.HuntId +import net.halfbinary.scavengerhuntapi.model.HunterId +import net.halfbinary.scavengerhuntapi.model.ItemId import java.time.LocalDateTime /** 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 4f251e3..3822b00 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/record/TeamHuntRecord.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/record/TeamHuntRecord.kt @@ -6,7 +6,6 @@ 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.* @Entity @Table(name = "team_hunt") diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/HuntRepository.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/HuntRepository.kt index 1ccb029..40bdc38 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/HuntRepository.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/HuntRepository.kt @@ -2,7 +2,6 @@ package net.halfbinary.scavengerhuntapi.repository import net.halfbinary.scavengerhuntapi.model.HuntId import net.halfbinary.scavengerhuntapi.model.HunterId -import net.halfbinary.scavengerhuntapi.model.TeamId import net.halfbinary.scavengerhuntapi.model.record.HuntRecord import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/HunterTeamRepository.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/HunterTeamRepository.kt index 46b375b..1edd62b 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/HunterTeamRepository.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/HunterTeamRepository.kt @@ -3,7 +3,7 @@ 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 +import java.util.* @Repository interface HunterTeamRepository : JpaRepository diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/TeamRepository.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/TeamRepository.kt index 31644d0..8cf9575 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/TeamRepository.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/repository/TeamRepository.kt @@ -1,6 +1,5 @@ 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/HuntService.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HuntService.kt index 14655fa..a9b572a 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HuntService.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HuntService.kt @@ -15,7 +15,7 @@ import java.time.LocalDateTime @Service class HuntService(private val huntRepository: HuntRepository) { fun getHunt(huntId: HuntId): Hunt { - return huntRepository.findByIdOrNull(huntId)?.toDomain() ?: throw NotFoundException("No hunt with id ${huntId} found") + return huntRepository.findByIdOrNull(huntId)?.toDomain() ?: throw NotFoundException("No hunt with id $huntId found") } fun getAllHunts(status: HuntStatus?): List { diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HunterDetailsService.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HunterDetailsService.kt index bc4e7ea..77c69aa 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HunterDetailsService.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HunterDetailsService.kt @@ -7,7 +7,7 @@ import org.springframework.security.core.userdetails.UserDetails import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.core.userdetails.UsernameNotFoundException import org.springframework.stereotype.Service -import java.util.Collections +import java.util.* @Service diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/TeamService.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/TeamService.kt index 664f0f8..498ed71 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/TeamService.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/TeamService.kt @@ -8,16 +8,13 @@ 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 +import java.util.* @Service class TeamService(