diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/ItemController.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/ItemController.kt index dbd1c2f..397671a 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/ItemController.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/controller/ItemController.kt @@ -13,6 +13,7 @@ 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.security.core.Authentication import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PatchMapping @@ -27,8 +28,8 @@ import org.springframework.web.bind.annotation.RestController class ItemController(private val huntService: HuntService) { @GetMapping - fun getItemsForHunt(@PathVariable huntId: HuntId): ResponseEntity> { - return ResponseEntity.ok(huntService.getItemsForHunt(huntId).map { it.toResponse() }) + fun getItemsForHunt(@PathVariable huntId: HuntId, authentication: Authentication): ResponseEntity> { + return ResponseEntity.ok(huntService.getItemsForHunt(huntId, authentication.name).map { it.toResponse() }) } @GetMapping("/{itemId}") diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/Hunt.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/Hunt.kt index f0adfd4..80e6036 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/Hunt.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/model/domain/Hunt.kt @@ -10,4 +10,7 @@ data class Hunt( val startDateTime: LocalDateTime, val endDateTime: LocalDateTime, val isTerminated: Boolean -) \ No newline at end of file +) { + val isOngoing: Boolean + get() = !isTerminated && startDateTime < LocalDateTime.now() && endDateTime > LocalDateTime.now() +} \ 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 d77959d..e268c21 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HuntService.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/HuntService.kt @@ -1,5 +1,6 @@ package net.halfbinary.scavengerhuntapi.service +import net.halfbinary.scavengerhuntapi.error.exception.ForbiddenException import net.halfbinary.scavengerhuntapi.error.exception.NotFoundException import net.halfbinary.scavengerhuntapi.model.HuntId import net.halfbinary.scavengerhuntapi.model.HunterId @@ -22,7 +23,8 @@ import java.time.LocalDateTime class HuntService( private val huntRepository: HuntRepository, private val itemRepository: ItemRepository, - private val huntItemRepository: HuntItemRepository + private val huntItemRepository: HuntItemRepository, + private val hunterService: HunterService ) { fun getHunt(huntId: HuntId): Hunt { return huntRepository.findByIdOrNull(huntId)?.toDomain() ?: throw NotFoundException("No hunt with id $huntId found") @@ -66,8 +68,10 @@ class HuntService( return huntRepository.save(hunt.toRecord()).toDomain() } - fun getItemsForHunt(huntId: HuntId): List { - huntRepository.findByIdOrNull(huntId) ?: throw NotFoundException("No hunt with id $huntId found") + 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) + if (!hunter.isAdmin && !hunt.isOngoing) throw ForbiddenException() return itemRepository.findAllByHuntId(huntId).map { it.toDomain() } } diff --git a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/PhotoService.kt b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/PhotoService.kt index 612515a..38b55d6 100644 --- a/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/PhotoService.kt +++ b/src/main/kotlin/net/halfbinary/scavengerhuntapi/service/PhotoService.kt @@ -36,10 +36,15 @@ class PhotoService( private val photoRepository: PhotoRepository, private val hunterService: HunterService, private val teamService: TeamService, + private val huntService: HuntService, private val s3StorageService: S3StorageService, private val fileProbeService: FileProbeService ) { fun submitPhoto(huntId: HuntId, itemId: ItemId, email: String, file: MultipartFile) { + val hunter = hunterService.getHunterByEmail(email) + val hunt = huntService.getHunt(huntId) + if (!hunter.isAdmin && !hunt.isOngoing) throw ForbiddenException() + val originalBytes = file.bytes val fileType = fileProbeService.getFileType(originalBytes) @@ -51,7 +56,6 @@ class PhotoService( throw BadFileException("Image type is not supported") } - val hunter = hunterService.getHunterByEmail(email) val now = LocalDateTime.now() val photo = Photo( itemId = itemId, @@ -76,6 +80,8 @@ class PhotoService( ?: throw NotFoundException(PHOTO_NOT_FOUND) if (!requestingHunter.isAdmin) { + val hunt = huntService.getHunt(huntId) + if (!hunt.isOngoing) throw ForbiddenException() val team = try { teamService.getTeamForHunterInHunt(huntId, email) } catch (_: NotFoundException) { @@ -121,6 +127,8 @@ class PhotoService( val requestingHunter = hunterService.getHunterByEmail(email) if (!requestingHunter.isAdmin) { + val hunt = huntService.getHunt(huntId) + if (!hunt.isOngoing) throw ForbiddenException() val team = try { teamService.getTeamForHunterInHunt(huntId, email) } catch (_: NotFoundException) { @@ -142,15 +150,24 @@ class PhotoService( } fun removePhoto(huntId: HuntId, teamId: TeamId, itemId: ItemId, photoId: PhotoId, email: String) { + val requestingHunter = hunterService.getHunterByEmail(email) + + if (!requestingHunter.isAdmin) { + val hunt = huntService.getHunt(huntId) + if (!hunt.isOngoing) throw ForbiddenException() + } + val photoRecord = photoRepository.findByIdAndItemIdAndHuntId(photoId, itemId, huntId) ?: throw NotFoundException(PHOTO_NOT_FOUND) - val team = try { - teamService.getTeamForHunterInHunt(huntId, email) - } catch (_: NotFoundException) { - throw ForbiddenException() + if (!requestingHunter.isAdmin) { + val team = try { + teamService.getTeamForHunterInHunt(huntId, email) + } catch (_: NotFoundException) { + throw ForbiddenException() + } + if (team.id != teamId) throw ForbiddenException() } - if (team.id != teamId) throw ForbiddenException() if (photoRecord.status == PhotoStatus.APPROVED) throw ConflictException("Cannot remove an approved photo") @@ -161,6 +178,8 @@ class PhotoService( val requestingHunter = hunterService.getHunterByEmail(email) if (!requestingHunter.isAdmin) { + val hunt = huntService.getHunt(huntId) + if (!hunt.isOngoing) throw ForbiddenException() val team = try { teamService.getTeamForHunterInHunt(huntId, email) } catch (_: NotFoundException) {