Skip to content

Commit

Permalink
검색에 평점순 정렬 추가 + 오류 수정 (#261)
Browse files Browse the repository at this point in the history
  • Loading branch information
asp345 authored Aug 26, 2024
1 parent 6cd9025 commit 2cdd224
Show file tree
Hide file tree
Showing 16 changed files with 191 additions and 2 deletions.
4 changes: 3 additions & 1 deletion api/src/main/kotlin/handler/LectureSearchHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ data class SearchQueryLegacy(
val page: Int = 0,
val offset: Long = page * 20L,
val limit: Int = 20,
val sortCriteria: String? = null,
) {
fun toSearchDto(): SearchDto {
return SearchDto(
Expand All @@ -63,7 +64,8 @@ data class SearchQueryLegacy(
timesToExclude = timesToExclude,
page = page,
offset = offset,
limit = limit
limit = limit,
sortBy = sortCriteria
)
}

Expand Down
33 changes: 33 additions & 0 deletions api/src/main/kotlin/handler/TagHandler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.wafflestudio.snu4t.handler

import com.wafflestudio.snu4t.common.enum.Semester
import com.wafflestudio.snu4t.common.exception.InvalidPathParameterException
import com.wafflestudio.snu4t.middleware.SnuttRestApiDefaultMiddleware
import com.wafflestudio.snu4t.tag.TagListService
import com.wafflestudio.snu4t.tag.data.TagListResponse
import com.wafflestudio.snu4t.tag.data.TagListUpdateTimeResponse
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.server.ServerRequest
import org.springframework.web.reactive.function.server.ServerResponse

@Component
class TagHandler(
private val tagService: TagListService,
snuttRestApiDefaultMiddleware: SnuttRestApiDefaultMiddleware
) : ServiceHandler(snuttRestApiDefaultMiddleware) {
suspend fun getTagList(req: ServerRequest): ServerResponse = handle(req) {
val year = req.pathVariable("year").toInt()
val semester =
Semester.getOfValue(req.pathVariable("semester").toInt()) ?: throw InvalidPathParameterException("semester")
val tagList = tagService.getTagList(year, semester)
TagListResponse(tagList)
}

suspend fun getTagListUpdateTime(req: ServerRequest): ServerResponse = handle(req) {
val year = req.pathVariable("year").toInt()
val semester =
Semester.getOfValue(req.pathVariable("semester").toInt()) ?: throw InvalidPathParameterException("semester")
val tagList = tagService.getTagList(year, semester)
TagListUpdateTimeResponse(tagList.updatedAt.toEpochMilli())
}
}
12 changes: 12 additions & 0 deletions api/src/main/kotlin/router/MainRouter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.wafflestudio.snu4t.handler.FriendTableHandler
import com.wafflestudio.snu4t.handler.LectureSearchHandler
import com.wafflestudio.snu4t.handler.NotificationHandler
import com.wafflestudio.snu4t.handler.PopupHandler
import com.wafflestudio.snu4t.handler.TagHandler
import com.wafflestudio.snu4t.handler.TimetableHandler
import com.wafflestudio.snu4t.handler.TimetableLectureHandler
import com.wafflestudio.snu4t.handler.TimetableThemeHandler
Expand All @@ -27,6 +28,7 @@ import com.wafflestudio.snu4t.router.docs.FriendDocs
import com.wafflestudio.snu4t.router.docs.LectureSearchDocs
import com.wafflestudio.snu4t.router.docs.NotificationDocs
import com.wafflestudio.snu4t.router.docs.PopupDocs
import com.wafflestudio.snu4t.router.docs.TagDocs
import com.wafflestudio.snu4t.router.docs.ThemeDocs
import com.wafflestudio.snu4t.router.docs.TimetableDocs
import com.wafflestudio.snu4t.router.docs.UserDocs
Expand Down Expand Up @@ -57,6 +59,7 @@ class MainRouter(
private val adminHandler: AdminHandler,
private val buildingHandler: BuildingHandler,
private val evHandler: EvHandler,
private val tagHandler: TagHandler
) {
@Bean
fun healthCheck() = coRouter {
Expand Down Expand Up @@ -239,6 +242,15 @@ class MainRouter(
}
}

@Bean
@TagDocs
fun tagRoute() = v1CoRouter {
"/tags".nest {
GET("/{year}/{semester}", tagHandler::getTagList)
GET("/{year}/{semester}/update_time", tagHandler::getTagListUpdateTime)
}
}

@Bean
@EvDocs
fun evRouter() = v1CoRouter {
Expand Down
39 changes: 39 additions & 0 deletions api/src/main/kotlin/router/docs/TagDocs.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.wafflestudio.snu4t.router.docs

import com.wafflestudio.snu4t.tag.data.TagListResponse
import com.wafflestudio.snu4t.tag.data.TagListUpdateTimeResponse
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.enums.ParameterIn
import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import org.springdoc.core.annotations.RouterOperation
import org.springdoc.core.annotations.RouterOperations

@RouterOperations(
RouterOperation(
path = "/v1/tags/{year}/{semester}",
operation = Operation(
operationId = "getTagList",
parameters = [
Parameter(`in` = ParameterIn.PATH, name = "year", required = true),
Parameter(`in` = ParameterIn.PATH, name = "semester", required = true)
],
responses = [ApiResponse(responseCode = "200", content = [Content(schema = Schema(implementation = TagListResponse::class))])]
),
),
RouterOperation(
path = "/v1/tags/{year}/{semester}/update_time",
operation = Operation(
operationId = "getTagListUpdateTime",
parameters = [
Parameter(`in` = ParameterIn.PATH, name = "year", required = true),
Parameter(`in` = ParameterIn.PATH, name = "semester", required = true)
],
responses = [ApiResponse(responseCode = "200", content = [Content(schema = Schema(implementation = TagListUpdateTimeResponse::class))])]
)
),

)
annotation class TagDocs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.wafflestudio.snu4t.sugangsnu.job.sync.service

import com.wafflestudio.snu4t.bookmark.repository.BookmarkRepository
import com.wafflestudio.snu4t.common.cache.Cache
import com.wafflestudio.snu4t.common.enum.SortCriteria
import com.wafflestudio.snu4t.coursebook.data.Coursebook
import com.wafflestudio.snu4t.coursebook.repository.CoursebookRepository
import com.wafflestudio.snu4t.lecturebuildings.data.Campus
Expand Down Expand Up @@ -129,6 +130,7 @@ class SugangSnuSyncServiceImpl(
credit = parsedTag.credit.sorted().map { "${it}학점" },
instructor = parsedTag.instructor.filterNotNull().filter { it.isNotBlank() }.sorted(),
category = parsedTag.category.filterNotNull().filter { it.isNotBlank() }.sorted(),
sortCriteria = SortCriteria.values().map { it.fullName }.filterNot { it == "기본값" }.sorted()
)
}
val tagList = tagListRepository.findByYearAndSemester(coursebook.year, coursebook.semester)
Expand Down
33 changes: 33 additions & 0 deletions core/src/main/kotlin/common/enum/SortCriteria.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.wafflestudio.snu4t.common.enum

import com.fasterxml.jackson.annotation.JsonValue
import com.wafflestudio.snu4t.common.extension.asc
import com.wafflestudio.snu4t.common.extension.desc
import com.wafflestudio.snu4t.lectures.data.EvInfo
import com.wafflestudio.snu4t.lectures.data.Lecture
import org.springframework.data.domain.Sort
import org.springframework.data.mapping.div

enum class SortCriteria(
val value: Int,
@JsonValue
val fullName: String
) {
ID(1, "기본값"),
RATING_DESC(2, "평점 높은 순"),
RATING_ASC(3, "평점 낮은 순"),
COUNT_DESC(4, "강의평 많은 순"),
COUNT_ASC(5, "강의평 적은 순");

companion object {
private val nameMap = values().associateBy { it.fullName }
fun getOfName(sortCriteriaName: String?): SortCriteria? = nameMap[sortCriteriaName]
fun getSort(sortCriteria: SortCriteria?): Sort = when (sortCriteria) {
RATING_DESC -> (Lecture::evInfo / EvInfo::avgRating).desc()
RATING_ASC -> (Lecture::evInfo / EvInfo::avgRating).asc()
COUNT_DESC -> (Lecture::evInfo / EvInfo::count).desc()
COUNT_ASC -> (Lecture::evInfo / EvInfo::count).asc()
else -> Sort.unsorted()
}
}
}
1 change: 1 addition & 0 deletions core/src/main/kotlin/common/exception/ErrorType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ enum class ErrorType(
USER_NOT_FOUND_BY_NICKNAME(HttpStatus.NOT_FOUND, 40405, "해당 닉네임의 유저를 찾을 수 없습니다.", "해당 닉네임의 유저를 찾을 수 없습니다."),
THEME_NOT_FOUND(HttpStatus.NOT_FOUND, 40406, "테마를 찾을 수 없습니다.", "테마를 찾을 수 없습니다."),
EV_DATA_NOT_FOUND(HttpStatus.NOT_FOUND, 40407, "강의평 데이터를 찾을 수 없습니다.", "강의평 데이터를 찾을 수 없습니다."),
TAG_LIST_NOT_FOUND(HttpStatus.NOT_FOUND, 40408, "태그 리스트를 찾을 수 없습니다.", "태그 리스트를 찾을 수 없습니다."),

DUPLICATE_VACANCY_NOTIFICATION(HttpStatus.CONFLICT, 40900, "빈자리 알림 중복"),
DUPLICATE_EMAIL(HttpStatus.CONFLICT, 40901, "이미 사용 중인 이메일입니다.", "이미 사용 중인 이메일입니다."),
Expand Down
1 change: 1 addition & 0 deletions core/src/main/kotlin/common/exception/Snu4tException.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ object FriendNotFoundException : Snu4tException(ErrorType.FRIEND_NOT_FOUND)
object UserNotFoundByNicknameException : Snu4tException(ErrorType.USER_NOT_FOUND_BY_NICKNAME)
object ThemeNotFoundException : Snu4tException(ErrorType.THEME_NOT_FOUND)
object EvDataNotFoundException : Snu4tException(ErrorType.EV_DATA_NOT_FOUND)
object TagListNotFoundException : Snu4tException(ErrorType.TAG_LIST_NOT_FOUND)

object DuplicateVacancyNotificationException : Snu4tException(ErrorType.DUPLICATE_VACANCY_NOTIFICATION)
class DuplicateEmailException(socialProvider: SocialProvider) : Snu4tException(ErrorType.DUPLICATE_EMAIL, detail = mapOf("socialProvider" to socialProvider))
Expand Down
7 changes: 7 additions & 0 deletions core/src/main/kotlin/lectures/data/EvInfo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.wafflestudio.snu4t.lectures.data

data class EvInfo(
val evId: String? = null,
val avgRating: Double?,
val count: Int?,
)
1 change: 1 addition & 0 deletions core/src/main/kotlin/lectures/data/Lecture.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ data class Lecture(
var courseTitle: String,
var registrationCount: Int = 0,
var wasFull: Boolean = false,
val evInfo: EvInfo? = null,
) {
infix fun equalsMetadata(other: Lecture): Boolean {
return this === other ||
Expand Down
1 change: 1 addition & 0 deletions core/src/main/kotlin/lectures/dto/SearchDto.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ data class SearchDto(
val page: Int = 0,
val offset: Long = page * 20L,
val limit: Int = 20,
val sortBy: String?,
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.wafflestudio.snu4t.lectures.repository

import com.wafflestudio.snu4t.common.enum.SortCriteria
import com.wafflestudio.snu4t.common.extension.isEqualTo
import com.wafflestudio.snu4t.lectures.data.ClassPlaceAndTime
import com.wafflestudio.snu4t.lectures.data.Lecture
Expand Down Expand Up @@ -87,7 +88,9 @@ class LectureCustomRepositoryImpl(
}.toTypedArray()
),
)
).skip(searchCondition.offset).limit(searchCondition.limit)
)
.with(SortCriteria.getSort(SortCriteria.getOfName(searchCondition.sortBy)))
.skip(searchCondition.offset).limit(searchCondition.limit)
).asFlow()

private fun makeSearchCriteriaFromQuery(query: String): Criteria =
Expand Down
19 changes: 19 additions & 0 deletions core/src/main/kotlin/tag/TagListService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.wafflestudio.snu4t.tag

import com.wafflestudio.snu4t.common.enum.Semester
import com.wafflestudio.snu4t.common.exception.TagListNotFoundException
import com.wafflestudio.snu4t.tag.data.TagList
import com.wafflestudio.snu4t.tag.repository.TagListRepository
import org.springframework.stereotype.Service

interface TagListService {
suspend fun getTagList(year: Int, semester: Semester): TagList
}

@Service
class TagServiceImpl(
private val tagListRepository: TagListRepository
) : TagListService {
override suspend fun getTagList(year: Int, semester: Semester): TagList =
tagListRepository.findByYearAndSemester(year, semester) ?: throw TagListNotFoundException
}
1 change: 1 addition & 0 deletions core/src/main/kotlin/tag/data/TagList.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ data class TagCollection(
val credit: List<String>,
val instructor: List<String>,
val category: List<String>,
val sortCriteria: List<String> = listOf()
)
26 changes: 26 additions & 0 deletions core/src/main/kotlin/tag/data/TagListResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.wafflestudio.snu4t.tag.data

import com.fasterxml.jackson.annotation.JsonProperty

data class TagListResponse(
val classification: List<String>,
val department: List<String>,
@JsonProperty("academic_year")
val academicYear: List<String>,
val credit: List<String>,
val instructor: List<String>,
val category: List<String>,
val sortCriteria: List<String>,
@JsonProperty("updated_at")
val updatedAt: Long,
)
fun TagListResponse(tagList: TagList) = TagListResponse(
classification = tagList.tagCollection.classification,
department = tagList.tagCollection.department,
academicYear = tagList.tagCollection.academicYear,
credit = tagList.tagCollection.credit,
instructor = tagList.tagCollection.instructor,
category = tagList.tagCollection.category,
sortCriteria = tagList.tagCollection.sortCriteria,
updatedAt = tagList.updatedAt.toEpochMilli()
)
8 changes: 8 additions & 0 deletions core/src/main/kotlin/tag/data/TagListUpdateTimeResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.wafflestudio.snu4t.tag.data

import com.fasterxml.jackson.annotation.JsonProperty

data class TagListUpdateTimeResponse(
@JsonProperty("updated_at")
val updatedAt: Long
)

0 comments on commit 2cdd224

Please sign in to comment.