diff --git a/src/main/kotlin/com/tistory/shanepark/dutypark/member/service/FriendService.kt b/src/main/kotlin/com/tistory/shanepark/dutypark/member/service/FriendService.kt index 11a368ed..6a1819e0 100644 --- a/src/main/kotlin/com/tistory/shanepark/dutypark/member/service/FriendService.kt +++ b/src/main/kotlin/com/tistory/shanepark/dutypark/member/service/FriendService.kt @@ -180,4 +180,17 @@ class FriendService( } } + @Transactional(readOnly = true) + fun availableVisibilities(loginMember: LoginMember?, member: Member): Set { + if (loginMember == null) + return setOf(Visibility.PUBLIC) + if (loginMember.id == member.id) { + return Visibility.entries.toSet() + } + if (isFriend(loginMember.id, member.id!!)) { + return setOf(Visibility.PUBLIC, Visibility.FRIENDS) + } + return setOf(Visibility.PUBLIC) + } + } diff --git a/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/controller/ScheduleController.kt b/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/controller/ScheduleController.kt index e910d90d..e5664d32 100644 --- a/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/controller/ScheduleController.kt +++ b/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/controller/ScheduleController.kt @@ -2,9 +2,14 @@ package com.tistory.shanepark.dutypark.schedule.controller import com.tistory.shanepark.dutypark.member.domain.annotation.Login import com.tistory.shanepark.dutypark.schedule.domain.dto.ScheduleDto +import com.tistory.shanepark.dutypark.schedule.domain.dto.ScheduleSearchResult import com.tistory.shanepark.dutypark.schedule.domain.dto.ScheduleUpdateDto +import com.tistory.shanepark.dutypark.schedule.service.ScheduleSearchService import com.tistory.shanepark.dutypark.schedule.service.ScheduleService import com.tistory.shanepark.dutypark.security.domain.dto.LoginMember +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.web.PageableDefault import org.springframework.http.ResponseEntity import org.springframework.validation.annotation.Validated import org.springframework.web.bind.annotation.* @@ -15,6 +20,7 @@ import java.util.* @RequestMapping("/api/schedules") class ScheduleController( private val scheduleService: ScheduleService, + private val scheduleSearchService: ScheduleSearchService, ) { @GetMapping @@ -31,6 +37,16 @@ class ScheduleController( ) } + @GetMapping("/{id}/search") + fun searchSchedule( + @Login(required = false) loginMember: LoginMember, + @PathVariable(value = "id") targetMemberId: Long, + @PageableDefault(size = 10) pageable: Pageable, + @RequestParam q: String + ): Page { + return scheduleSearchService.search(loginMember, targetMemberId, pageable, q) + } + @PostMapping fun createSchedule( @RequestBody @Validated scheduleUpdateDto: ScheduleUpdateDto, diff --git a/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/domain/dto/ScheduleSearchResult.kt b/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/domain/dto/ScheduleSearchResult.kt new file mode 100644 index 00000000..6802c489 --- /dev/null +++ b/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/domain/dto/ScheduleSearchResult.kt @@ -0,0 +1,24 @@ +package com.tistory.shanepark.dutypark.schedule.domain.dto + +import com.tistory.shanepark.dutypark.schedule.domain.entity.Schedule +import java.time.LocalDateTime + +data class ScheduleSearchResult( + val content: String, + val startDateTime: LocalDateTime, + val endDateTime: LocalDateTime, + val visibility: String, + val isTagged: Boolean, +) { + companion object { + fun of(schedule: Schedule): ScheduleSearchResult { + return ScheduleSearchResult( + content = schedule.content, + startDateTime = schedule.startDateTime, + endDateTime = schedule.endDateTime, + visibility = schedule.visibility.name, + isTagged = schedule.tags.isNotEmpty() + ) + } + } +} diff --git a/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/repository/ScheduleRepository.kt b/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/repository/ScheduleRepository.kt index d235a715..73fb8ceb 100644 --- a/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/repository/ScheduleRepository.kt +++ b/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/repository/ScheduleRepository.kt @@ -3,6 +3,8 @@ package com.tistory.shanepark.dutypark.schedule.repository import com.tistory.shanepark.dutypark.member.domain.entity.Member import com.tistory.shanepark.dutypark.member.domain.enums.Visibility import com.tistory.shanepark.dutypark.schedule.domain.entity.Schedule +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query import java.time.LocalDateTime @@ -10,6 +12,24 @@ import java.util.* interface ScheduleRepository : JpaRepository { + @Query( + "SELECT s" + + " FROM Schedule s" + + " JOIN FETCH s.member m" + + " LEFT JOIN FETCH s.tags t" + + " LEFT JOIN FETCH t.member tm" + + " WHERE (m = :member or tm = :member)" + + " AND s.content LIKE %:content%" + + " AND s.visibility IN (:visibility)" + + " ORDER BY s.startDateTime DESC" + ) + fun findByMemberAndContentContainingAndVisibilityIn( + member: Member, + content: String, + visibility: Collection, + pageable: Pageable, + ): Page + @Query( "SELECT s" + " FROM Schedule s" + diff --git a/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/service/ScheduleSearchService.kt b/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/service/ScheduleSearchService.kt new file mode 100644 index 00000000..f00d4425 --- /dev/null +++ b/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/service/ScheduleSearchService.kt @@ -0,0 +1,11 @@ +package com.tistory.shanepark.dutypark.schedule.service + +import com.tistory.shanepark.dutypark.schedule.domain.dto.ScheduleSearchResult +import com.tistory.shanepark.dutypark.security.domain.dto.LoginMember +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable + +interface ScheduleSearchService { + + fun search(loginMember: LoginMember, targetMemberId: Long, page: Pageable, query: String): Page +} diff --git a/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/service/ScheduleSearchServiceDBImpl.kt b/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/service/ScheduleSearchServiceDBImpl.kt new file mode 100644 index 00000000..3b5678ea --- /dev/null +++ b/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/service/ScheduleSearchServiceDBImpl.kt @@ -0,0 +1,39 @@ +package com.tistory.shanepark.dutypark.schedule.service + +import com.tistory.shanepark.dutypark.member.repository.MemberRepository +import com.tistory.shanepark.dutypark.member.service.FriendService +import com.tistory.shanepark.dutypark.schedule.domain.dto.ScheduleSearchResult +import com.tistory.shanepark.dutypark.schedule.repository.ScheduleRepository +import com.tistory.shanepark.dutypark.security.domain.dto.LoginMember +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service + +/** + * When search engine is implemented, this service will be replaced with ScheduleSearchServiceESImpl + */ +@Service +class ScheduleSearchServiceDBImpl( + private val scheduleRepository: ScheduleRepository, + private val memberRepository: MemberRepository, + private val friendService: FriendService, +) : ScheduleSearchService { + + override fun search( + loginMember: LoginMember, + targetMemberId: Long, + page: Pageable, + query: String + ): Page { + val target = memberRepository.findById(targetMemberId).orElseThrow() + val availableVisibilities = friendService.availableVisibilities(loginMember, target) + + return scheduleRepository.findByMemberAndContentContainingAndVisibilityIn( + member = target, + content = query, + visibility = availableVisibilities, + pageable = page + ).map { ScheduleSearchResult.of(it) } + } + +} diff --git a/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/service/ScheduleService.kt b/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/service/ScheduleService.kt index 8d9664a9..e5443685 100644 --- a/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/service/ScheduleService.kt +++ b/src/main/kotlin/com/tistory/shanepark/dutypark/schedule/service/ScheduleService.kt @@ -3,7 +3,6 @@ package com.tistory.shanepark.dutypark.schedule.service import com.tistory.shanepark.dutypark.common.domain.dto.CalendarView import com.tistory.shanepark.dutypark.common.exceptions.DutyparkAuthException import com.tistory.shanepark.dutypark.member.domain.entity.Member -import com.tistory.shanepark.dutypark.member.domain.enums.Visibility import com.tistory.shanepark.dutypark.member.repository.MemberRepository import com.tistory.shanepark.dutypark.member.service.FriendService import com.tistory.shanepark.dutypark.schedule.domain.dto.ScheduleDto @@ -44,7 +43,7 @@ class ScheduleService( val start = calendarView.rangeFrom val end = calendarView.rangeEnd - val availableVisibilities = availableVisibilities(loginMember, member) + val availableVisibilities = friendService.availableVisibilities(loginMember, member) val userSchedules = scheduleRepository.findSchedulesOfMonth(member, start, end, visibilities = availableVisibilities) @@ -75,17 +74,6 @@ class ScheduleService( return array } - private fun availableVisibilities(loginMember: LoginMember?, member: Member): Collection { - if (loginMember == null) - return setOf(Visibility.PUBLIC) - if (loginMember.id == member.id) { - return Visibility.values().toList() - } - if (friendService.isFriend(loginMember.id, member.id!!)) { - return setOf(Visibility.PUBLIC, Visibility.FRIENDS) - } - return setOf(Visibility.PUBLIC) - } fun createSchedule(loginMember: LoginMember, scheduleUpdateDto: ScheduleUpdateDto): Schedule { val scheduleMember = memberRepository.findById(scheduleUpdateDto.memberId).orElseThrow() diff --git a/src/main/resources/static/css/base.css b/src/main/resources/static/css/base.css index 4677654a..c38cb2a0 100644 --- a/src/main/resources/static/css/base.css +++ b/src/main/resources/static/css/base.css @@ -710,3 +710,11 @@ input[readonly], textarea[readonly] { background-color: #f8f9fa; cursor: not-allowed; } + +.search-bar input { + border-radius: 10px 0 0 10px; +} + +.search-bar .btn { + border-radius: 0 10px 10px 0; +} diff --git a/src/main/resources/templates/duty/duty.html b/src/main/resources/templates/duty/duty.html index c587ae7a..de086dd7 100644 --- a/src/main/resources/templates/duty/duty.html +++ b/src/main/resources/templates/duty/duty.html @@ -25,9 +25,9 @@
-
+
- +
@@ -36,16 +36,22 @@

- +

-
-
- - +
+
@@ -248,6 +254,54 @@
+ +