Converts all timestamps to UTC

This commit is contained in:
2026-05-18 23:02:49 -05:00
parent 5e2976180c
commit 3b5046f1db
12 changed files with 38 additions and 38 deletions

View File

@@ -1,16 +1,16 @@
package net.halfbinary.scavengerhuntapi.model.domain package net.halfbinary.scavengerhuntapi.model.domain
import net.halfbinary.scavengerhuntapi.model.HuntId import net.halfbinary.scavengerhuntapi.model.HuntId
import java.time.LocalDateTime import java.time.OffsetDateTime
import java.util.* import java.util.*
data class Hunt( data class Hunt(
val id: HuntId = UUID.randomUUID(), val id: HuntId = UUID.randomUUID(),
val title: String, val title: String,
val startDateTime: LocalDateTime, val startDateTime: OffsetDateTime,
val endDateTime: LocalDateTime, val endDateTime: OffsetDateTime,
val isTerminated: Boolean val isTerminated: Boolean
) { ) {
val isOngoing: Boolean val isOngoing: Boolean
get() = !isTerminated && startDateTime < LocalDateTime.now() && endDateTime > LocalDateTime.now() get() = !isTerminated && startDateTime < OffsetDateTime.now() && endDateTime > OffsetDateTime.now()
} }

View File

@@ -5,7 +5,7 @@ import net.halfbinary.scavengerhuntapi.model.HunterId
import net.halfbinary.scavengerhuntapi.model.ItemId import net.halfbinary.scavengerhuntapi.model.ItemId
import net.halfbinary.scavengerhuntapi.model.PhotoId import net.halfbinary.scavengerhuntapi.model.PhotoId
import net.halfbinary.scavengerhuntapi.model.PhotoStatus import net.halfbinary.scavengerhuntapi.model.PhotoStatus
import java.time.LocalDateTime import java.time.OffsetDateTime
import java.util.* import java.util.*
data class Photo( data class Photo(
@@ -13,7 +13,7 @@ data class Photo(
val itemId: ItemId, val itemId: ItemId,
val huntId: HuntId, val huntId: HuntId,
val hunterId: HunterId, val hunterId: HunterId,
val foundDateTime: LocalDateTime, val foundDateTime: OffsetDateTime,
val status: PhotoStatus, val status: PhotoStatus,
val statusChangeDateTime: LocalDateTime val statusChangeDateTime: OffsetDateTime
) )

View File

@@ -4,7 +4,7 @@ import jakarta.persistence.Entity
import jakarta.persistence.Id import jakarta.persistence.Id
import jakarta.persistence.Table import jakarta.persistence.Table
import net.halfbinary.scavengerhuntapi.model.HuntId import net.halfbinary.scavengerhuntapi.model.HuntId
import java.time.LocalDateTime import java.time.OffsetDateTime
/** /**
* Represents a scavenger hunt event * Represents a scavenger hunt event
@@ -16,7 +16,7 @@ data class HuntRecord(
@Id @Id
val id: HuntId, val id: HuntId,
val title: String, val title: String,
val startDateTime: LocalDateTime, val startDateTime: OffsetDateTime,
val endDateTime: LocalDateTime, val endDateTime: OffsetDateTime,
val isTerminated: Boolean val isTerminated: Boolean
) )

View File

@@ -8,7 +8,7 @@ import net.halfbinary.scavengerhuntapi.model.HunterId
import net.halfbinary.scavengerhuntapi.model.ItemId import net.halfbinary.scavengerhuntapi.model.ItemId
import net.halfbinary.scavengerhuntapi.model.PhotoId import net.halfbinary.scavengerhuntapi.model.PhotoId
import net.halfbinary.scavengerhuntapi.model.PhotoStatus import net.halfbinary.scavengerhuntapi.model.PhotoStatus
import java.time.LocalDateTime import java.time.OffsetDateTime
/** /**
* Represents a found Item for a Hunt by a Hunter * Represents a found Item for a Hunt by a Hunter
@@ -21,7 +21,7 @@ data class PhotoRecord(
val itemId: ItemId, val itemId: ItemId,
val huntId: HuntId, val huntId: HuntId,
val hunterId: HunterId, val hunterId: HunterId,
val foundDateTime: LocalDateTime, val foundDateTime: OffsetDateTime,
val status: PhotoStatus, val status: PhotoStatus,
val statusChangeDateTime: LocalDateTime, val statusChangeDateTime: OffsetDateTime,
) )

View File

@@ -4,7 +4,7 @@ import jakarta.persistence.Entity
import jakarta.persistence.Id import jakarta.persistence.Id
import jakarta.persistence.Table import jakarta.persistence.Table
import net.halfbinary.scavengerhuntapi.model.RefreshId import net.halfbinary.scavengerhuntapi.model.RefreshId
import java.time.LocalDateTime import java.time.OffsetDateTime
@Entity @Entity
@Table(name = "refresh_token") @Table(name = "refresh_token")
@@ -12,5 +12,5 @@ data class RefreshTokenRecord(
@Id @Id
val token: RefreshId, val token: RefreshId,
val email: String, val email: String,
val expiryDateTime: LocalDateTime val expiryDateTime: OffsetDateTime
) )

View File

@@ -2,13 +2,13 @@ package net.halfbinary.scavengerhuntapi.model.request
import jakarta.validation.constraints.Future import jakarta.validation.constraints.Future
import jakarta.validation.constraints.NotBlank import jakarta.validation.constraints.NotBlank
import java.time.LocalDateTime import java.time.OffsetDateTime
data class HuntCreateRequest( data class HuntCreateRequest(
@field:NotBlank(message = "Hunt title is required") @field:NotBlank(message = "Hunt title is required")
val title: String, val title: String,
@field:Future @field:Future
val startDateTime: LocalDateTime, val startDateTime: OffsetDateTime,
@field:Future @field:Future
val endDateTime: LocalDateTime, val endDateTime: OffsetDateTime,
) )

View File

@@ -1,10 +1,10 @@
package net.halfbinary.scavengerhuntapi.model.request package net.halfbinary.scavengerhuntapi.model.request
import java.time.LocalDateTime import java.time.OffsetDateTime
data class HuntUpdateRequest( data class HuntUpdateRequest(
val title: String?, val title: String?,
val startDateTime: LocalDateTime?, val startDateTime: OffsetDateTime?,
val endDateTime: LocalDateTime?, val endDateTime: OffsetDateTime?,
val isTerminated: Boolean? val isTerminated: Boolean?
) )

View File

@@ -1,12 +1,12 @@
package net.halfbinary.scavengerhuntapi.model.response package net.halfbinary.scavengerhuntapi.model.response
import net.halfbinary.scavengerhuntapi.model.HuntId import net.halfbinary.scavengerhuntapi.model.HuntId
import java.time.LocalDateTime import java.time.OffsetDateTime
data class HuntResponse( data class HuntResponse(
val id: HuntId, val id: HuntId,
val title: String, val title: String,
val startDateTime: LocalDateTime, val startDateTime: OffsetDateTime,
val endDateTime: LocalDateTime, val endDateTime: OffsetDateTime,
val isTerminated: Boolean val isTerminated: Boolean
) )

View File

@@ -2,12 +2,12 @@ package net.halfbinary.scavengerhuntapi.model.response
import net.halfbinary.scavengerhuntapi.model.PhotoId import net.halfbinary.scavengerhuntapi.model.PhotoId
import net.halfbinary.scavengerhuntapi.model.PhotoStatus import net.halfbinary.scavengerhuntapi.model.PhotoStatus
import java.time.LocalDateTime import java.time.OffsetDateTime
data class PhotoResponse( data class PhotoResponse(
val id: PhotoId, val id: PhotoId,
val hunterName: String, val hunterName: String,
val photoUploadDateTime: LocalDateTime, val photoUploadDateTime: OffsetDateTime,
val photoStatus: PhotoStatus, val photoStatus: PhotoStatus,
val photoStatusChangeDateTime: LocalDateTime, val photoStatusChangeDateTime: OffsetDateTime,
) )

View File

@@ -18,7 +18,7 @@ import net.halfbinary.scavengerhuntapi.repository.HuntRepository
import net.halfbinary.scavengerhuntapi.repository.ItemRepository import net.halfbinary.scavengerhuntapi.repository.ItemRepository
import org.springframework.data.repository.findByIdOrNull import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import java.time.LocalDateTime import java.time.OffsetDateTime
@Service @Service
class HuntService( class HuntService(
@@ -49,16 +49,16 @@ class HuntService(
val filteredHunts = when (status) { val filteredHunts = when (status) {
HuntStatus.ONGOING -> { HuntStatus.ONGOING -> {
allHunts allHunts
.filter { !it.isTerminated && it.startDateTime < LocalDateTime.now() && it.endDateTime > LocalDateTime.now() } .filter { !it.isTerminated && it.startDateTime < OffsetDateTime.now() && it.endDateTime > OffsetDateTime.now() }
.toList() .toList()
} }
HuntStatus.CLOSED -> { HuntStatus.CLOSED -> {
allHunts allHunts
.filter { it.isTerminated || it.endDateTime < LocalDateTime.now() } .filter { it.isTerminated || it.endDateTime < OffsetDateTime.now() }
} }
HuntStatus.UNSTARTED -> { HuntStatus.UNSTARTED -> {
allHunts allHunts
.filter { !it.isTerminated && it.startDateTime > LocalDateTime.now() } .filter { !it.isTerminated && it.startDateTime > OffsetDateTime.now() }
} }
else -> { allHunts } else -> { allHunts }
} }

View File

@@ -27,7 +27,7 @@ import org.springframework.stereotype.Service
import org.springframework.web.multipart.MultipartFile import org.springframework.web.multipart.MultipartFile
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.time.LocalDateTime import java.time.OffsetDateTime
private const val PHOTO_NOT_FOUND = "Photo not found" private const val PHOTO_NOT_FOUND = "Photo not found"
@@ -56,7 +56,7 @@ class PhotoService(
throw BadFileException("Image type is not supported") throw BadFileException("Image type is not supported")
} }
val now = LocalDateTime.now() val now = OffsetDateTime.now()
val photo = Photo( val photo = Photo(
itemId = itemId, itemId = itemId,
huntId = huntId, huntId = huntId,
@@ -171,7 +171,7 @@ class PhotoService(
if (photoRecord.status == PhotoStatus.APPROVED) throw ConflictException("Cannot remove an approved photo") if (photoRecord.status == PhotoStatus.APPROVED) throw ConflictException("Cannot remove an approved photo")
photoRepository.save(photoRecord.copy(status = PhotoStatus.REMOVED, statusChangeDateTime = LocalDateTime.now())) photoRepository.save(photoRecord.copy(status = PhotoStatus.REMOVED, statusChangeDateTime = OffsetDateTime.now()))
} }
fun getItemPhotos(huntId: HuntId, teamId: TeamId, itemId: ItemId, email: String): List<PhotoResponse> { fun getItemPhotos(huntId: HuntId, teamId: TeamId, itemId: ItemId, email: String): List<PhotoResponse> {
@@ -197,7 +197,7 @@ class PhotoService(
fun updatePhotoStatus(photoId: PhotoId, status: PhotoStatus) { fun updatePhotoStatus(photoId: PhotoId, status: PhotoStatus) {
val record = photoRepository.findByIdOrNull(photoId) val record = photoRepository.findByIdOrNull(photoId)
?: throw NotFoundException(PHOTO_NOT_FOUND) ?: throw NotFoundException(PHOTO_NOT_FOUND)
photoRepository.save(record.copy(status = status, statusChangeDateTime = LocalDateTime.now())) photoRepository.save(record.copy(status = status, statusChangeDateTime = OffsetDateTime.now()))
} }
private fun toJpeg(bytes: ByteArray): ByteArray { private fun toJpeg(bytes: ByteArray): ByteArray {

View File

@@ -10,7 +10,7 @@ import net.halfbinary.scavengerhuntapi.repository.RefreshTokenRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.data.repository.findByIdOrNull import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import java.time.LocalDateTime import java.time.OffsetDateTime
import java.time.temporal.ChronoUnit import java.time.temporal.ChronoUnit
@Service @Service
@@ -33,11 +33,11 @@ class RefreshTokenService(private val refreshTokenRepository: RefreshTokenReposi
} }
fun generateRefreshToken(email: String): RefreshId { fun generateRefreshToken(email: String): RefreshId {
return refreshTokenRepository.save(RefreshTokenRecord(RefreshId.randomUUID(), email, LocalDateTime.now().plus(1, ChronoUnit.MONTHS))).token return refreshTokenRepository.save(RefreshTokenRecord(RefreshId.randomUUID(), email, OffsetDateTime.now().plus(1, ChronoUnit.MONTHS))).token
} }
fun isTokenExpired(token: RefreshTokenRecord): Boolean { fun isTokenExpired(token: RefreshTokenRecord): Boolean {
return token.expiryDateTime.isBefore(LocalDateTime.now()) return token.expiryDateTime.isBefore(OffsetDateTime.now())
} }
fun getToken(token: RefreshId): RefreshTokenRecord? { fun getToken(token: RefreshId): RefreshTokenRecord? {