diff --git a/src/main/kotlin/org/gitanimals/render/domain/Persona.kt b/src/main/kotlin/org/gitanimals/render/domain/Persona.kt index 149ae13..4635a8b 100644 --- a/src/main/kotlin/org/gitanimals/render/domain/Persona.kt +++ b/src/main/kotlin/org/gitanimals/render/domain/Persona.kt @@ -19,6 +19,9 @@ class Persona( @Embedded val level: Level, + @Column(name = "visible", nullable = false) + val visible: Boolean, + @JsonIgnore @JoinColumn(name = "user_id") @ManyToOne(fetch = FetchType.LAZY, optional = false) @@ -28,10 +31,16 @@ class Persona( constructor( type: PersonaType, level: Long, - ) : this(type = type, level = Level(level)) + visible: Boolean + ) : this(type = type, level = Level(level), visible = visible) - fun toSvg(): String = type.load(this) + fun toSvg(): String { + if (!visible) { + return "" + } + return type.load(this) + } fun level(): Long = level.value } diff --git a/src/main/kotlin/org/gitanimals/render/domain/User.kt b/src/main/kotlin/org/gitanimals/render/domain/User.kt index 908f997..c831a33 100644 --- a/src/main/kotlin/org/gitanimals/render/domain/User.kt +++ b/src/main/kotlin/org/gitanimals/render/domain/User.kt @@ -63,7 +63,12 @@ class User( fun updateContribution(contribution: Int) { val currentYear = ZonedDateTime.now(ZoneId.of("UTC")).year val currentYearContribution = - contributions.first { it.year == currentYear } + contributions.firstOrNull { it.year == currentYear } + ?: run { + val currentYearContribution = Contribution(currentYear, 0, Instant.now()) + contributions.add(currentYearContribution) + currentYearContribution + } val newContribution = contribution - currentYearContribution.contribution @@ -71,7 +76,6 @@ class User( lastPersonaGivePoint += newContribution currentYearContribution.lastUpdatedContribution = Instant.now() levelUpPersonas(newContribution) - giveNewPersona() } private fun levelUpPersonas(newContribution: Int) { @@ -86,15 +90,27 @@ class User( } } - private fun giveNewPersona() { + fun giveNewPersona() { if (lastPersonaGivePoint < FOR_NEW_PERSONA_COUNT) { return } lastPersonaGivePoint %= FOR_NEW_PERSONA_COUNT.toInt() - if (personas.size >= MAX_PERSONA_COUNT) { - return + + val newPersona = when (personas.size >= MAX_PERSONA_COUNT) { + true -> Persona( + type = PersonaType.random(), + level = Level(0), + visible = false, + user = this + ) + + false -> Persona( + type = PersonaType.random(), + level = Level(0), + visible = true, + user = this + ) } - val newPersona = Persona(type = PersonaType.random(), level = Level(0), user = this) personas.add(newPersona) } @@ -202,7 +218,7 @@ class User( max((totalContributionCount / FOR_INIT_PERSONA_COUNT), 1) ).toInt() ) { - personas.add(Persona(PersonaType.random(), 0)) + personas.add(Persona(PersonaType.random(), 0, true)) } return personas } diff --git a/src/main/kotlin/org/gitanimals/render/domain/UserService.kt b/src/main/kotlin/org/gitanimals/render/domain/UserService.kt index 9955a90..66df64e 100644 --- a/src/main/kotlin/org/gitanimals/render/domain/UserService.kt +++ b/src/main/kotlin/org/gitanimals/render/domain/UserService.kt @@ -1,6 +1,6 @@ package org.gitanimals.render.domain -import org.springframework.dao.OptimisticLockingFailureException +import org.springframework.orm.ObjectOptimisticLockingFailureException import org.springframework.retry.annotation.Retryable import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -21,17 +21,18 @@ class UserService( return getUserByName(username).createLineAnimation(personaId) } - @Retryable(retryFor = [OptimisticLockingFailureException::class], maxAttempts = 10) + @Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 10) @Transactional fun increaseVisit(username: String) { getUserByName(username).increaseVisitCount() } - @Retryable(retryFor = [OptimisticLockingFailureException::class], maxAttempts = 10) + @Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 10) @Transactional fun updateContributions(username: String, contribution: Int) { - getUserByName(username) - .updateContribution(contribution) + val user = getUserByName(username) + user.updateContribution(contribution) + user.giveNewPersona() } fun isContributionUpdatedBeforeOneHour(name: String): Boolean = diff --git a/src/test/kotlin/org/gitanimals/render/domain/UserTest.kt b/src/test/kotlin/org/gitanimals/render/domain/UserTest.kt index 40e40a3..81e32d0 100644 --- a/src/test/kotlin/org/gitanimals/render/domain/UserTest.kt +++ b/src/test/kotlin/org/gitanimals/render/domain/UserTest.kt @@ -63,6 +63,18 @@ internal class UserTest : DescribeSpec({ } } } + + describe("giveNewPersona 메소드는") { + val user = User.newUser("new-user", mutableMapOf()) + context("펫이 30마리가 넘을경우, visible false의 pet을 생성한다.") { + repeat(99) { + user.updateContribution(30 * (it + 1)) + user.giveNewPersona() + } + + user.personas.count { !it.visible } shouldBeEqual 70 + } + } }) { private companion object { private const val ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"