diff --git a/pic-api/src/main/kotlin/com/mashup/pic/group/applicationservice/GroupApplicationService.kt b/pic-api/src/main/kotlin/com/mashup/pic/group/applicationservice/GroupApplicationService.kt index 12c0d8d..5f753c8 100644 --- a/pic-api/src/main/kotlin/com/mashup/pic/group/applicationservice/GroupApplicationService.kt +++ b/pic-api/src/main/kotlin/com/mashup/pic/group/applicationservice/GroupApplicationService.kt @@ -1,5 +1,8 @@ package com.mashup.pic.group.applicationservice +import com.mashup.pic.common.exception.PicException +import com.mashup.pic.common.exception.PicExceptionType +import com.mashup.pic.domain.event.EventDto import com.mashup.pic.domain.event.EventService import com.mashup.pic.domain.event.EventStatus import com.mashup.pic.domain.event.UploadService @@ -13,8 +16,10 @@ import com.mashup.pic.group.applicationservice.dto.CreateGroupServiceRequest import com.mashup.pic.group.applicationservice.dto.JoinGroupServiceRequest import com.mashup.pic.group.controller.dto.FramedImage import com.mashup.pic.group.controller.dto.GroupViewStatus +import com.mashup.pic.group.controller.dto.HistoryItem import com.mashup.pic.group.controller.dto.JoinGroupResponse import com.mashup.pic.group.controller.dto.RecentEvent +import com.mashup.pic.group.controller.dto.RecentEventDetail import com.mashup.pic.group.controller.dto.ViewGroupDetailResponse import com.mashup.pic.group.controller.dto.ViewGroupItem import com.mashup.pic.group.controller.dto.ViewGroupResponse @@ -23,6 +28,7 @@ import com.mashup.pic.group.util.GroupViewStatusUtil import com.mashup.pic.util.InviteCodeUtil import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional +import java.time.LocalDateTime @Service @Transactional(readOnly = true) @@ -58,12 +64,69 @@ class GroupApplicationService( return ViewGroupResponse(groupItems) } - fun getGroup( + fun getGroupDetail( userId: Long, groupId: Long - ): ViewGroupDetailResponse? { - // TODO: add detail view logic - return null + ): ViewGroupDetailResponse { + val group = groupService.getGroupById(groupId) + val lastEvent = eventService.getLastEvent(group.id) + + val status: GroupViewStatus + val statusDescription = GroupViewStatusUtil.generateDescription(lastEvent) + var recentEventDetail = RecentEventDetail() + val cardFrontImageUrl: String + var cardBackImages: ResultDto? = null + + if (lastEvent == null) { // 현 이벤트 X, 역대 이벤트 X + status = GroupViewStatus.NO_PAST_AND_CURRENT_EVENT + cardFrontImageUrl = group.imageUrl + } else if (lastEvent.eventStatus == EventStatus.COMPLETE) { // 현 이벤트 X, 역대 이벤트 O + status = + if (eventService.hasVisitedEvent(userId, lastEvent.id)) { // 방문했다면 + GroupViewStatus.NO_CURRENT_EVENT + } else { + GroupViewStatus.EVENT_COMPLETED + } + recentEventDetail = RecentEventDetail(lastEvent.id, lastEvent.description, lastEvent.date, getDeadline(lastEvent)) + cardBackImages = resultService.getResultOfEvent(lastEvent.id) + cardFrontImageUrl = cardBackImages.resultImages[0].imageUrl + } else { // 현 이벤트 O + recentEventDetail = RecentEventDetail(lastEvent.id, lastEvent.description, lastEvent.date, getDeadline(lastEvent)) + cardFrontImageUrl = eventService.getRandomImageOptionFromEvent(lastEvent.id) + + status = + when (lastEvent.eventStatus) { + EventStatus.UPLOADING -> + if (uploadService.hasUserUploaded(userId, lastEvent.id)) { + GroupViewStatus.AFTER_MY_UPLOAD + } else { + GroupViewStatus.BEFORE_MY_UPLOAD + } + + EventStatus.VOTING -> + if (voteService.hasUserVoted(userId, lastEvent.id)) { + GroupViewStatus.AFTER_MY_VOTE + } else { + GroupViewStatus.BEFORE_MY_VOTE + } + + else -> { + GroupViewStatus.NO_CURRENT_EVENT + } + } + } + + return ViewGroupDetailResponse( + id = groupId, + name = group.name, + keyword = group.keyword, + status = status, + statusDescription = statusDescription, + recentEvent = recentEventDetail, + cardFrontImageUrl = cardFrontImageUrl, + cardBackImages = convertResultDtoToFramedImages(cardBackImages), + history = getHistoryItems(groupId) + ) } private fun getViewGroupItem( @@ -82,12 +145,12 @@ class GroupApplicationService( status = GroupViewStatus.NO_PAST_AND_CURRENT_EVENT cardFrontImageUrl = group.imageUrl } else if (lastEvent.eventStatus == EventStatus.COMPLETE) { // 현 이벤트 X, 역대 이벤트 O - status = GroupViewStatus.EVENT_COMPLETED - recentEvent = RecentEvent(lastEvent.description, lastEvent.date) + status = GroupViewStatus.NO_CURRENT_EVENT + recentEvent = RecentEvent(lastEvent.id, lastEvent.description, lastEvent.date) cardBackImages = resultService.getResultOfEvent(lastEvent.id) cardFrontImageUrl = cardBackImages.resultImages[0].imageUrl } else { // 현 이벤트 O - recentEvent = RecentEvent(lastEvent.description, lastEvent.date) + recentEvent = RecentEvent(lastEvent.id, lastEvent.description, lastEvent.date) cardFrontImageUrl = eventService.getRandomImageOptionFromEvent(lastEvent.id) status = @@ -107,7 +170,7 @@ class GroupApplicationService( } else -> { - GroupViewStatus.EVENT_COMPLETED + GroupViewStatus.NO_CURRENT_EVENT } } } @@ -121,6 +184,26 @@ class GroupApplicationService( ) } + private fun getHistoryItems(groupId: Long): List { + val events = eventService.getAllEventsAsc(groupId).drop(1) + return events.map { + HistoryItem( + id = it.id, + name = it.description, + date = it.date, + images = convertResultDtoToFramedImages(resultService.getResultOfEvent(it.id)) + ) + } + } + + private fun getDeadline(event: EventDto): LocalDateTime { + if (event.eventStatus == EventStatus.UPLOADING) { + return event.createdAt.plusHours(UPLOADING_HOURS) + } + + return event.uploadingEndDate?.plusHours(VOTING_HOURS) ?: throw PicException.of(PicExceptionType.ARGUMENT_NOT_VALID, "업로드 종료 시간 오류") + } + private fun convertResultDtoToFramedImages(resultDto: ResultDto?): List? { return resultDto?.resultImages?.map { resultItem -> FramedImage( @@ -129,4 +212,9 @@ class GroupApplicationService( ) } } + + companion object { + const val UPLOADING_HOURS = 2L + const val VOTING_HOURS = 2L + } } diff --git a/pic-api/src/main/kotlin/com/mashup/pic/group/controller/GroupController.kt b/pic-api/src/main/kotlin/com/mashup/pic/group/controller/GroupController.kt index a20fc65..18aa160 100644 --- a/pic-api/src/main/kotlin/com/mashup/pic/group/controller/GroupController.kt +++ b/pic-api/src/main/kotlin/com/mashup/pic/group/controller/GroupController.kt @@ -65,6 +65,6 @@ class GroupController(private val groupApplicationService: GroupApplicationServi @AuthenticationPrincipal userInfo: UserInfo, @PathVariable groupId: Long ): ApiResponse { - return ApiResponse.success(groupApplicationService.getGroup(userInfo.id, groupId)) + return ApiResponse.success(groupApplicationService.getGroupDetail(userInfo.id, groupId)) } } diff --git a/pic-api/src/main/kotlin/com/mashup/pic/group/controller/dto/ViewGroupDetailResponse.kt b/pic-api/src/main/kotlin/com/mashup/pic/group/controller/dto/ViewGroupDetailResponse.kt index 13d5b01..2b2e536 100644 --- a/pic-api/src/main/kotlin/com/mashup/pic/group/controller/dto/ViewGroupDetailResponse.kt +++ b/pic-api/src/main/kotlin/com/mashup/pic/group/controller/dto/ViewGroupDetailResponse.kt @@ -16,14 +16,15 @@ data class ViewGroupDetailResponse( ) data class RecentEventDetail( - val name: String, - val date: LocalDateTime, - val deadline: LocalDateTime + val id: Long = -1, + val name: String = "", + val date: LocalDateTime = LocalDateTime.now(), + val deadline: LocalDateTime = LocalDateTime.now() ) data class HistoryItem( val id: Long, val name: String, val date: LocalDateTime, - val images: List + val images: List? ) diff --git a/pic-api/src/main/kotlin/com/mashup/pic/group/controller/dto/ViewGroupResponse.kt b/pic-api/src/main/kotlin/com/mashup/pic/group/controller/dto/ViewGroupResponse.kt index 806046b..c693dca 100644 --- a/pic-api/src/main/kotlin/com/mashup/pic/group/controller/dto/ViewGroupResponse.kt +++ b/pic-api/src/main/kotlin/com/mashup/pic/group/controller/dto/ViewGroupResponse.kt @@ -26,6 +26,7 @@ data class FramedImage( ) data class RecentEvent( + var id: Long = -1, var name: String? = null, var date: LocalDateTime? = null ) diff --git a/pic-api/src/main/kotlin/com/mashup/pic/group/util/GroupViewStatusUtil.kt b/pic-api/src/main/kotlin/com/mashup/pic/group/util/GroupViewStatusUtil.kt index 27b5527..641fafa 100644 --- a/pic-api/src/main/kotlin/com/mashup/pic/group/util/GroupViewStatusUtil.kt +++ b/pic-api/src/main/kotlin/com/mashup/pic/group/util/GroupViewStatusUtil.kt @@ -1,48 +1,31 @@ package com.mashup.pic.group.util import com.mashup.pic.domain.event.EventDto -import com.mashup.pic.group.controller.dto.GroupViewStatus +import java.time.LocalDateTime +import java.time.temporal.ChronoUnit object GroupViewStatusUtil { - fun determineStatus( - hasCurrentEvent: Boolean, - hasPastEvent: Boolean, - uploaded: Boolean, - voted: Boolean - ): GroupViewStatus { - return when { - !hasCurrentEvent && !hasPastEvent -> GroupViewStatus.NO_PAST_AND_CURRENT_EVENT - hasCurrentEvent && !hasPastEvent -> GroupViewStatus.NO_CURRENT_EVENT - !uploaded && !voted -> GroupViewStatus.BEFORE_MY_UPLOAD - uploaded && !voted -> GroupViewStatus.AFTER_MY_UPLOAD - uploaded && voted -> GroupViewStatus.BEFORE_MY_VOTE - else -> GroupViewStatus.AFTER_MY_VOTE - } - } - - fun determineStatus( - hasCurrentEvent: Boolean, - hasPastEvent: Boolean, - uploaded: Boolean, - voted: Boolean, - visited: Boolean - ): GroupViewStatus { - return when { - !hasCurrentEvent && !hasPastEvent -> GroupViewStatus.NO_PAST_AND_CURRENT_EVENT - hasCurrentEvent && !hasPastEvent -> GroupViewStatus.NO_CURRENT_EVENT - !uploaded && !voted -> GroupViewStatus.BEFORE_MY_UPLOAD - uploaded && !voted -> GroupViewStatus.AFTER_MY_UPLOAD - uploaded && voted -> GroupViewStatus.BEFORE_MY_VOTE - !visited -> GroupViewStatus.AFTER_MY_VOTE - else -> GroupViewStatus.EVENT_COMPLETED - } - } + private const val RECENT_UPDATE = "최근 업데이트가 없습니다." + private const val VOTING_MESSAGE = "쉿, 투표 중" + private const val DAYS_AGO_UPDATE = "%d일 전 업데이트" + private const val WEEK_AGO_UPDATE = "일주일 전 업데이트" + private const val TWO_WEEKS_AGO_UPDATE = "이주일 전 업데이트" + private const val NO_RECENT_PIC = "최근 PIC이 없어요" - // TODO: Update with real parameters fun generateDescription(event: EventDto?): String { - return when { - event != null -> "최근 업데이트 10일 전" - else -> "쉿, 투표 중" + return if (event != null) { + val daysSinceUpdate = ChronoUnit.DAYS.between(event.date.toLocalDate(), LocalDateTime.now().toLocalDate()) + + when { + daysSinceUpdate in 1..6 -> DAYS_AGO_UPDATE.format(daysSinceUpdate) + daysSinceUpdate == 7L -> WEEK_AGO_UPDATE + daysSinceUpdate in 8..13 -> DAYS_AGO_UPDATE.format(daysSinceUpdate) + daysSinceUpdate == 14L -> TWO_WEEKS_AGO_UPDATE + daysSinceUpdate >= 15 -> NO_RECENT_PIC + else -> RECENT_UPDATE + } + } else { + VOTING_MESSAGE } } } diff --git a/pic-domain/src/main/kotlin/com/mashup/pic/domain/event/EventDto.kt b/pic-domain/src/main/kotlin/com/mashup/pic/domain/event/EventDto.kt index 56b2918..3aab5dd 100644 --- a/pic-domain/src/main/kotlin/com/mashup/pic/domain/event/EventDto.kt +++ b/pic-domain/src/main/kotlin/com/mashup/pic/domain/event/EventDto.kt @@ -9,7 +9,8 @@ data class EventDto( val date: LocalDateTime, val eventStatus: EventStatus, val uploadingEndDate: LocalDateTime?, - val votingEndDate: LocalDateTime? + val votingEndDate: LocalDateTime?, + val createdAt: LocalDateTime ) fun Event.toDto(): EventDto { @@ -20,6 +21,7 @@ fun Event.toDto(): EventDto { date = this.date, eventStatus = this.eventStatus, uploadingEndDate = this.uploadingEndDate, - votingEndDate = this.votingEndDate + votingEndDate = this.votingEndDate, + createdAt = this.createdAt ) } diff --git a/pic-domain/src/main/kotlin/com/mashup/pic/domain/event/EventRepository.kt b/pic-domain/src/main/kotlin/com/mashup/pic/domain/event/EventRepository.kt index 1f468cc..46b94aa 100644 --- a/pic-domain/src/main/kotlin/com/mashup/pic/domain/event/EventRepository.kt +++ b/pic-domain/src/main/kotlin/com/mashup/pic/domain/event/EventRepository.kt @@ -4,4 +4,8 @@ import org.springframework.data.jpa.repository.JpaRepository interface EventRepository : JpaRepository { fun findTopByGroupIdOrderByDateDesc(groupId: Long): Event? + + fun findTopByGroupIdOrderByDateAsc(groupId: Long): Event? + + fun findAllByGroupIdOrderByIdDesc(groupId: Long): List } diff --git a/pic-domain/src/main/kotlin/com/mashup/pic/domain/event/EventService.kt b/pic-domain/src/main/kotlin/com/mashup/pic/domain/event/EventService.kt index 9a023c7..f7ae9ac 100644 --- a/pic-domain/src/main/kotlin/com/mashup/pic/domain/event/EventService.kt +++ b/pic-domain/src/main/kotlin/com/mashup/pic/domain/event/EventService.kt @@ -49,7 +49,7 @@ class EventService( } fun getLastEvent(groupId: Long): EventDto? { - return eventRepository.findTopByGroupIdOrderByDateDesc(groupId)?.toDto() + return eventRepository.findTopByGroupIdOrderByDateAsc(groupId)?.toDto() } fun getRandomImageOptionFromEvent(eventId: Long): String { @@ -99,6 +99,18 @@ class EventService( } } + fun hasVisitedEvent( + userId: Long, + eventId: Long + ): Boolean { + return getEventJoinByUserIdAndEventId(userId, eventId).isVisited + } + + fun getAllEventsAsc(groupId: Long): List { + val events = eventRepository.findAllByGroupIdOrderByIdDesc(groupId) + return events.map { it.toDto() } + } + private fun validateUserImageUpload( event: Event, evenJoinId: Long diff --git a/pic-domain/src/main/kotlin/com/mashup/pic/domain/group/GroupService.kt b/pic-domain/src/main/kotlin/com/mashup/pic/domain/group/GroupService.kt index c17f059..2e0b1a1 100644 --- a/pic-domain/src/main/kotlin/com/mashup/pic/domain/group/GroupService.kt +++ b/pic-domain/src/main/kotlin/com/mashup/pic/domain/group/GroupService.kt @@ -3,6 +3,7 @@ package com.mashup.pic.domain.group import com.mashup.pic.common.exception.PicException import com.mashup.pic.common.exception.PicExceptionType import com.mashup.pic.domain.user.UserRepository +import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -41,6 +42,10 @@ class GroupService( return groupRepository.findAllById(myGroupIds).map { it.toDto() } } + fun getGroupById(groupId: Long): GroupDto { + return groupRepository.findByIdOrNull(groupId)?.toDto() ?: throw PicException.of(PicExceptionType.ARGUMENT_NOT_VALID, "없는 그룹 ID") + } + private fun validateUser(userId: Long) { if (!checkUserExists(userId)) { throw PicException.of(