Skip to content

Commit

Permalink
[YS-97] feat: 피험자 모집 실험 공고 상세 정보 조회 API 구현 및 자잘한 리팩터링 (#27)
Browse files Browse the repository at this point in the history
* refactor: Update region and area's values to English for consistency

* feat: add ExperimentPostDetailResponse

* refactor: Update timeSlot's values to English for consistency

* refact: rename Signup to Member for consistency

* refact: remove AuditingEntity and manually set createdAt

* refact: refactor ExperimentPostDetailResponse

* feat: add getExperimentPostDetail Api

* refact: rename state field's name

* feat: add increment views

* test: add GetExperimentPostDetailUseCase test code

* refact: change field types to enum in response and request DTOs

* refact: add `@PreAuthorize` for researcher's api

* refact: Handle nullable fields for CreateExperimentPost in the flow

* feat: add annotation to appropriate api
  • Loading branch information
Ji-soo708 authored Jan 12, 2025
1 parent 6988476 commit c899c50
Show file tree
Hide file tree
Showing 51 changed files with 860 additions and 577 deletions.
2 changes: 0 additions & 2 deletions src/main/kotlin/com/dobby/backend/DobbyBackendApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.cloud.openfeign.EnableFeignClients
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.FilterType
import org.springframework.data.jpa.repository.config.EnableJpaAuditing

@ComponentScan(
includeFilters = [ComponentScan.Filter(
Expand All @@ -18,7 +17,6 @@ import org.springframework.data.jpa.repository.config.EnableJpaAuditing
@SpringBootApplication
@ConfigurationPropertiesScan
@EnableFeignClients
@EnableJpaAuditing
class DobbyBackendApplication

fun main(args: Array<String>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import com.dobby.backend.domain.model.member.Participant
import com.dobby.backend.domain.model.member.Researcher
import com.dobby.backend.infrastructure.database.entity.member.MemberEntity
import com.dobby.backend.infrastructure.database.entity.member.ParticipantEntity
import com.dobby.backend.infrastructure.database.entity.enum.MemberStatus
import com.dobby.backend.infrastructure.database.entity.enum.RoleType
import com.dobby.backend.presentation.api.dto.request.signup.ParticipantSignupRequest
import com.dobby.backend.infrastructure.database.entity.member.AddressInfo
import com.dobby.backend.infrastructure.database.entity.member.ResearcherEntity
Expand All @@ -19,29 +17,7 @@ object SignupMapper {
dto.area
)
}
fun toParticipantMember(req: ParticipantSignupRequest): MemberEntity {
return MemberEntity(
id = 0, // Auto-generated
oauthEmail = req.oauthEmail,
provider = req.provider,
status = MemberStatus.ACTIVE,
role = RoleType.PARTICIPANT,
contactEmail = req.contactEmail,
name = req.name
)
}

fun toResearcherMember(req: CreateResearcherUseCase.Input): MemberEntity {
return MemberEntity(
id = 0, // Auto-generated
oauthEmail = req.oauthEmail,
provider = req.provider,
status = MemberStatus.ACTIVE,
role = RoleType.RESEARCHER,
contactEmail = req.contactEmail,
name = req.name,
)
}
fun toParticipant(
member: MemberEntity,
req: ParticipantSignupRequest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ object VerificationMapper {
univEmail = req.univEmail,
verificationCode = code,
status = VerificationStatus.HOLD,
expiresAt = null
expiresAt = null,
createdAt = null,
updatedAt = null
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package com.dobby.backend.application.service

import com.dobby.backend.application.usecase.experiment.CreateExperimentPostUseCase
import com.dobby.backend.application.usecase.experiment.GetExperimentPostDetailUseCase
import com.dobby.backend.application.usecase.experiment.GetResearcherInfoUseCase
import jakarta.transaction.Transactional
import org.springframework.stereotype.Service

@Service
class ExperimentPostService(
private val createExperimentPostUseCase: CreateExperimentPostUseCase,
private val getResearcherInfoUseCase: GetResearcherInfoUseCase
private val getResearcherInfoUseCase: GetResearcherInfoUseCase,
private val getExperimentPostDetailUseCase: GetExperimentPostDetailUseCase
) {
@Transactional
fun createNewExperimentPost(input: CreateExperimentPostUseCase.Input): CreateExperimentPostUseCase.Output {
Expand All @@ -18,4 +20,8 @@ class ExperimentPostService(
fun getDefaultInfo(input: GetResearcherInfoUseCase.Input): GetResearcherInfoUseCase.Output {
return getResearcherInfoUseCase.execute(input)
}

fun getExperimentPostDetail(input: GetExperimentPostDetailUseCase.Input): GetExperimentPostDetailUseCase.Output {
return getExperimentPostDetailUseCase.execute(input)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import jakarta.transaction.Transactional
import org.springframework.stereotype.Service

@Service
class SignupService(
class MemberService(
private val memberGateway: MemberGateway,
private val createParticipantUseCase: CreateParticipantUseCase,
private val createResearcherUseCase: CreateResearcherUseCase,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package com.dobby.backend.application.usecase.experiment

import com.dobby.backend.application.usecase.UseCase
import com.dobby.backend.domain.exception.PermissionDeniedException
import com.dobby.backend.domain.gateway.*
Expand All @@ -13,22 +14,24 @@ import com.dobby.backend.infrastructure.database.entity.enum.TimeSlot
import com.dobby.backend.infrastructure.database.entity.enum.areaInfo.Area
import com.dobby.backend.infrastructure.database.entity.enum.areaInfo.Region
import java.time.LocalDate
import java.time.LocalDateTime

class CreateExperimentPostUseCase(
private val experimentPostGateway: ExperimentPostGateway,
private val memberGateway: MemberGateway,
private val memberGateway: MemberGateway
) : UseCase<CreateExperimentPostUseCase.Input, CreateExperimentPostUseCase.Output> {

data class Input(
val memberId: Long,
val targetGroupInfo: TargetGroupInfo,
val applyMethodInfo: ApplyMethodInfo,
val imageListInfo: ImageListInfo,

val startDate: LocalDate,
val endDate: LocalDate,
val startDate: LocalDate?,
val endDate: LocalDate?,
val matchType: MatchType,
val count: Int, // N 회 참여
val durationMinutes: TimeSlot,
val timeRequired: TimeSlot?,

val leadResearcher: String,
val univName: String,
Expand All @@ -46,13 +49,13 @@ class CreateExperimentPostUseCase(
val startAge: Int?,
val endAge: Int?,
val genderType: GenderType,
val otherCondition: String?,
val otherCondition: String?
)

data class ApplyMethodInfo(
val content: String,
val formUrl: String?,
val phoneNum: String?,
val phoneNum: String?
)

data class ImageListInfo(
Expand All @@ -67,10 +70,10 @@ class CreateExperimentPostUseCase(
val postId: Long,
val title: String,
val views: Int,
val school: String,
val univName: String,
val reward: String,
val startDate: LocalDate,
val endDate: LocalDate
val startDate: LocalDate?,
val endDate: LocalDate?
)

override fun execute(input: Input): Output {
Expand All @@ -79,6 +82,7 @@ class CreateExperimentPostUseCase(
if (member.role != RoleType.RESEARCHER) {
throw PermissionDeniedException()
}

val targetGroup = createTargetGroup(input.targetGroupInfo)
val applyMethod = createApplyMethod(input.applyMethodInfo)
val experimentPost = createExperimentPost(member, input, targetGroup, applyMethod)
Expand All @@ -89,7 +93,7 @@ class CreateExperimentPostUseCase(
postId = savedExperimentPost.id,
title = savedExperimentPost.title,
views = savedExperimentPost.views,
school = savedExperimentPost.univName,
univName = savedExperimentPost.univName,
startDate = savedExperimentPost.startDate,
endDate = savedExperimentPost.endDate,
reward = savedExperimentPost.reward
Expand All @@ -99,27 +103,26 @@ class CreateExperimentPostUseCase(

private fun createTargetGroup(targetGroupInfo: TargetGroupInfo): TargetGroup {
return TargetGroup(
id = 0L,
startAge = targetGroupInfo.startAge,
endAge = targetGroupInfo.endAge,
genderType = targetGroupInfo.genderType,
otherCondition = targetGroupInfo.otherCondition
)
}
id = 0L,
startAge = targetGroupInfo.startAge,
endAge = targetGroupInfo.endAge,
genderType = targetGroupInfo.genderType,
otherCondition = targetGroupInfo.otherCondition
)
}

private fun createApplyMethod(applyMethodInfo: CreateExperimentPostUseCase.ApplyMethodInfo): ApplyMethod {
private fun createApplyMethod(applyMethodInfo: ApplyMethodInfo): ApplyMethod {
return ApplyMethod(
id = 0L,
phoneNum = applyMethodInfo.phoneNum,
formUrl = applyMethodInfo.formUrl,
content = applyMethodInfo.content
)
id = 0L,
phoneNum = applyMethodInfo.phoneNum,
formUrl = applyMethodInfo.formUrl,
content = applyMethodInfo.content
)
}

private fun createExperimentPost(
member: Member,
input: CreateExperimentPostUseCase.Input,
input: Input,
targetGroup: TargetGroup,
applyMethod: ApplyMethod
): ExperimentPost {
Expand All @@ -135,15 +138,17 @@ class CreateExperimentPostUseCase(
reward = input.reward,
startDate = input.startDate,
endDate = input.endDate,
durationMinutes = input.durationMinutes,
timeRequired = input.timeRequired,
count = input.count,
matchType = input.matchType,
univName = input.univName,
region = input.region,
area = input.area,
detailedAddress = input.detailedAddress,
alarmAgree = input.alarmAgree,
images = emptyList() // 이미지 업로드 보류
images = emptyList(), // 이미지 업로드 보류
createdAt = LocalDateTime.now(),
updatedAt = LocalDateTime.now()
)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.dobby.backend.application.usecase.experiment

import com.dobby.backend.application.usecase.UseCase
import com.dobby.backend.domain.exception.ExperimentPostNotFoundException
import com.dobby.backend.domain.gateway.ExperimentPostGateway
import com.dobby.backend.domain.model.experiment.ExperimentPost
import com.dobby.backend.domain.model.experiment.TargetGroup
import com.dobby.backend.presentation.api.dto.response.expirement.ExperimentPostDetailResponse

class GetExperimentPostDetailUseCase(
private val experimentPostGateway: ExperimentPostGateway
) : UseCase<GetExperimentPostDetailUseCase.Input, GetExperimentPostDetailUseCase.Output> {

data class Input(
val experimentPostId: Long
)

data class Output(
val experimentPostDetailResponse: ExperimentPostDetailResponse
)

override fun execute(input: Input): Output {
val experimentPost = experimentPostGateway.findById(input.experimentPostId)
?: throw ExperimentPostNotFoundException()
experimentPost.incrementViews()
experimentPostGateway.save(experimentPost)

return Output(
experimentPostDetailResponse = experimentPost.toDetailResponse()
)
}
}

fun ExperimentPost.toDetailResponse(): ExperimentPostDetailResponse {
return ExperimentPostDetailResponse(
experimentPostId = this.id,
title = this.title,
uploadDate = this.createdAt.toLocalDate(),
uploaderName = this.member.name,
views = this.views,
recruitDone = this.recruitDone,
summary = this.toSummaryResponse(),
targetGroup = this.targetGroup.toResponse(),
address = this.toAddressResponse(),
content = this.content,
imageList = this.images.map { it.imageUrl }
)
}

fun ExperimentPost.toSummaryResponse(): ExperimentPostDetailResponse.SummaryResponse {
return ExperimentPostDetailResponse.SummaryResponse(
startDate = this.startDate,
endDate = this.endDate,
leadResearcher = this.leadResearcher,
matchType = this.matchType,
reward = this.reward,
count = this.count,
timeRequired = this.timeRequired
)
}

fun TargetGroup.toResponse(): ExperimentPostDetailResponse.TargetGroupResponse {
return ExperimentPostDetailResponse.TargetGroupResponse(
startAge = this.startAge,
endAge = this.endAge,
genderType = this.genderType,
otherCondition = this.otherCondition
)
}

fun ExperimentPost.toAddressResponse(): ExperimentPostDetailResponse.AddressResponse {
return ExperimentPostDetailResponse.AddressResponse(
univName = this.univName,
region = this.region,
area = this.area,
detailedAddress = this.detailedAddress
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.dobby.backend.infrastructure.database.entity.enum.*
import com.dobby.backend.infrastructure.database.entity.enum.areaInfo.Area
import com.dobby.backend.infrastructure.database.entity.enum.areaInfo.Region
import java.time.LocalDate
import java.time.LocalDateTime

class CreateParticipantUseCase (
private val participantGateway: ParticipantGateway,
Expand Down Expand Up @@ -71,7 +72,9 @@ class CreateParticipantUseCase (
provider = input.provider,
role = RoleType.PARTICIPANT,
name = input.name,
status = MemberStatus.ACTIVE
status = MemberStatus.ACTIVE,
createdAt = LocalDateTime.now(),
updatedAt = LocalDateTime.now()
)

return Participant(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.dobby.backend.domain.gateway.TokenGateway
import com.dobby.backend.domain.model.member.Member
import com.dobby.backend.domain.model.member.Researcher
import com.dobby.backend.infrastructure.database.entity.enum.*
import java.time.LocalDateTime

class CreateResearcherUseCase(
private val memberGateway: MemberGateway,
Expand Down Expand Up @@ -63,7 +64,9 @@ class CreateResearcherUseCase(
contactEmail = input.contactEmail,
provider = input.provider,
role = RoleType.RESEARCHER,
name = input.name
name = input.name,
createdAt = LocalDateTime.now(),
updatedAt = LocalDateTime.now()
)

val researcher = Researcher(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ class EmailCodeSendUseCase(
univEmail = univEmail,
verificationCode = code,
status = VerificationStatus.HOLD,
expiresAt = LocalDateTime.now().plusMinutes(10)
expiresAt = LocalDateTime.now().plusMinutes(10),
createdAt = LocalDateTime.now(),
updatedAt = LocalDateTime.now()
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ enum class ErrorCode(
VERIFY_ALREADY_VERIFIED("VE007", "This email is already verified", HttpStatus.CONFLICT),

/**
* Researcher Post error codes
* Researcher error codes
*/
RESEARCHER_NOT_FOUND("RE001", "Researcher Not Found.", HttpStatus.NOT_FOUND),

/**
* Experiment Post error codes
*/
EXPERIMENT_POST_NOT_FOUND("EP001", "Experiment Post Not Found.", HttpStatus.NOT_FOUND),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.dobby.backend.domain.exception

open class ExperimentPostException(
errorCode: ErrorCode,
) : DomainException(errorCode)

class ExperimentPostNotFoundException : ExperimentPostException(ErrorCode.EXPERIMENT_POST_NOT_FOUND)
Loading

0 comments on commit c899c50

Please sign in to comment.