feat(agent-assignment): 에이전트 크리에이터 소속 관리 기능을 추가한다
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
package kr.co.vividnext.sodalive.admin.partner.agent.assignment
|
||||
|
||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||
import kr.co.vividnext.sodalive.partner.agent.assignment.AssignAgentCreatorRequest
|
||||
import kr.co.vividnext.sodalive.partner.agent.assignment.RemoveAgentCreatorRequest
|
||||
import org.springframework.security.access.prepost.PreAuthorize
|
||||
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
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
@RequestMapping("/admin/partner/agent/assignment")
|
||||
class AdminAgentCreatorController(private val service: AdminAgentCreatorService) {
|
||||
@PostMapping
|
||||
fun assignCreator(@RequestBody request: AssignAgentCreatorRequest) = ApiResponse.ok(service.assignCreator(request))
|
||||
|
||||
@PostMapping("/remove")
|
||||
fun removeCreator(@RequestBody request: RemoveAgentCreatorRequest) = ApiResponse.ok(service.removeCreator(request))
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package kr.co.vividnext.sodalive.admin.partner.agent.assignment
|
||||
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.partner.agent.assignment.AgentCreatorRelation
|
||||
import kr.co.vividnext.sodalive.partner.agent.assignment.AgentCreatorRelationRepository
|
||||
import kr.co.vividnext.sodalive.partner.agent.assignment.AssignAgentCreatorRequest
|
||||
import kr.co.vividnext.sodalive.partner.agent.assignment.RemoveAgentCreatorRequest
|
||||
import org.springframework.dao.DataIntegrityViolationException
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@Service
|
||||
class AdminAgentCreatorService(
|
||||
private val relationRepository: AgentCreatorRelationRepository,
|
||||
private val memberRepository: MemberRepository
|
||||
) {
|
||||
@Transactional
|
||||
fun assignCreator(request: AssignAgentCreatorRequest) {
|
||||
if (request.agentId == request.creatorId) {
|
||||
throw SodaException(messageKey = "partner.agent.assignment.invalid_relation")
|
||||
}
|
||||
|
||||
val agent = memberRepository.findByIdOrNull(request.agentId)
|
||||
?: throw SodaException(messageKey = "partner.agent.assignment.agent_not_found")
|
||||
if (agent.role != MemberRole.AGENT) {
|
||||
throw SodaException(messageKey = "partner.agent.assignment.invalid_agent")
|
||||
}
|
||||
|
||||
val creator = memberRepository.findByIdForUpdate(request.creatorId)
|
||||
?: throw SodaException(messageKey = "partner.agent.assignment.creator_not_found")
|
||||
if (creator.role != MemberRole.CREATOR) {
|
||||
throw SodaException(messageKey = "partner.agent.assignment.invalid_creator")
|
||||
}
|
||||
|
||||
val existingRelations = relationRepository.findAllByCreatorIdOrderByAssignedAtAsc(request.creatorId)
|
||||
if (hasAssignmentOverlap(existingRelations, request.assignedAt)) {
|
||||
throw SodaException(messageKey = "partner.agent.assignment.assignment_overlap")
|
||||
}
|
||||
|
||||
val relation = AgentCreatorRelation()
|
||||
relation.agent = agent
|
||||
relation.creator = creator
|
||||
relation.assignedAt = request.assignedAt
|
||||
try {
|
||||
relationRepository.saveAndFlush(relation)
|
||||
} catch (e: DataIntegrityViolationException) {
|
||||
relationRepository.findFirstByCreatorIdAndUnassignedAtIsNull(request.creatorId)
|
||||
?: throw e
|
||||
throw SodaException(messageKey = "partner.agent.assignment.assignment_overlap")
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun removeCreator(request: RemoveAgentCreatorRequest) {
|
||||
val creator = memberRepository.findByIdForUpdate(request.creatorId)
|
||||
?: throw SodaException(messageKey = "partner.agent.assignment.creator_not_found")
|
||||
if (creator.role != MemberRole.CREATOR) {
|
||||
throw SodaException(messageKey = "partner.agent.assignment.invalid_creator")
|
||||
}
|
||||
|
||||
val relation = relationRepository.findFirstByCreatorIdAndUnassignedAtIsNull(request.creatorId)
|
||||
?: throw SodaException(messageKey = "partner.agent.assignment.not_found")
|
||||
|
||||
val assignedAt = relation.assignedAt
|
||||
?: throw SodaException(messageKey = "partner.agent.assignment.not_found")
|
||||
if (!request.unassignedAt.isAfter(assignedAt)) {
|
||||
throw SodaException(messageKey = "partner.agent.assignment.invalid_unassigned_at")
|
||||
}
|
||||
|
||||
relation.unassignedAt = request.unassignedAt
|
||||
relationRepository.save(relation)
|
||||
}
|
||||
|
||||
private fun hasAssignmentOverlap(
|
||||
existingRelations: List<AgentCreatorRelation>,
|
||||
assignedAt: LocalDateTime
|
||||
): Boolean {
|
||||
return existingRelations.any { relation ->
|
||||
val existingUnassignedAt = relation.unassignedAt
|
||||
existingUnassignedAt == null || assignedAt.isBefore(existingUnassignedAt)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package kr.co.vividnext.sodalive.partner.agent.assignment
|
||||
|
||||
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import java.time.LocalDateTime
|
||||
import javax.persistence.Column
|
||||
import javax.persistence.Entity
|
||||
import javax.persistence.FetchType
|
||||
import javax.persistence.JoinColumn
|
||||
import javax.persistence.ManyToOne
|
||||
|
||||
@Entity
|
||||
class AgentCreatorRelation : BaseEntity() {
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "agent_id", nullable = false)
|
||||
var agent: Member? = null
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "creator_id", nullable = false)
|
||||
var creator: Member? = null
|
||||
|
||||
@Column(nullable = false)
|
||||
var assignedAt: LocalDateTime? = null
|
||||
|
||||
@Column(nullable = true)
|
||||
var unassignedAt: LocalDateTime? = null
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package kr.co.vividnext.sodalive.partner.agent.assignment
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
|
||||
interface AgentCreatorRelationRepository : JpaRepository<AgentCreatorRelation, Long> {
|
||||
fun findAllByCreatorIdOrderByAssignedAtAsc(creatorId: Long): List<AgentCreatorRelation>
|
||||
|
||||
fun findFirstByCreatorIdAndUnassignedAtIsNull(creatorId: Long): AgentCreatorRelation?
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package kr.co.vividnext.sodalive.partner.agent.assignment
|
||||
|
||||
import java.time.LocalDateTime
|
||||
|
||||
data class AssignAgentCreatorRequest(
|
||||
val agentId: Long,
|
||||
val creatorId: Long,
|
||||
val assignedAt: LocalDateTime
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
package kr.co.vividnext.sodalive.partner.agent.assignment
|
||||
|
||||
import java.time.LocalDateTime
|
||||
|
||||
data class RemoveAgentCreatorRequest(
|
||||
val creatorId: Long,
|
||||
val unassignedAt: LocalDateTime
|
||||
)
|
||||
Reference in New Issue
Block a user