Skip to content

Commit

Permalink
release: 0.8.4 (#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
devxb authored Oct 28, 2024
2 parents 192665c + 7b8ba26 commit 46458ef
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 12 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @devxb
19 changes: 19 additions & 0 deletions src/main/kotlin/org/gitanimals/render/app/UserFacade.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.gitanimals.render.app

import org.gitanimals.render.app.request.MergePersonaRequest
import org.gitanimals.render.domain.FieldType
import org.gitanimals.render.domain.UserService
import org.gitanimals.render.domain.request.PersonaChangeRequest
import org.gitanimals.render.domain.response.PersonaResponse
Expand Down Expand Up @@ -51,4 +52,22 @@ class UserFacade(
request.deletePersonaId.toLong(),
)
}

fun addField(token: String, fieldType: FieldType) {
val user = identityApi.getUserByToken(token)

return userService.addField(user.username, fieldType)
}

fun deleteField(token: String, fieldType: FieldType) {
val user = identityApi.getUserByToken(token)

return userService.deleteField(user.username, fieldType)
}

fun changeField(token: String, fieldType: FieldType) {
val user = identityApi.getUserByToken(token)

return userService.changeField(user.username, fieldType)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.gitanimals.render.controller

import org.gitanimals.render.app.UserFacade
import org.gitanimals.render.controller.request.ChangeFieldRequest
import org.gitanimals.render.controller.response.BackgroundResponse
import org.gitanimals.render.domain.FieldType
import org.gitanimals.render.domain.UserService
import org.gitanimals.render.domain.UserService.Companion.loadField
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.*

@RestController
class BackgroundController(
private val userFacade: UserFacade,
private val userService: UserService,
) {

@ResponseStatus(HttpStatus.OK)
@GetMapping("/users/{username}/backgrounds")
fun getBackgrounds(
@PathVariable("username") username: String,
) = BackgroundResponse.from(userService.getByNameWithLazyLoading(username, loadField))

@ResponseStatus(HttpStatus.OK)
@PutMapping("/users/backgrounds")
fun changeBackground(
@RequestHeader(HttpHeaders.AUTHORIZATION) token: String,
@RequestBody changeFieldRequest: ChangeFieldRequest,
) = userFacade.changeField(token, FieldType.valueOf(changeFieldRequest.type.uppercase()))

@ResponseStatus(HttpStatus.OK)
@PostMapping("/internals/backgrounds")
fun addBackground(
@RequestHeader(HttpHeaders.AUTHORIZATION) token: String,
@RequestParam(name = "name") name: String,
) = userFacade.addField(token, FieldType.valueOf(name.uppercase()))


@ResponseStatus(HttpStatus.OK)
@DeleteMapping("/internals/backgrounds")
fun deleteBackground(
@RequestHeader(HttpHeaders.AUTHORIZATION) token: String,
@RequestParam(name = "name") name: String,
) = userFacade.deleteField(token, FieldType.valueOf(name.uppercase()))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.gitanimals.render.controller.request

data class ChangeFieldRequest(
val type: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.gitanimals.render.controller.response

import org.gitanimals.render.domain.User

data class BackgroundResponse(
val id: String,
val name: String,
val backgrounds: List<Background>,
) {

data class Background(
val type: String,
)

companion object {
fun from(user: User): BackgroundResponse {
return BackgroundResponse(
id = user.id.toString(),
name = user.name,
backgrounds = user.fields.map { Background(it.fieldType.toString()) },
)
}
}
}
65 changes: 65 additions & 0 deletions src/main/kotlin/org/gitanimals/render/domain/Field.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.gitanimals.render.domain

import com.fasterxml.jackson.annotation.JsonIgnore
import jakarta.persistence.*
import org.gitanimals.render.core.IdGenerator

@Entity
@Table(name = "field")
class Field(
@Id
@Column(name = "id")
private val id: Long,

@Column(name = "field_type")
@Enumerated(value = EnumType.STRING)
val fieldType: FieldType,

@Column(name = "is_choose", nullable = false)
private var isChoose: Boolean,

@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
val user: User,
) {

fun isChoose(): Boolean = this.isChoose

fun choose() {
this.isChoose = true
}

fun unChoose() {
this.isChoose = false
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Field) return false

return fieldType == other.fieldType
}

override fun hashCode(): Int {
return fieldType.hashCode()
}

fun fillBackground(): String = this.fieldType.fillBackground()

fun loadComponent(name: String, totalCount: Long): String =
this.fieldType.loadComponent(name, totalCount)

fun drawBorder(): String = this.fieldType.drawBorder()

companion object {
fun from(user: User, fieldType: FieldType): Field {
return Field(
id = IdGenerator.generate(),
fieldType = fieldType,
isChoose = false,
user = user,
)
}
}
}
59 changes: 52 additions & 7 deletions src/main/kotlin/org/gitanimals/render/domain/User.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,13 @@ class User(
@Column(name = "visit", nullable = false)
private var visit: Long,

@Enumerated(EnumType.STRING)
@Column(name = "field_type", nullable = false)
val field: FieldType,
@OneToMany(
mappedBy = "user",
fetch = FetchType.LAZY,
cascade = [CascadeType.ALL],
orphanRemoval = true
)
val fields: MutableSet<Field> = mutableSetOf(),

@Column(name = "last_persona_give_point", nullable = false)
private var lastPersonaGivePoint: Int,
Expand Down Expand Up @@ -163,7 +167,7 @@ class User(
fun createLineAnimation(personaId: Long, mode: Mode): String {
val builder = StringBuilder().openLine()

val persona = personas.find { it.id!! >= personaId }
val persona = personas.find { it.id >= personaId }
?: throw IllegalArgumentException("Cannot find persona by id \"$personaId\"")
builder.append(persona.toSvgForce(mode))

Expand All @@ -175,6 +179,8 @@ class User(
}

fun createFarmAnimation(): String {
val field = getOrCreateDefaultFieldIfAbsent()

val builder = StringBuilder().openFarm()
.append(field.fillBackground())

Expand All @@ -186,8 +192,44 @@ class User(
.closeSvg()
}


fun contributionCount(): Long = contributions.totalCount()

fun changeField(fieldType: FieldType) {
getOrCreateDefaultFieldIfAbsent()

unChooseField()
chooseField(fieldType)
}

private fun unChooseField() {
getOrCreateDefaultFieldIfAbsent()

fields.first { it.isChoose() }.unChoose()
}

fun addField(fieldType: FieldType) {
getOrCreateDefaultFieldIfAbsent()

this.fields.add(Field.from(this, fieldType))
}

private fun getOrCreateDefaultFieldIfAbsent() = fields.firstOrNull { it.isChoose() } ?: run {
this.addField(FieldType.WHITE_FIELD)
this.chooseField(FieldType.WHITE_FIELD)

fields.first { it.fieldType == FieldType.WHITE_FIELD }
}

private fun chooseField(fieldType: FieldType) {
this.fields.first { it.fieldType == fieldType }.choose()
}

fun deleteField(fieldType: FieldType) {
fields.firstOrNull { it.fieldType == fieldType }
?.let { fields.remove(it) }
}

private fun List<Contribution>.totalCount(): Long {
var totalCount = 0L
this.forEach { totalCount += it.contribution }
Expand Down Expand Up @@ -232,20 +274,23 @@ class User(
throw IllegalArgumentException("Not supported word contained in \"${name}\"")
}

return User(
val user = User(
id = IdGenerator.generate(),
name = name,
personas = createPersonas(contributions),
field = FieldType.WHITE_FIELD,
contributions = contributions.map {
val year = it.key
val contribution = it.value
Contribution(year, contribution, Instant.now())
}.toMutableList(),
visit = 1,
version = 0,
lastPersonaGivePoint = (totalContributionCount(contributions) % FOR_NEW_PERSONA_COUNT).toInt()
lastPersonaGivePoint = (totalContributionCount(contributions) % FOR_NEW_PERSONA_COUNT).toInt(),
)

user.addField(FieldType.WHITE_FIELD)

return user
}

private fun createPersonas(contributions: Map<Int, Int>): MutableList<Persona> {
Expand Down
41 changes: 36 additions & 5 deletions src/main/kotlin/org/gitanimals/render/domain/UserService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.gitanimals.render.domain

import org.gitanimals.render.domain.request.PersonaChangeRequest
import org.gitanimals.render.domain.response.PersonaResponse
import org.hibernate.Hibernate
import org.springframework.data.repository.findByIdOrNull
import org.springframework.orm.ObjectOptimisticLockingFailureException
import org.springframework.retry.annotation.Retryable
Expand Down Expand Up @@ -51,7 +52,7 @@ class UserService(
fun createNewUser(name: String, contributions: Map<Int, Int>): User =
userRepository.save(User.newUser(name, contributions))

@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 100)
@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 10)
@Transactional
fun givePersonaByCoupon(name: String, persona: String, code: String) {
requireIdempotency("$name:$code")
Expand All @@ -61,7 +62,7 @@ class UserService(
user.giveNewPersonaByType(PersonaType.valueOf(persona.uppercase()))
}

@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 100)
@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 10)
@Transactional
fun changePersona(name: String, personChangeRequest: PersonaChangeRequest): PersonaResponse {
val user = getUserByName(name)
Expand All @@ -74,7 +75,7 @@ class UserService(
return PersonaResponse.from(changedPersona)
}

@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 100)
@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 10)
@Transactional
fun addPersona(
name: String,
Expand All @@ -98,7 +99,7 @@ class UserService(
idempotencyRepository.save(Idempotency(idempotencyKey))
}

@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 100)
@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 10)
@Transactional
fun deletePersona(name: String, personaId: Long): PersonaResponse {
val user = getUserByName(name)
Expand All @@ -107,18 +108,48 @@ class UserService(
}

@Transactional
@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 100)
@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 10)
fun mergePersona(id: Long, increasePersonaId: Long, deletePersonaId: Long) {
val user = userRepository.findByIdOrNull(id)
?: throw IllegalArgumentException("Cannot find user by id \"$id\"")

user.mergePersona(increasePersonaId, deletePersonaId)
}

@Transactional
@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 10)
fun addField(name: String, fieldType: FieldType) {
getUserByName(name).addField(fieldType)
}

@Transactional
@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 10)
fun deleteField(name: String, fieldType: FieldType) {
getUserByName(name).deleteField(fieldType)
}

@Transactional
@Retryable(retryFor = [ObjectOptimisticLockingFailureException::class], maxAttempts = 10)
fun changeField(name: String, fieldType: FieldType) {
getUserByName(name).changeField(fieldType)
}

fun getByNameWithLazyLoading(name: String, vararg lazyLoading: (User) -> Unit): User {
val user = getUserByName(name)

lazyLoading.forEach { it(user) }

return user
}

fun getPersona(name: String, personaId: Long): PersonaResponse {
return getUserByName(name).personas
.find { it.id == personaId }
?.let { PersonaResponse.from(it) }
?: throw IllegalArgumentException("Cannot find matched persona \"$personaId\" by user name \"$name\"")
}

companion object {
val loadField: (User) -> Unit = { Hibernate.initialize(it.fields) }
}
}

0 comments on commit 46458ef

Please sign in to comment.