From 1a8ffcc33ba7fc11c63fe2928c5cffb6003beae4 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:46:03 +0900 Subject: [PATCH 001/223] =?UTF-8?q?rename:=20Diet=20Domain=20=EB=94=94?= =?UTF-8?q?=EB=A0=89=ED=86=A0=EB=A6=AC=EB=A1=9C=20=EA=B5=AC=EB=B6=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/v1/DietController.kt | 4 +-- .../api/controller/v1/ScheduleController.kt | 34 +++++++++++++++++++ .../com/dmforu/domain/{ => diet}/Diet.kt | 2 +- .../dmforu/domain/{ => diet}/DietReader.kt | 2 +- .../dmforu/domain/{ => diet}/DietService.kt | 2 +- 5 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt rename dmforu-domain/src/main/kotlin/com/dmforu/domain/{ => diet}/Diet.kt (76%) rename dmforu-domain/src/main/kotlin/com/dmforu/domain/{ => diet}/DietReader.kt (93%) rename dmforu-domain/src/main/kotlin/com/dmforu/domain/{ => diet}/DietService.kt (85%) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt index 88c8c5e..be284ae 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt @@ -1,7 +1,7 @@ package com.dmforu.api.controller.v1 -import com.dmforu.domain.Diet -import com.dmforu.domain.DietService +import com.dmforu.domain.diet.Diet +import com.dmforu.domain.diet.DietService import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.ResponseEntity diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt new file mode 100644 index 0000000..31b1c6b --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt @@ -0,0 +1,34 @@ +package com.dmforu.api.controller.v1 + +import com.dmforu.domain.schedule.Schedule +import com.dmforu.domain.schedule.ScheduleService +import com.dmforu.domain.schedule.legacy.YearSchedule +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController + +@Tag(name = "학사일정") +@RestController +class ScheduleController( + private val scheduleService: ScheduleService +) { + @GetMapping("/api/v1/dmu/schedule") + @Operation( + summary = "[구버전] 학사일정 API", + description = "현재년도를 기준으로 작년부터 내년 2월까지의 학사일정을 출력한다." + ) + fun readScheduleOld(): ResponseEntity> { + return ResponseEntity.ok().body(scheduleService.readOld()) + } + + @GetMapping("/api/v1/schedule") + @Operation( + summary = "학사일정 API", + description = "현재년도를 기준으로 작년부터 내년 2월까지의 학사일정을 출력한다." + ) + fun raedSchedule(): ResponseEntity> { + return ResponseEntity.ok().body(scheduleService.read()) + } +} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/Diet.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt similarity index 76% rename from dmforu-domain/src/main/kotlin/com/dmforu/domain/Diet.kt rename to dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt index 2da85d9..36985ab 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/Diet.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt @@ -1,4 +1,4 @@ -package com.dmforu.domain +package com.dmforu.domain.diet import java.time.LocalDate diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/DietReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt similarity index 93% rename from dmforu-domain/src/main/kotlin/com/dmforu/domain/DietReader.kt rename to dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt index 72c57b6..5146545 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/DietReader.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt @@ -1,4 +1,4 @@ -package com.dmforu.domain +package com.dmforu.domain.diet import org.springframework.stereotype.Component import java.time.LocalDate diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/DietService.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietService.kt similarity index 85% rename from dmforu-domain/src/main/kotlin/com/dmforu/domain/DietService.kt rename to dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietService.kt index 653c9d1..2960a42 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/DietService.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietService.kt @@ -1,4 +1,4 @@ -package com.dmforu.domain +package com.dmforu.domain.diet import org.springframework.stereotype.Service From 1e4673e242e53812968cf0f4dfe50c2e2d4b7488 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:50:15 +0900 Subject: [PATCH 002/223] =?UTF-8?q?feat:=20LegacySchedule,=20Schedule=20Da?= =?UTF-8?q?ta=20Class=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/schedule/Schedule.kt | 24 +++++++++++++++++++ .../domain/schedule/legacy/LegacySchedule.kt | 14 +++++++++++ .../domain/schedule/legacy/MonthSchedule.kt | 6 +++++ .../domain/schedule/legacy/YearSchedule.kt | 6 +++++ 4 files changed, 50 insertions(+) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt new file mode 100644 index 0000000..ae37b02 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt @@ -0,0 +1,24 @@ +package com.dmforu.domain.schedule + +data class Schedule( + val date: String, + val content: String +) { + constructor(dateArray: Array, content: String) : this( + dateArray.joinToString( + prefix = "[", + separator = ", ", + postfix = "]" + ), content + ) + + data class Month( + val month: Int, + val monthSchedule: List + ) + + data class Year( + val year: Int, + val yearSchedule: List + ) +} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt new file mode 100644 index 0000000..5b02d93 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt @@ -0,0 +1,14 @@ +package com.dmforu.domain.schedule.legacy; + +data class LegacySchedule( + val date: String, + val content: String +) { + constructor(dateArray: Array, content: String) : this( + dateArray.joinToString( + prefix = "[", + separator = ", ", + postfix = "]" + ), content + ) +} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt new file mode 100644 index 0000000..56c88bb --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt @@ -0,0 +1,6 @@ +package com.dmforu.domain.schedule.legacy; + +data class MonthSchedule ( + val month: Int, + val scheduleEntries: List +) \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt new file mode 100644 index 0000000..77c834b --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt @@ -0,0 +1,6 @@ +package com.dmforu.domain.schedule.legacy; + +data class YearSchedule ( + val year: Int, + val yearSchedule: List +) \ No newline at end of file From de2d7bba9f2f606feda540ed9a8a64ea4cea1438 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:51:09 +0900 Subject: [PATCH 003/223] =?UTF-8?q?feat:=20Schedule=20=EB=B6=88=EB=9F=AC?= =?UTF-8?q?=EC=98=A4=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 크롤링 모듈이 없기 때문에 임시로 값을 반환하도록 작성 --- .../dmforu/domain/schedule/ScheduleReader.kt | 26 +++++++++++++++++++ .../dmforu/domain/schedule/ScheduleService.kt | 18 +++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt new file mode 100644 index 0000000..18c0a19 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt @@ -0,0 +1,26 @@ +package com.dmforu.domain.schedule + +import com.dmforu.domain.schedule.legacy.LegacySchedule +import com.dmforu.domain.schedule.legacy.MonthSchedule +import com.dmforu.domain.schedule.legacy.YearSchedule +import org.springframework.stereotype.Component + +@Component +class ScheduleReader { + @Deprecated("Use read() instead.", ReplaceWith("read()")) + fun readOld(): List { + val legacySchedule = LegacySchedule(arrayOf("01.01(일)", "01.01(일)"), "신정") + val monthSchedule = MonthSchedule(1, listOf(legacySchedule)) + val yearSchedule = YearSchedule(2024, listOf(monthSchedule)) + + return listOf(yearSchedule) + } + + fun read(): List { + val schedule = Schedule(arrayOf("01.01(일)", "01.01(일)"), "신정") + val monthSchedule = Schedule.Month(1, listOf(schedule)) + val yearSchedule = Schedule.Year(2024, listOf(monthSchedule)) + + return listOf(yearSchedule) + } +} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt new file mode 100644 index 0000000..7e22c77 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt @@ -0,0 +1,18 @@ +package com.dmforu.domain.schedule + +import com.dmforu.domain.schedule.legacy.YearSchedule +import org.springframework.stereotype.Service + +@Service +class ScheduleService( + private val scheduleReader: ScheduleReader +) { + @Deprecated("Use read() instead.", ReplaceWith("read()")) + fun readOld(): List { + return scheduleReader.readOld() + } + + fun read(): List { + return scheduleReader.read() + } +} \ No newline at end of file From 05ac6cff4f763ffc1ceff51b9f741a7abb75f4cb Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 27 Sep 2024 23:59:15 +0900 Subject: [PATCH 004/223] =?UTF-8?q?chore:=20crawling=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-api/build.gradle.kts | 1 + dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt | 3 ++- dmforu-crawling/build.gradle.kts | 6 ++++++ settings.gradle.kts | 6 +++--- 4 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 dmforu-crawling/build.gradle.kts diff --git a/dmforu-api/build.gradle.kts b/dmforu-api/build.gradle.kts index 1d6124f..622ebd1 100644 --- a/dmforu-api/build.gradle.kts +++ b/dmforu-api/build.gradle.kts @@ -8,6 +8,7 @@ tasks.getByName("jar") { dependencies { implementation(project(":dmforu-domain")) + implementation(project(":dmforu-crawling")) runtimeOnly(project(":dmforu-storage:db-mysql")) implementation("org.springframework.boot:spring-boot-starter-web") diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt index b260e05..aa5f059 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt @@ -5,8 +5,9 @@ import org.springframework.boot.runApplication @SpringBootApplication( scanBasePackages = [ + "com.dmforu.api", "com.dmforu.domain", - "com.dmforu.api" + "com.dmforu.crawling" ] ) class ApiApplication diff --git a/dmforu-crawling/build.gradle.kts b/dmforu-crawling/build.gradle.kts new file mode 100644 index 0000000..f08941b --- /dev/null +++ b/dmforu-crawling/build.gradle.kts @@ -0,0 +1,6 @@ +dependencies { + implementation(project(":dmforu-domain")) + implementation("org.jsoup:jsoup:1.17.2") + + compileOnly("org.springframework:spring-context") +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index f154230..3c9fac6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,9 +1,9 @@ rootProject.name = "DMU-BackEnd" include( - "dmforu-api", - "dmforu-domain", - "dmforu-storage:db-mysql" + "dmforu-api", + "dmforu-domain", + "dmforu-crawling" ) pluginManagement { From 55346a6895ce4c5eb4ad682a587d21bcf1645628 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 00:02:14 +0900 Subject: [PATCH 005/223] =?UTF-8?q?feat:=20Jsoup=EC=9D=84=20=ED=99=9C?= =?UTF-8?q?=EC=9A=A9=ED=95=9C=20=ED=81=AC=EB=A1=A4=EB=A7=81=20static=20Met?= =?UTF-8?q?hod=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/crawling/WebPageLoader.kt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt new file mode 100644 index 0000000..2ab1349 --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt @@ -0,0 +1,27 @@ +package com.dmforu.crawling + +import org.jsoup.Jsoup +import org.jsoup.nodes.Document +import java.io.IOException + +object WebPageLoader { + /** + * Jsoup을 사용하여 URL에 해당하는 웹 페이지의 HTML을 가져온다. + * + * @param url HTML을 가져오고자 하는 웹 페이지의 URL + * @return URL에 접속하면 볼 수 있는 HTML을 반환 + */ + @JvmStatic + fun getHTML(url: String?): Document { + if (url.isNullOrBlank()) { + throw IllegalArgumentException("URL이 비어있거나 잘못되었습니다.") + } + + return try { + Jsoup.connect(url).get() + } catch (e: IOException) { + // TODO: 페이지 로딩 실패나 네트워크 오류인 경우 핸들링을 해야함 + throw IllegalArgumentException() + } + } +} \ No newline at end of file From 12506eebf4d23bbd788784f36764411c67d31bfc Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 00:02:52 +0900 Subject: [PATCH 006/223] =?UTF-8?q?feat:=20=EA=B5=AC=ED=98=84=EC=B2=B4?= =?UTF-8?q?=EB=A5=BC=20=EC=88=A8=EA=B8=B0=EA=B8=B0=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?Parser=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/dmforu/crawling/Parser.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/Parser.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/Parser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/Parser.kt new file mode 100644 index 0000000..5b24f7c --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/Parser.kt @@ -0,0 +1,5 @@ +package com.dmforu.crawling + +interface Parser { + fun parse(): List +} \ No newline at end of file From 0f0c4fe540d658780c9c7720f0376e274b105f29 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 00:03:28 +0900 Subject: [PATCH 007/223] =?UTF-8?q?feat:=20=EC=8B=9D=EB=8B=A8=EC=9D=84=20?= =?UTF-8?q?=EB=B6=88=EB=9F=AC=EC=98=A4=EB=8A=94=20Parser=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/crawling/diet/DietParser.kt | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietParser.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietParser.kt new file mode 100644 index 0000000..4e24e55 --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietParser.kt @@ -0,0 +1,55 @@ +package com.dmforu.crawling.diet + +import com.dmforu.crawling.Parser +import com.dmforu.crawling.WebPageLoader +import com.dmforu.domain.diet.Diet +import org.jsoup.nodes.Element +import org.springframework.stereotype.Service +import java.time.LocalDate +import java.time.format.DateTimeFormatter + +@Service +class DietParser : Parser { + override fun parse(): List { + val document = WebPageLoader.getHTML(DMU_DIET_URL) + val rows = document.select(TABLE_SELECTOR) + + return rows.mapNotNull { row -> parseDiet(row) } + } + + private fun parseDiet(row: Element): Diet? { + val columns = row.select(DATA_SELECTOR) + + // 요일 출력 + val day = columns[0].text() + + // 짝수 컬럼에는 day 정보가 있는 위치에 "교직원식당"의 정보가 기입됨으로 넘겨야 함 + if (PASS_COLUMN == day) { + return null + } + + val parsedDate = LocalDate.parse(day.substring(0, 10), DATE_FORMATTER) + + // 코리안 푸드 메뉴가 4번째 컬럼에 작성된다. + // 만일 식단의 작성 방법이 변경된다면 해당 로직 또한 변경의 필요성이 존재한다. + val menuColumn = columns.getOrNull(3) + val menuElement = menuColumn?.text() + + // 메뉴가 공백이 아니면 메뉴를 분리하여 리스트로 변환 + val menus = menuElement?.takeIf { it.isNotBlank() } + ?.split(MENU_SEPARATOR) + ?.map { it.trim() } + ?: emptyList() + + return Diet(parsedDate, menus) + } + + companion object { + private val DATE_FORMATTER: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") + private const val DMU_DIET_URL = "https://www.dongyang.ac.kr/diet/dongyang/1/view.do" + private const val TABLE_SELECTOR = "div.table_1 table tbody tr" + private const val DATA_SELECTOR = "th, td" + private const val MENU_SEPARATOR = ", " + private const val PASS_COLUMN = "교직원식당" + } +} From 6efaf716c469f2f7b6b5ecdc0ccea637a9976d99 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 00:03:49 +0900 Subject: [PATCH 008/223] =?UTF-8?q?feat:=20=ED=95=99=EC=82=AC=EC=9D=BC?= =?UTF-8?q?=EC=A0=95=EC=9D=84=20=EB=B6=88=EB=9F=AC=EC=98=A4=EB=8A=94=20Par?= =?UTF-8?q?ser=20=EA=B5=AC=ED=98=84=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawling/schedule/ScheduleParser.kt | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleParser.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleParser.kt new file mode 100644 index 0000000..7d51e7b --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleParser.kt @@ -0,0 +1,89 @@ +package com.dmforu.crawling.schedule + +import com.dmforu.crawling.Parser +import com.dmforu.crawling.WebPageLoader +import com.dmforu.domain.schedule.Schedule +import org.jsoup.nodes.Element +import org.springframework.stereotype.Service +import java.time.LocalDate +import java.time.ZoneId + +@Service +class ScheduleParser : Parser { + override fun parse(): List { + val currentYear = LocalDate.now(ZoneId.of(TIME_ZONE)).year + + // 작년부터 내년의 일정을 가져온다. + return (currentYear - 1..currentYear + 1).map { year -> + val yearSchedule = fetchYearSchedule(year) + Schedule.Year(year, yearSchedule) + } + } + + private fun fetchYearSchedule(year: Int): List { + val document = WebPageLoader.getHTML(DMU_SCHEDULE_URL + year) + val monthTables = document.select(YEAR_SCHEDULE_SELECTOR) + + return monthTables.mapNotNull { monthTable -> + val monthSchedule = fetchMonthSchedule(monthTable) + + // 일정 정보가 업로드 되지 않는 달은 제외한다. (다음 년도 3월 이후의 정보) + if (monthSchedule.monthSchedule.isEmpty()) null else monthSchedule + } + } + + private fun fetchMonthSchedule(monthTable: Element): Schedule.Month { + //

2024.1

p태그에서 "2024.1"을 문자열로 가져온다. + // 이때, 월 정보만 필요하기 때문에 문자열 인덱스 5부터의 정보만을 가져온다. + val monthText = monthTable.select(MONTH_DATE_SELECTOR).first()?.text() + ?: throw IllegalArgumentException("Month text not found in the provided element.") + + val month = extractMonth(monthText) + + val scheduleTable = monthTable.select(MONTH_SCHEDULE_SELECTOR) + val monthSchedule = scheduleTable.map { schedule -> parseSchedule(schedule) } + + return Schedule.Month(month, monthSchedule) + } + + private fun extractMonth(monthText: String): Int { + return monthText.split(MONTH_SEPARATOR).last().toIntOrNull() + ?: throw IllegalArgumentException("Invalid month format: $monthText") + } + + /** + * 다음과 같이 일정을 파싱한다. + * + * 01.01 (월) 신정 + * -> ["01.01 (월)", "01.01 (월)"], "신정" + * + * 01.03 (수) ~ 01.15 (월) 정시모집 원서 접수 + * -> ["01.03 (수)", "01.15 (월)"], "정시모집 원서 접수" + */ + private fun parseSchedule(schedule: Element): Schedule { + val dateText = schedule.select(SCHEDULE_DATE_SELECTOR).text().replace(SPACE_CHAR, EMPTY_CHAR) + val dates = if (dateText.contains(DATE_SEPARATOR)) { + dateText.split(DATE_SEPARATOR).map { it.trim() } + } else { + listOf(dateText, dateText) + } + + val content = schedule.select(SCHEDULE_CONTENT_SELECTOR).text() + + return Schedule(dates.toTypedArray(), content) + } + + companion object { + private const val TIME_ZONE = "Asia/Seoul" + private const val DMU_SCHEDULE_URL = "https://www.dongyang.ac.kr/dongyang/71/subview.do?year=" + private const val YEAR_SCHEDULE_SELECTOR = ".yearSchdulWrap" + private const val MONTH_DATE_SELECTOR = "p" + private const val MONTH_SCHEDULE_SELECTOR = ".scheList li" + private const val MONTH_SEPARATOR = "." + private const val SCHEDULE_DATE_SELECTOR = "dt span" + private const val SCHEDULE_CONTENT_SELECTOR = "dd span" + private const val DATE_SEPARATOR = "~" + private const val EMPTY_CHAR = "" + private const val SPACE_CHAR = " " + } +} From 802ae9608d2f59238f3cb87af3221f083e51f419 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 00:06:26 +0900 Subject: [PATCH 009/223] =?UTF-8?q?chore:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20H2=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-storage/db-mysql/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/dmforu-storage/db-mysql/build.gradle.kts b/dmforu-storage/db-mysql/build.gradle.kts index 63c8d18..767cc0d 100644 --- a/dmforu-storage/db-mysql/build.gradle.kts +++ b/dmforu-storage/db-mysql/build.gradle.kts @@ -8,5 +8,4 @@ dependencies { compileOnly(project(":dmforu-domain")) implementation("org.springframework.boot:spring-boot-starter-data-jpa") runtimeOnly ("com.mysql:mysql-connector-j") - runtimeOnly("com.h2database:h2") } \ No newline at end of file From 52fc989f5948592b0bbe4cae6d6091e11e740c11 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 00:13:53 +0900 Subject: [PATCH 010/223] =?UTF-8?q?chore:=20redis=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-api/build.gradle.kts | 1 + dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt | 3 ++- dmforu-storage/db-redis/build.gradle.kts | 4 ++++ settings.gradle.kts | 4 +++- 4 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 dmforu-storage/db-redis/build.gradle.kts diff --git a/dmforu-api/build.gradle.kts b/dmforu-api/build.gradle.kts index 622ebd1..d774cac 100644 --- a/dmforu-api/build.gradle.kts +++ b/dmforu-api/build.gradle.kts @@ -10,6 +10,7 @@ dependencies { implementation(project(":dmforu-domain")) implementation(project(":dmforu-crawling")) runtimeOnly(project(":dmforu-storage:db-mysql")) + runtimeOnly(project(":dmforu-storage:db-redis")) implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0") diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt index aa5f059..70900fe 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt @@ -7,7 +7,8 @@ import org.springframework.boot.runApplication scanBasePackages = [ "com.dmforu.api", "com.dmforu.domain", - "com.dmforu.crawling" + "com.dmforu.crawling", + "com.dmforu.storage.db.redis" ] ) class ApiApplication diff --git a/dmforu-storage/db-redis/build.gradle.kts b/dmforu-storage/db-redis/build.gradle.kts new file mode 100644 index 0000000..151b3e3 --- /dev/null +++ b/dmforu-storage/db-redis/build.gradle.kts @@ -0,0 +1,4 @@ +dependencies { + compileOnly(project(":dmforu-domain")) + implementation("org.springframework.boot:spring-boot-starter-data-redis") +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 3c9fac6..e97154d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,7 +3,9 @@ rootProject.name = "DMU-BackEnd" include( "dmforu-api", "dmforu-domain", - "dmforu-crawling" + "dmforu-crawling", + "dmforu-storage:db-mysql", + "dmforu-storage:db-redis" ) pluginManagement { From 3917001d2cf7a9261c9f2bc2f4aaed5b476ed3b9 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 00:17:15 +0900 Subject: [PATCH 011/223] =?UTF-8?q?feat:=20Redis=20Config=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/db/redis/config/RedisConfig.kt | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt new file mode 100644 index 0000000..999c056 --- /dev/null +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt @@ -0,0 +1,60 @@ +package com.dmforu.storage.db.redis.config + + +import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.autoconfigure.domain.EntityScan +import org.springframework.cache.CacheManager +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.data.redis.cache.RedisCacheConfiguration +import org.springframework.data.redis.cache.RedisCacheManager +import org.springframework.data.redis.connection.RedisConnectionFactory +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory +import org.springframework.data.redis.core.RedisTemplate +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer +import org.springframework.data.redis.serializer.RedisSerializationContext +import org.springframework.data.redis.serializer.StringRedisSerializer +import java.time.Duration + +@Configuration +@EntityScan(basePackages = ["com.dmforu.storage.db.redis"]) +@EnableRedisRepositories(basePackages = ["com.dmforu.storage.db.redis"]) +internal class RedisConfig( + @Value("\${spring.data.redis.host}") + var host: String, + @Value("\${spring.data.redis.port}") + val port: Int +) { + @Bean + fun redisConnectionFactory(): RedisConnectionFactory { + return LettuceConnectionFactory(host, port) + } + + @Bean + fun redisTemplate(redisConnectionFactory: RedisConnectionFactory): RedisTemplate<*, *> { + return RedisTemplate().apply { + this.connectionFactory = redisConnectionFactory + + this.keySerializer = StringRedisSerializer() + this.hashKeySerializer = StringRedisSerializer() + this.valueSerializer = StringRedisSerializer() + } + } + + @Bean + fun cacheManager(redisConnectionFactory: RedisConnectionFactory): CacheManager { + val configuration = RedisCacheConfiguration.defaultCacheConfig() + .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer())) + .serializeValuesWith( + RedisSerializationContext.SerializationPair.fromSerializer( + GenericJackson2JsonRedisSerializer() + )) // Serialize 관련 설정 + .entryTtl(Duration.ofDays(2)) // 캐시 기본 ttl 2분 설정 + .disableCachingNullValues() // Null 캐싱 제외 + return RedisCacheManager.RedisCacheManagerBuilder + .fromConnectionFactory(redisConnectionFactory) + .cacheDefaults(configuration) + .build() + } +} \ No newline at end of file From 9118dea303c6b1c05c393de9792e01f30f707769 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 00:17:59 +0900 Subject: [PATCH 012/223] =?UTF-8?q?feat:=20Diet=20Entity=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/storage/db/redis/diet/DietEntity.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt new file mode 100644 index 0000000..60d5516 --- /dev/null +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt @@ -0,0 +1,12 @@ +package com.dmforu.storage.db.redis.diet + +import com.dmforu.domain.diet.Diet +import org.springframework.data.annotation.Id +import org.springframework.data.redis.core.RedisHash + +@RedisHash("diet") +internal class DietEntity( + @Id val id: String = "diet", + val diets: List +) + From 49b2af94cb43d3464c4d60f087cdf944c799e85d Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 00:18:54 +0900 Subject: [PATCH 013/223] =?UTF-8?q?feat:=20Redis=20Repository=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=9C=20Diet=20Repository=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/storage/db/redis/diet/DietRedisRepository.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietRedisRepository.kt diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietRedisRepository.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietRedisRepository.kt new file mode 100644 index 0000000..25d6ed2 --- /dev/null +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietRedisRepository.kt @@ -0,0 +1,5 @@ +package com.dmforu.storage.db.redis.diet + +import org.springframework.data.repository.CrudRepository + +internal interface DietRedisRepository : CrudRepository {} \ No newline at end of file From a8979697bd13fee0dfdc5754abb30f101d510178 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 01:07:50 +0900 Subject: [PATCH 014/223] =?UTF-8?q?feat:=20Diet=20Repository=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/com/dmforu/domain/diet/DietRepository.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietRepository.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietRepository.kt new file mode 100644 index 0000000..fdfef54 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietRepository.kt @@ -0,0 +1,6 @@ +package com.dmforu.domain.diet + +interface DietRepository { + fun write(diets: List) + fun read(): List? +} \ No newline at end of file From fd640d2f113dac1fcfffa233dd83cbbd90b4a8ce Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 01:08:21 +0900 Subject: [PATCH 015/223] =?UTF-8?q?feat:=20Diet=20Repository=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../db/redis/diet/DietEntityRepository.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt new file mode 100644 index 0000000..c5d9800 --- /dev/null +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt @@ -0,0 +1,21 @@ +package com.dmforu.storage.db.redis.diet + +import com.dmforu.domain.diet.Diet +import com.dmforu.domain.diet.DietRepository +import org.springframework.stereotype.Repository + +@Repository +internal class DietEntityRepository( + private val dietRedisRepository: DietRedisRepository +) : DietRepository { + override fun write(diets: List) { + // 기존 데이터를 모두 삭제 + dietRedisRepository.deleteAll() + // 새로운 데이터를 저장 + dietRedisRepository.save(DietEntity(diets = diets)) + } + + override fun read(): List? { + return dietRedisRepository.findAll().firstOrNull()?.diets + } +} \ No newline at end of file From 0fac32bbcf85eee087020066ce3f7745710d9186 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 01:09:49 +0900 Subject: [PATCH 016/223] =?UTF-8?q?feat:=20Diet=20write,=20read=20?= =?UTF-8?q?=EB=B9=84=EC=A7=80=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/domain/diet/DietReader.kt | 14 ++++---------- .../kotlin/com/dmforu/domain/diet/DietService.kt | 7 ++++++- .../kotlin/com/dmforu/domain/diet/DietWriter.kt | 12 ++++++++++++ 3 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietWriter.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt index 5146545..32c58f7 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt @@ -1,18 +1,12 @@ package com.dmforu.domain.diet import org.springframework.stereotype.Component -import java.time.LocalDate @Component -class DietReader { - // TODO: Diet 크롤링 정보를 가져와야 함 +class DietReader( + private val dietRepository: DietRepository, +) { fun read(): List { - val list = mutableListOf() - - list.add(Diet(LocalDate.now(), listOf("메뉴1", "메뉴2"))) - list.add(Diet(LocalDate.now(), listOf("메뉴1", "메뉴2"))) - list.add(Diet(LocalDate.now(), listOf("메뉴1", "메뉴2"))) - - return list + return dietRepository.read().orEmpty() } } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietService.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietService.kt index 2960a42..7f45825 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietService.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietService.kt @@ -4,9 +4,14 @@ import org.springframework.stereotype.Service @Service class DietService( - private val dietReader: DietReader + private val dietReader: DietReader, + private val dietWriter: DietWriter ) { fun read(): List { return dietReader.read() } + + fun write(diets: List) { + return dietWriter.write(diets) + } } diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietWriter.kt new file mode 100644 index 0000000..34b7853 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietWriter.kt @@ -0,0 +1,12 @@ +package com.dmforu.domain.diet + +import org.springframework.stereotype.Component + +@Component +class DietWriter( + private val dietRepository: DietRepository +) { + fun write(diets: List) { + dietRepository.write(diets) + } +} \ No newline at end of file From db2a9165b4d0740fc1ff84bc5c3d3dd07b0eca5f Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 01:10:48 +0900 Subject: [PATCH 017/223] =?UTF-8?q?.gitignore=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=ED=8F=AC=ED=95=A8=EB=90=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8F=84=EB=A1=9D=20=EC=9E=84=EC=8B=9C=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index cc04fe6..73465a0 100644 --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,5 @@ out/ .kotlin ### Configuration Settings ### -**/application.yml \ No newline at end of file +**/application.yml +**/*.yml \ No newline at end of file From f8782b19d1d19cbc310ea5aea98ab5f4c7493b51 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 28 Sep 2024 01:31:16 +0900 Subject: [PATCH 018/223] =?UTF-8?q?feat:=20Batch=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-batch/build.gradle.kts | 19 +++++++++++++++++++ .../com/dmforu/batch/BatchApplication.kt | 19 +++++++++++++++++++ .../com/dmforu/batch/BatchApplicationTests.kt | 13 +++++++++++++ settings.gradle.kts | 1 + 4 files changed, 52 insertions(+) create mode 100644 dmforu-batch/build.gradle.kts create mode 100644 dmforu-batch/src/main/kotlin/com/dmforu/batch/BatchApplication.kt create mode 100644 dmforu-batch/src/test/kotlin/com/dmforu/batch/BatchApplicationTests.kt diff --git a/dmforu-batch/build.gradle.kts b/dmforu-batch/build.gradle.kts new file mode 100644 index 0000000..d89c59e --- /dev/null +++ b/dmforu-batch/build.gradle.kts @@ -0,0 +1,19 @@ +tasks.getByName("bootJar") { + enabled = true +} + +tasks.getByName("jar") { + enabled = false +} + +dependencies { + implementation(project(":dmforu-domain")) + implementation(project(":dmforu-crawling")) + runtimeOnly(project(":dmforu-storage:db-mysql")) + runtimeOnly(project(":dmforu-storage:db-redis")) + + implementation("org.springframework.boot:spring-boot-starter-batch") + // Jackson Library + implementation("com.fasterxml.jackson.core:jackson-databind") + implementation("com.fasterxml.jackson.module:jackson-module-kotlin") +} \ No newline at end of file diff --git a/dmforu-batch/src/main/kotlin/com/dmforu/batch/BatchApplication.kt b/dmforu-batch/src/main/kotlin/com/dmforu/batch/BatchApplication.kt new file mode 100644 index 0000000..c341140 --- /dev/null +++ b/dmforu-batch/src/main/kotlin/com/dmforu/batch/BatchApplication.kt @@ -0,0 +1,19 @@ +package com.dmforu.batch + +import com.dmforu.crawling.diet.DietParser +import com.dmforu.domain.diet.DietRepository +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication + +@SpringBootApplication( + scanBasePackages = [ + "com.dmforu.domain", + "com.dmforu.crawling", + "com.dmforu.storage.db.redis" + ] +) +class BatchApplication + +fun main(args: Array) { + runApplication(*args) +} diff --git a/dmforu-batch/src/test/kotlin/com/dmforu/batch/BatchApplicationTests.kt b/dmforu-batch/src/test/kotlin/com/dmforu/batch/BatchApplicationTests.kt new file mode 100644 index 0000000..a39ddfb --- /dev/null +++ b/dmforu-batch/src/test/kotlin/com/dmforu/batch/BatchApplicationTests.kt @@ -0,0 +1,13 @@ +package com.dmforu.batch + +import org.junit.jupiter.api.Test +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest +class BatchApplicationTests { + + @Test + fun contextLoads() { + } + +} diff --git a/settings.gradle.kts b/settings.gradle.kts index e97154d..589c39b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,6 +2,7 @@ rootProject.name = "DMU-BackEnd" include( "dmforu-api", + "dmforu-batch", "dmforu-domain", "dmforu-crawling", "dmforu-storage:db-mysql", From f4fe5c3e604dc5622c63c1466bcd8ffdf5c48b48 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 29 Sep 2024 00:10:09 +0900 Subject: [PATCH 019/223] =?UTF-8?q?feat:=20Schedule=20Repository=20?= =?UTF-8?q?=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/schedule/ScheduleRepository.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleRepository.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleRepository.kt new file mode 100644 index 0000000..f5bd3f1 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleRepository.kt @@ -0,0 +1,10 @@ +package com.dmforu.domain.schedule + +import com.dmforu.domain.schedule.legacy.YearSchedule + +interface ScheduleRepository { + fun writeOld(schedules: List) + fun write(schedules: List) + fun readOld(): List? + fun read(): List? +} \ No newline at end of file From 8ee4e0e5274bcde7f5f4b510d2a3b127160686d4 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 29 Sep 2024 00:11:54 +0900 Subject: [PATCH 020/223] =?UTF-8?q?feat:=20Redis=20Config=20=EC=A7=81?= =?UTF-8?q?=EB=A0=AC=ED=99=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - StringRedisSerializer() -> GenericJackson2JsonRedisSerializer() - Redis에 저장하는 타입이 String이 아니고 객체이기 때문에 직렬화 메서드 변경 --- .../kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt index 999c056..a550ca6 100644 --- a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt @@ -37,8 +37,9 @@ internal class RedisConfig( this.connectionFactory = redisConnectionFactory this.keySerializer = StringRedisSerializer() + this.valueSerializer = GenericJackson2JsonRedisSerializer() this.hashKeySerializer = StringRedisSerializer() - this.valueSerializer = StringRedisSerializer() + this.hashValueSerializer = GenericJackson2JsonRedisSerializer() } } From 8d4dd944a7e26c55ec8fde05d8cd2159859bc7c5 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 29 Sep 2024 00:14:04 +0900 Subject: [PATCH 021/223] =?UTF-8?q?feat:=20Schedule=20Entity=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/db/redis/schedule/OldScheduleEntity.kt | 11 +++++++++++ .../storage/db/redis/schedule/ScheduleEntity.kt | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt create mode 100644 dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt new file mode 100644 index 0000000..70401e6 --- /dev/null +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt @@ -0,0 +1,11 @@ +package com.dmforu.storage.db.redis.schedule + +import com.dmforu.domain.schedule.legacy.YearSchedule +import org.springframework.data.annotation.Id +import org.springframework.data.redis.core.RedisHash + +@RedisHash("legacySchedule") +internal class OldScheduleEntity( + @Id val id: String = "legacySchedule", + val schedules: List +) \ No newline at end of file diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt new file mode 100644 index 0000000..518ba8a --- /dev/null +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt @@ -0,0 +1,11 @@ +package com.dmforu.storage.db.redis.schedule + +import com.dmforu.domain.schedule.Schedule +import org.springframework.data.annotation.Id +import org.springframework.data.redis.core.RedisHash + +@RedisHash("schedule") +internal class ScheduleEntity( + @Id val id: String = "schedule", + val schedules: List +) \ No newline at end of file From 242c6b5f062ad223d20787bc3aa2d703e35852d1 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 29 Sep 2024 00:14:11 +0900 Subject: [PATCH 022/223] =?UTF-8?q?feat:=20Schedule=20Repository=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../schedule/ScheduleEntityRepository.kt | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt new file mode 100644 index 0000000..bd35442 --- /dev/null +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt @@ -0,0 +1,50 @@ +package com.dmforu.storage.db.redis.schedule + +import com.dmforu.domain.schedule.Schedule +import com.dmforu.domain.schedule.ScheduleRepository +import com.dmforu.domain.schedule.legacy.YearSchedule +import org.springframework.data.redis.core.RedisTemplate +import org.springframework.stereotype.Repository + +@Repository +internal class ScheduleEntityRepository ( + private val redisTemplate: RedisTemplate +) : ScheduleRepository{ + + private companion object { + const val SCHEDULE_KEY = "schedule" + const val OLD_SCHEDULE_KEY = "oldSchedule" + } + + override fun writeOld(schedules: List) { + writeEntity(OLD_SCHEDULE_KEY, OldScheduleEntity(schedules = schedules)) + } + + override fun write(schedules: List) { + writeEntity(SCHEDULE_KEY, ScheduleEntity(schedules = schedules)) + } + + override fun readOld(): List? { + return readEntity(OLD_SCHEDULE_KEY)?.schedules + } + + override fun read(): List? { + return readEntity(SCHEDULE_KEY)?.schedules + } + + /** + * 공통된 엔티티 쓰기 메서드 + */ + private fun writeEntity(key: String, entity: T) { + redisTemplate.delete(key) + redisTemplate.opsForValue().set(key, entity) + } + + /** + * 공통된 엔티티 읽기 메서드 + */ + @Suppress("UNCHECKED_CAST") + private fun readEntity(key: String): T? { + return redisTemplate.opsForValue().get(key) as? T + } +} \ No newline at end of file From 49c552bb349d47e051e7a4bd9150b4d6b42baa54 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 29 Sep 2024 00:16:48 +0900 Subject: [PATCH 023/223] =?UTF-8?q?fix:=20=EC=A7=81=EB=A0=AC=ED=99=94?= =?UTF-8?q?=EA=B0=80=20=EC=A7=84=ED=96=89=EB=90=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8D=98=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기본 생성자가 없어 Jackson 메서드가 정상적으로 수행되지 않았음 - 이를 위해 private 기본 생성자를 추가 작성함 --- .../main/kotlin/com/dmforu/domain/schedule/Schedule.kt | 10 ++++++++-- .../dmforu/domain/schedule/legacy/LegacySchedule.kt | 2 ++ .../com/dmforu/domain/schedule/legacy/MonthSchedule.kt | 6 ++++-- .../com/dmforu/domain/schedule/legacy/YearSchedule.kt | 4 +++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt index ae37b02..db2589f 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt @@ -4,6 +4,8 @@ data class Schedule( val date: String, val content: String ) { + private constructor() : this("", "") + constructor(dateArray: Array, content: String) : this( dateArray.joinToString( prefix = "[", @@ -15,10 +17,14 @@ data class Schedule( data class Month( val month: Int, val monthSchedule: List - ) + ) { + private constructor() : this(0, emptyList()) + } data class Year( val year: Int, val yearSchedule: List - ) + ) { + private constructor() : this(0, emptyList()) + } } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt index 5b02d93..65b1f59 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt @@ -4,6 +4,8 @@ data class LegacySchedule( val date: String, val content: String ) { + private constructor() : this("", "") + constructor(dateArray: Array, content: String) : this( dateArray.joinToString( prefix = "[", diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt index 56c88bb..98c813f 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt @@ -1,6 +1,8 @@ package com.dmforu.domain.schedule.legacy; -data class MonthSchedule ( +data class MonthSchedule( val month: Int, val scheduleEntries: List -) \ No newline at end of file +) { + private constructor() : this(0, emptyList()) +} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt index 77c834b..bfe433d 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt @@ -3,4 +3,6 @@ package com.dmforu.domain.schedule.legacy; data class YearSchedule ( val year: Int, val yearSchedule: List -) \ No newline at end of file +) { + private constructor() : this(0, emptyList()) +} \ No newline at end of file From 75553a6417d5b4cb990fedd597589a5f67bc8e06 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 29 Sep 2024 00:17:25 +0900 Subject: [PATCH 024/223] =?UTF-8?q?feat:=20Schedule=20write,=20read=20?= =?UTF-8?q?=EB=B9=84=EC=A7=80=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/domain/schedule/ScheduleReader.kt | 18 +++++------------- .../dmforu/domain/schedule/ScheduleService.kt | 12 +++++++++++- .../dmforu/domain/schedule/ScheduleWriter.kt | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt index 18c0a19..1dfcbb0 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt @@ -1,26 +1,18 @@ package com.dmforu.domain.schedule -import com.dmforu.domain.schedule.legacy.LegacySchedule -import com.dmforu.domain.schedule.legacy.MonthSchedule import com.dmforu.domain.schedule.legacy.YearSchedule import org.springframework.stereotype.Component @Component -class ScheduleReader { +class ScheduleReader( + private val scheduleRepository: ScheduleRepository +) { @Deprecated("Use read() instead.", ReplaceWith("read()")) fun readOld(): List { - val legacySchedule = LegacySchedule(arrayOf("01.01(일)", "01.01(일)"), "신정") - val monthSchedule = MonthSchedule(1, listOf(legacySchedule)) - val yearSchedule = YearSchedule(2024, listOf(monthSchedule)) - - return listOf(yearSchedule) + return scheduleRepository.readOld().orEmpty() } fun read(): List { - val schedule = Schedule(arrayOf("01.01(일)", "01.01(일)"), "신정") - val monthSchedule = Schedule.Month(1, listOf(schedule)) - val yearSchedule = Schedule.Year(2024, listOf(monthSchedule)) - - return listOf(yearSchedule) + return scheduleRepository.read().orEmpty() } } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt index 7e22c77..8ce3cd0 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt @@ -5,7 +5,8 @@ import org.springframework.stereotype.Service @Service class ScheduleService( - private val scheduleReader: ScheduleReader + private val scheduleReader: ScheduleReader, + private val scheduleWriter: ScheduleWriter ) { @Deprecated("Use read() instead.", ReplaceWith("read()")) fun readOld(): List { @@ -15,4 +16,13 @@ class ScheduleService( fun read(): List { return scheduleReader.read() } + + @Deprecated("Use write() instead.", ReplaceWith("write()")) + fun writeOld(schedules: List) { + return scheduleWriter.writeOld(schedules) + } + + fun write(schedules: List) { + return scheduleWriter.write(schedules) + } } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt new file mode 100644 index 0000000..7a67516 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt @@ -0,0 +1,18 @@ +package com.dmforu.domain.schedule + +import com.dmforu.domain.schedule.legacy.YearSchedule +import org.springframework.stereotype.Component + +@Component +class ScheduleWriter( + private val scheduleRepository: ScheduleRepository +) { + @Deprecated("Use write() instead.", ReplaceWith("write()")) + fun writeOld(schedules: List) { + scheduleRepository.writeOld(schedules) + } + + fun write(schedules: List) { + scheduleRepository.write(schedules) + } +} \ No newline at end of file From 5503bf7f6d6a3bb70039d369773cb25b6a242529 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 29 Sep 2024 02:16:32 +0900 Subject: [PATCH 025/223] =?UTF-8?q?fix:=20=EC=97=AD=EC=A7=81=EB=A0=AC?= =?UTF-8?q?=ED=99=94=EA=B0=80=20=EA=B0=80=EB=8A=A5=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EA=B8=B0=EB=B3=B8=20=EC=83=9D=EC=84=B1=EC=9E=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt | 4 +++- .../com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt index 70401e6..4233bde 100644 --- a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt @@ -8,4 +8,6 @@ import org.springframework.data.redis.core.RedisHash internal class OldScheduleEntity( @Id val id: String = "legacySchedule", val schedules: List -) \ No newline at end of file +) { + private constructor() : this("", emptyList()) +} \ No newline at end of file diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt index 518ba8a..7158353 100644 --- a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt @@ -8,4 +8,6 @@ import org.springframework.data.redis.core.RedisHash internal class ScheduleEntity( @Id val id: String = "schedule", val schedules: List -) \ No newline at end of file +) { + private constructor(): this("", emptyList()) +} \ No newline at end of file From 2031654d8ac94b8280ad04afdfea783ba2d5a4f2 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 29 Sep 2024 02:18:29 +0900 Subject: [PATCH 026/223] =?UTF-8?q?feat:=20=ED=95=99=EC=82=AC=EC=9D=BC?= =?UTF-8?q?=EC=A0=95=EC=9D=84=20=EB=B6=88=EB=9F=AC=EC=98=A4=EB=8A=94=20Par?= =?UTF-8?q?ser=20=EA=B5=AC=ED=98=84=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20(Legacy=20=EB=B2=84=EC=A0=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawling/schedule/LegacyScheduleParser.kt | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/LegacyScheduleParser.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/LegacyScheduleParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/LegacyScheduleParser.kt new file mode 100644 index 0000000..3900f48 --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/LegacyScheduleParser.kt @@ -0,0 +1,79 @@ +package com.dmforu.crawling.schedule + +import com.dmforu.crawling.Parser +import com.dmforu.crawling.WebPageLoader +import com.dmforu.domain.schedule.legacy.LegacySchedule +import com.dmforu.domain.schedule.legacy.MonthSchedule +import com.dmforu.domain.schedule.legacy.YearSchedule +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import org.springframework.stereotype.Service +import java.time.LocalDate +import java.time.ZoneId + +@Service +class LegacyScheduleParser : Parser { + override fun parse(): List { + val yearSchedules: MutableList = ArrayList() + + val currentYear: Int = LocalDate.now(ZoneId.of(TIME_ZONE)).getYear() + + // 작년부터 내년의 일정을 가져온다. + for (year in currentYear - 1..currentYear + 1) { + val schedules: List = fetchYearSchedule(year) + yearSchedules.add(YearSchedule(year, schedules)) + } + + return yearSchedules + } + + private fun fetchYearSchedule(year: Int): List { + val yearSchedules: MutableList = ArrayList() + val document: Document = WebPageLoader.getHTML(DMU_SCHEDULER_URL + year) + + val monthTables = document.select(".yearSchdulWrap") + + for (monthTable in monthTables) { + val monthSchedule: MonthSchedule = fetchMonthSchedule(monthTable) + + // 일정 정보가 업로드 되지 않는 달은 제외한다. (다음 년도 3월 이후의 정보) + if (monthSchedule.scheduleEntries.isEmpty()) break + + yearSchedules.add(monthSchedule) + } + + return yearSchedules + } + + private fun fetchMonthSchedule(monthTable: Element): MonthSchedule { + val monthEntries: MutableList = ArrayList() + + //

2024.1

p태그에서 "2024.1"을 문자열로 가져온다. + // 이때, 월 정보만 필요하기 때문에 문자열 인덱스 5부터의 정보만을 가져온다. + val monthText = monthTable.select("p").first().text().substring(5) + val month = monthText.toInt() + + val scheduleList = monthTable.select(".scheList li") + for (schedule in scheduleList) { + val scheduleEntry: LegacySchedule = parseSchedule(schedule) + monthEntries.add(scheduleEntry) + } + + return MonthSchedule(month, monthEntries) + } + + private fun parseSchedule(schedule: Element): LegacySchedule { + val dateText = schedule.select("dt span").text().replace(" ".toRegex(), "") + val dates = if (dateText.contains("~")) dateText.split("~".toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray() else arrayOf(dateText, dateText) + + val content = schedule.select("dd span").text() + + return LegacySchedule(dates, content) + } + + companion object { + private const val TIME_ZONE = "Asia/Seoul" + private const val DMU_SCHEDULER_URL = "https://www.dongyang.ac.kr/dongyang/71/subview.do?year=" + } +} \ No newline at end of file From 75a6cd75d239403c0ce851912eca8c270bb3866f Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 1 Oct 2024 03:31:51 +0900 Subject: [PATCH 027/223] =?UTF-8?q?chore:=20Data=20Class=EB=A5=BC=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=ED=95=98=EB=A0=A4=EB=8B=A4=EA=B0=80=20?= =?UTF-8?q?=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/schedule/legacy/LegacySchedule.kt | 2 +- .../kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt | 2 +- .../kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt index 65b1f59..3e48671 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt @@ -1,4 +1,4 @@ -package com.dmforu.domain.schedule.legacy; +package com.dmforu.domain.schedule.legacy data class LegacySchedule( val date: String, diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt index 98c813f..e302196 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt @@ -1,4 +1,4 @@ -package com.dmforu.domain.schedule.legacy; +package com.dmforu.domain.schedule.legacy data class MonthSchedule( val month: Int, diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt index bfe433d..f1ccb79 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt @@ -1,6 +1,6 @@ -package com.dmforu.domain.schedule.legacy; +package com.dmforu.domain.schedule.legacy -data class YearSchedule ( +data class YearSchedule( val year: Int, val yearSchedule: List ) { From 78e92e4fa618674c5b70b50ceddcedf9ced583d7 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 1 Oct 2024 03:32:26 +0900 Subject: [PATCH 028/223] =?UTF-8?q?chore:=20Jsoup=20=EB=B2=84=EC=A0=84?= =?UTF-8?q?=EC=9D=84=20=EC=99=B8=EB=B6=80=EC=97=90=EC=84=9C=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-crawling/build.gradle.kts | 5 +++-- gradle.properties | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dmforu-crawling/build.gradle.kts b/dmforu-crawling/build.gradle.kts index f08941b..bb77787 100644 --- a/dmforu-crawling/build.gradle.kts +++ b/dmforu-crawling/build.gradle.kts @@ -1,6 +1,7 @@ +val jsoupVersion: String by project + dependencies { - implementation(project(":dmforu-domain")) - implementation("org.jsoup:jsoup:1.17.2") + implementation("org.jsoup:jsoup:${jsoupVersion}") compileOnly("org.springframework:spring-context") } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index cd2b8db..35ea512 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,6 +6,7 @@ projectGroup=com.dmforu ### Project dependency versions ### kotlinVersion=1.9.25 +jsoupVersion=1.17.2 ### Spring dependency versions ### springBootVersion=3.3.4 From 87f369c5ba0c81d88e436544e87d6f4949d8e44e Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 1 Oct 2024 03:34:48 +0900 Subject: [PATCH 029/223] =?UTF-8?q?fix:=20crawling=EC=97=90=20domain=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=EC=A0=9D=ED=8A=B8=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=EC=9D=B4=20=EB=B9=A0=EC=A0=B8=EC=9E=88=EB=8D=98=20?= =?UTF-8?q?=EB=B6=80=EB=B6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-crawling/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/dmforu-crawling/build.gradle.kts b/dmforu-crawling/build.gradle.kts index bb77787..e9e82a3 100644 --- a/dmforu-crawling/build.gradle.kts +++ b/dmforu-crawling/build.gradle.kts @@ -1,6 +1,7 @@ val jsoupVersion: String by project dependencies { + implementation(project(":dmforu-domain")) implementation("org.jsoup:jsoup:${jsoupVersion}") compileOnly("org.springframework:spring-context") From 2af3a59f87024e223fb90fb07b09f67aeffc5d72 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 1 Oct 2024 04:06:50 +0900 Subject: [PATCH 030/223] =?UTF-8?q?refactor:=20redisTemplate=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - set() 메서드를 통해서 자동으로 덮어쓰기가 진행됨 --- .../storage/db/redis/schedule/ScheduleEntityRepository.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt index bd35442..dd689ff 100644 --- a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt @@ -7,9 +7,9 @@ import org.springframework.data.redis.core.RedisTemplate import org.springframework.stereotype.Repository @Repository -internal class ScheduleEntityRepository ( +internal class ScheduleEntityRepository( private val redisTemplate: RedisTemplate -) : ScheduleRepository{ +) : ScheduleRepository { private companion object { const val SCHEDULE_KEY = "schedule" @@ -36,7 +36,6 @@ internal class ScheduleEntityRepository ( * 공통된 엔티티 쓰기 메서드 */ private fun writeEntity(key: String, entity: T) { - redisTemplate.delete(key) redisTemplate.opsForValue().set(key, entity) } From 46da80a00fd8d249955fdb14499546f4eb374f5e Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 1 Oct 2024 04:07:56 +0900 Subject: [PATCH 031/223] =?UTF-8?q?feat:=20Redis=EC=97=90=20Schedule?= =?UTF-8?q?=EC=9D=84=20=EC=B6=94=EA=B0=80=ED=95=98=EB=8A=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../schedule/ScheduleCrawlingService.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleCrawlingService.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleCrawlingService.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleCrawlingService.kt new file mode 100644 index 0000000..88903f9 --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleCrawlingService.kt @@ -0,0 +1,22 @@ +package com.dmforu.crawling.schedule + +import com.dmforu.domain.schedule.ScheduleService + +class ScheduleCrawlingService( + private val scheduleParser: ScheduleParser, + private val oldScheduleParser: LegacyScheduleParser, + private val scheduleService: ScheduleService +) { + fun refreshAllSchedules() { + rewriteScheduleToRedis() + rewriteOldScheduleToRedis() + } + + private fun rewriteScheduleToRedis() { + scheduleService.write(scheduleParser.parse()) + } + + private fun rewriteOldScheduleToRedis() { + scheduleService.writeOld(oldScheduleParser.parse()) + } +} \ No newline at end of file From 40e49cecb09005abc8a5547ea19bfd245734bf45 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 1 Oct 2024 04:29:09 +0900 Subject: [PATCH 032/223] =?UTF-8?q?refactor:=20RedisRepository=EC=97=90?= =?UTF-8?q?=EC=84=9C=20RedisTemplate=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RedisRepository와 다르게 덮어쓰기가 가능하며, - 트랜잭션을 지원하기 때문에 변경 --- .../db/redis/diet/DietEntityRepository.kt | 29 +++++++++++++++---- .../db/redis/diet/DietRedisRepository.kt | 5 ---- 2 files changed, 23 insertions(+), 11 deletions(-) delete mode 100644 dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietRedisRepository.kt diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt index c5d9800..b3cf2a3 100644 --- a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt @@ -2,20 +2,37 @@ package com.dmforu.storage.db.redis.diet import com.dmforu.domain.diet.Diet import com.dmforu.domain.diet.DietRepository +import org.springframework.data.redis.core.RedisTemplate import org.springframework.stereotype.Repository @Repository internal class DietEntityRepository( - private val dietRedisRepository: DietRedisRepository + private val redisTemplate: RedisTemplate ) : DietRepository { + private companion object { + const val DIET_KEY = "diet" + } + override fun write(diets: List) { - // 기존 데이터를 모두 삭제 - dietRedisRepository.deleteAll() - // 새로운 데이터를 저장 - dietRedisRepository.save(DietEntity(diets = diets)) + writeEntity(DIET_KEY, DietEntity(diets = diets)) } override fun read(): List? { - return dietRedisRepository.findAll().firstOrNull()?.diets + return readEntity(DIET_KEY)?.diets + } + + /** + * 공통된 엔티티 쓰기 메서드 + */ + private fun writeEntity(key: String, entity: T) { + redisTemplate.opsForValue().set(key, entity) + } + + /** + * 공통된 엔티티 읽기 메서드 + */ + @Suppress("UNCHECKED_CAST") + private fun readEntity(key: String): T? { + return redisTemplate.opsForValue().get(key) as? T } } \ No newline at end of file diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietRedisRepository.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietRedisRepository.kt deleted file mode 100644 index 25d6ed2..0000000 --- a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietRedisRepository.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.dmforu.storage.db.redis.diet - -import org.springframework.data.repository.CrudRepository - -internal interface DietRedisRepository : CrudRepository {} \ No newline at end of file From d5657c35d00ed011f775e4ad629d83579053b60a Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 1 Oct 2024 04:30:07 +0900 Subject: [PATCH 033/223] =?UTF-8?q?feat:=20Redis=EC=97=90=20Diet=EB=A5=BC?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/crawling/diet/DietCrawlingService.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietCrawlingService.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietCrawlingService.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietCrawlingService.kt new file mode 100644 index 0000000..8e27d82 --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietCrawlingService.kt @@ -0,0 +1,12 @@ +package com.dmforu.crawling.diet + +import com.dmforu.domain.diet.DietService + +class DietCrawlingService( + private val dietParser: DietParser, + private val dietService: DietService +) { + fun rewriteToRedis() { + dietService.write(dietParser.parse()) + } +} \ No newline at end of file From 73f91cbac260ed021c5a72ceeef6aab6f787c4c5 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:31:03 +0900 Subject: [PATCH 034/223] =?UTF-8?q?refactor:=20Legacy=20Schedule=EC=9D=84?= =?UTF-8?q?=20=EB=8F=84=EB=A9=94=EC=9D=B8=EC=97=90=EC=84=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=20=ED=9B=84,=20API=20DTO=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=B3=80=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 과거 Schedule과 현재 Schedule의 차이점은 이름밖에 없기 때문에, DTO에서 변환하도록 수정 --- .../api/controller/v1/ScheduleController.kt | 7 +- .../controller/v1/response/LegacySchedule.kt | 59 ++++++++++++++ .../crawling/schedule/LegacyScheduleParser.kt | 79 ------------------- .../schedule/ScheduleCrawlingService.kt | 12 +-- .../dmforu/domain/schedule/ScheduleReader.kt | 6 -- .../domain/schedule/ScheduleRepository.kt | 4 - .../dmforu/domain/schedule/ScheduleService.kt | 11 --- .../dmforu/domain/schedule/ScheduleWriter.kt | 6 -- .../domain/schedule/legacy/LegacySchedule.kt | 16 ---- .../domain/schedule/legacy/MonthSchedule.kt | 8 -- .../domain/schedule/legacy/YearSchedule.kt | 8 -- .../db/redis/schedule/OldScheduleEntity.kt | 13 --- .../schedule/ScheduleEntityRepository.kt | 8 -- 13 files changed, 64 insertions(+), 173 deletions(-) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/response/LegacySchedule.kt delete mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/LegacyScheduleParser.kt delete mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt delete mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt delete mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt delete mode 100644 dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt index 31b1c6b..8c0eaef 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt @@ -1,8 +1,8 @@ package com.dmforu.api.controller.v1 +import com.dmforu.api.controller.v1.response.LegacySchedule import com.dmforu.domain.schedule.Schedule import com.dmforu.domain.schedule.ScheduleService -import com.dmforu.domain.schedule.legacy.YearSchedule import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.ResponseEntity @@ -19,8 +19,9 @@ class ScheduleController( summary = "[구버전] 학사일정 API", description = "현재년도를 기준으로 작년부터 내년 2월까지의 학사일정을 출력한다." ) - fun readScheduleOld(): ResponseEntity> { - return ResponseEntity.ok().body(scheduleService.readOld()) + fun readScheduleOld(): ResponseEntity> { + val schedules = LegacySchedule.fromScheduleYears(scheduleService.read()) + return ResponseEntity.ok().body(schedules) } @GetMapping("/api/v1/schedule") diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/response/LegacySchedule.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/response/LegacySchedule.kt new file mode 100644 index 0000000..cad44d9 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/response/LegacySchedule.kt @@ -0,0 +1,59 @@ +package com.dmforu.api.controller.v1.response + +import com.dmforu.domain.schedule.Schedule + +data class LegacySchedule( + val date: String, + val content: String +) { + private constructor() : this("", "") + + private constructor(dateArray: Array, content: String) : this( + dateArray.joinToString( + prefix = "[", + separator = ", ", + postfix = "]" + ), content + ) + + data class MonthSchedule( + val month: Int, + val scheduleEntries: List + ) { + private constructor() : this(0, emptyList()) + } + + data class YearSchedule( + val year: Int, + val yearSchedule: List + ) { + private constructor() : this(0, emptyList()) + } + + companion object { + fun fromScheduleYears(scheduleYears: List): List { + return scheduleYears.map { it.toYearSchedule() } + } + + private fun Schedule.Year.toYearSchedule(): YearSchedule { + return YearSchedule( + year = this.year, + yearSchedule = this.yearSchedule.map { it.toMonthSchedule() } + ) + } + + private fun Schedule.Month.toMonthSchedule(): MonthSchedule { + return MonthSchedule( + month = this.month, + scheduleEntries = this.monthSchedule.map { it.toLegacySchedule() } + ) + } + + private fun Schedule.toLegacySchedule(): LegacySchedule { + return LegacySchedule( + date = this.date, + content = this.content + ) + } + } +} \ No newline at end of file diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/LegacyScheduleParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/LegacyScheduleParser.kt deleted file mode 100644 index 3900f48..0000000 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/LegacyScheduleParser.kt +++ /dev/null @@ -1,79 +0,0 @@ -package com.dmforu.crawling.schedule - -import com.dmforu.crawling.Parser -import com.dmforu.crawling.WebPageLoader -import com.dmforu.domain.schedule.legacy.LegacySchedule -import com.dmforu.domain.schedule.legacy.MonthSchedule -import com.dmforu.domain.schedule.legacy.YearSchedule -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import org.springframework.stereotype.Service -import java.time.LocalDate -import java.time.ZoneId - -@Service -class LegacyScheduleParser : Parser { - override fun parse(): List { - val yearSchedules: MutableList = ArrayList() - - val currentYear: Int = LocalDate.now(ZoneId.of(TIME_ZONE)).getYear() - - // 작년부터 내년의 일정을 가져온다. - for (year in currentYear - 1..currentYear + 1) { - val schedules: List = fetchYearSchedule(year) - yearSchedules.add(YearSchedule(year, schedules)) - } - - return yearSchedules - } - - private fun fetchYearSchedule(year: Int): List { - val yearSchedules: MutableList = ArrayList() - val document: Document = WebPageLoader.getHTML(DMU_SCHEDULER_URL + year) - - val monthTables = document.select(".yearSchdulWrap") - - for (monthTable in monthTables) { - val monthSchedule: MonthSchedule = fetchMonthSchedule(monthTable) - - // 일정 정보가 업로드 되지 않는 달은 제외한다. (다음 년도 3월 이후의 정보) - if (monthSchedule.scheduleEntries.isEmpty()) break - - yearSchedules.add(monthSchedule) - } - - return yearSchedules - } - - private fun fetchMonthSchedule(monthTable: Element): MonthSchedule { - val monthEntries: MutableList = ArrayList() - - //

2024.1

p태그에서 "2024.1"을 문자열로 가져온다. - // 이때, 월 정보만 필요하기 때문에 문자열 인덱스 5부터의 정보만을 가져온다. - val monthText = monthTable.select("p").first().text().substring(5) - val month = monthText.toInt() - - val scheduleList = monthTable.select(".scheList li") - for (schedule in scheduleList) { - val scheduleEntry: LegacySchedule = parseSchedule(schedule) - monthEntries.add(scheduleEntry) - } - - return MonthSchedule(month, monthEntries) - } - - private fun parseSchedule(schedule: Element): LegacySchedule { - val dateText = schedule.select("dt span").text().replace(" ".toRegex(), "") - val dates = if (dateText.contains("~")) dateText.split("~".toRegex()).dropLastWhile { it.isEmpty() } - .toTypedArray() else arrayOf(dateText, dateText) - - val content = schedule.select("dd span").text() - - return LegacySchedule(dates, content) - } - - companion object { - private const val TIME_ZONE = "Asia/Seoul" - private const val DMU_SCHEDULER_URL = "https://www.dongyang.ac.kr/dongyang/71/subview.do?year=" - } -} \ No newline at end of file diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleCrawlingService.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleCrawlingService.kt index 88903f9..59adbc2 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleCrawlingService.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleCrawlingService.kt @@ -4,19 +4,9 @@ import com.dmforu.domain.schedule.ScheduleService class ScheduleCrawlingService( private val scheduleParser: ScheduleParser, - private val oldScheduleParser: LegacyScheduleParser, private val scheduleService: ScheduleService ) { - fun refreshAllSchedules() { - rewriteScheduleToRedis() - rewriteOldScheduleToRedis() - } - - private fun rewriteScheduleToRedis() { + fun rewriteToRedis() { scheduleService.write(scheduleParser.parse()) } - - private fun rewriteOldScheduleToRedis() { - scheduleService.writeOld(oldScheduleParser.parse()) - } } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt index 1dfcbb0..5066df5 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt @@ -1,17 +1,11 @@ package com.dmforu.domain.schedule -import com.dmforu.domain.schedule.legacy.YearSchedule import org.springframework.stereotype.Component @Component class ScheduleReader( private val scheduleRepository: ScheduleRepository ) { - @Deprecated("Use read() instead.", ReplaceWith("read()")) - fun readOld(): List { - return scheduleRepository.readOld().orEmpty() - } - fun read(): List { return scheduleRepository.read().orEmpty() } diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleRepository.kt index f5bd3f1..8dd1643 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleRepository.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleRepository.kt @@ -1,10 +1,6 @@ package com.dmforu.domain.schedule -import com.dmforu.domain.schedule.legacy.YearSchedule - interface ScheduleRepository { - fun writeOld(schedules: List) fun write(schedules: List) - fun readOld(): List? fun read(): List? } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt index 8ce3cd0..1690d00 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt @@ -1,6 +1,5 @@ package com.dmforu.domain.schedule -import com.dmforu.domain.schedule.legacy.YearSchedule import org.springframework.stereotype.Service @Service @@ -8,20 +7,10 @@ class ScheduleService( private val scheduleReader: ScheduleReader, private val scheduleWriter: ScheduleWriter ) { - @Deprecated("Use read() instead.", ReplaceWith("read()")) - fun readOld(): List { - return scheduleReader.readOld() - } - fun read(): List { return scheduleReader.read() } - @Deprecated("Use write() instead.", ReplaceWith("write()")) - fun writeOld(schedules: List) { - return scheduleWriter.writeOld(schedules) - } - fun write(schedules: List) { return scheduleWriter.write(schedules) } diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt index 7a67516..6d07836 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt @@ -1,17 +1,11 @@ package com.dmforu.domain.schedule -import com.dmforu.domain.schedule.legacy.YearSchedule import org.springframework.stereotype.Component @Component class ScheduleWriter( private val scheduleRepository: ScheduleRepository ) { - @Deprecated("Use write() instead.", ReplaceWith("write()")) - fun writeOld(schedules: List) { - scheduleRepository.writeOld(schedules) - } - fun write(schedules: List) { scheduleRepository.write(schedules) } diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt deleted file mode 100644 index 3e48671..0000000 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/LegacySchedule.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.dmforu.domain.schedule.legacy - -data class LegacySchedule( - val date: String, - val content: String -) { - private constructor() : this("", "") - - constructor(dateArray: Array, content: String) : this( - dateArray.joinToString( - prefix = "[", - separator = ", ", - postfix = "]" - ), content - ) -} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt deleted file mode 100644 index e302196..0000000 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/MonthSchedule.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.dmforu.domain.schedule.legacy - -data class MonthSchedule( - val month: Int, - val scheduleEntries: List -) { - private constructor() : this(0, emptyList()) -} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt deleted file mode 100644 index f1ccb79..0000000 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/legacy/YearSchedule.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.dmforu.domain.schedule.legacy - -data class YearSchedule( - val year: Int, - val yearSchedule: List -) { - private constructor() : this(0, emptyList()) -} \ No newline at end of file diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt deleted file mode 100644 index 4233bde..0000000 --- a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/OldScheduleEntity.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.dmforu.storage.db.redis.schedule - -import com.dmforu.domain.schedule.legacy.YearSchedule -import org.springframework.data.annotation.Id -import org.springframework.data.redis.core.RedisHash - -@RedisHash("legacySchedule") -internal class OldScheduleEntity( - @Id val id: String = "legacySchedule", - val schedules: List -) { - private constructor() : this("", emptyList()) -} \ No newline at end of file diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt index dd689ff..3c9b73d 100644 --- a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt +++ b/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt @@ -2,7 +2,6 @@ package com.dmforu.storage.db.redis.schedule import com.dmforu.domain.schedule.Schedule import com.dmforu.domain.schedule.ScheduleRepository -import com.dmforu.domain.schedule.legacy.YearSchedule import org.springframework.data.redis.core.RedisTemplate import org.springframework.stereotype.Repository @@ -13,20 +12,13 @@ internal class ScheduleEntityRepository( private companion object { const val SCHEDULE_KEY = "schedule" - const val OLD_SCHEDULE_KEY = "oldSchedule" } - override fun writeOld(schedules: List) { - writeEntity(OLD_SCHEDULE_KEY, OldScheduleEntity(schedules = schedules)) - } override fun write(schedules: List) { writeEntity(SCHEDULE_KEY, ScheduleEntity(schedules = schedules)) } - override fun readOld(): List? { - return readEntity(OLD_SCHEDULE_KEY)?.schedules - } override fun read(): List? { return readEntity(SCHEDULE_KEY)?.schedules From d8b3018b81962c03feb86ff4ef76c5d9ac312173 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 9 Oct 2024 22:38:19 +0900 Subject: [PATCH 035/223] =?UTF-8?q?feat:=20Notice=20data=20class=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/domain/notice/Notice.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt new file mode 100644 index 0000000..9fc2e13 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt @@ -0,0 +1,23 @@ +package com.dmforu.domain.notice + +import java.time.LocalDate + +data class Notice( + // 공지사항 번호 + val number: Int, + + // 공지사항 종류 + val type: String, + + // 공지사항 날짜 + val date: LocalDate, + + // 공지사항 제목 + val title: String, + + // 공지사항 작성자 + val author: String, + + // 공지사항 URL + val url: String +) \ No newline at end of file From f8571aca658c78861ff5840a23d15f287d063346 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 9 Oct 2024 22:39:54 +0900 Subject: [PATCH 036/223] =?UTF-8?q?feat:=20mysql=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=EC=9D=84=20=EC=B0=BE=EC=9D=84=20=EC=88=98=20=EC=9E=88=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B9=88=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/dmforu/api/ApiApplication.kt | 3 ++- .../dmforu/storage/db/mysql/config/MysqlJpaConfig.kt | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt index 70900fe..1359758 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt @@ -8,7 +8,8 @@ import org.springframework.boot.runApplication "com.dmforu.api", "com.dmforu.domain", "com.dmforu.crawling", - "com.dmforu.storage.db.redis" + "com.dmforu.storage.db.redis", + "com.dmforu.storage.db.mysql" ] ) class ApiApplication diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt new file mode 100644 index 0000000..a9fe438 --- /dev/null +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt @@ -0,0 +1,12 @@ +package com.dmforu.storage.db.mysql.config + +import org.springframework.boot.autoconfigure.domain.EntityScan +import org.springframework.context.annotation.Configuration +import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.transaction.annotation.EnableTransactionManagement + +@Configuration +@EnableTransactionManagement +@EntityScan(basePackages = ["com.dmforu.storage.db.mysql"]) +@EnableJpaRepositories(basePackages = ["com.dmforu.storage.db.mysql"]) +internal class MysqlJpaConfig {} \ No newline at end of file From 131a6be026d8a22209a8a67d2a9dfc6472634da0 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 9 Oct 2024 22:40:37 +0900 Subject: [PATCH 037/223] =?UTF-8?q?feat:=20Notice=20Entity=20=EB=B0=8F=20R?= =?UTF-8?q?epository=20=EA=B5=AC=ED=98=84=EC=B2=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/db/mysql/notice/NoticeEntity.kt | 57 +++++++++++++++++++ .../db/mysql/notice/NoticeEntityRepository.kt | 48 ++++++++++++++++ .../db/mysql/notice/NoticeJpaRepository.kt | 41 +++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt create mode 100644 dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt create mode 100644 dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt new file mode 100644 index 0000000..876d077 --- /dev/null +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt @@ -0,0 +1,57 @@ +package com.dmforu.storage.db.mysql.notice + +import com.dmforu.domain.notice.Notice +import jakarta.persistence.* + +import java.time.LocalDate + +@Table(name = "notice") +@Entity +internal class NoticeEntity( + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long? = null, + + // 공지사항 번호 + val number: Int, + + // 공지사항 타입 + val type: String, + + // 공지사항 날짜 + val date: LocalDate, + + // 공지사항 제목 + val title: String, + + // 공지사항 작성자 + val author: String, + + // 공지사항 URL + val url: String +) { + constructor() : this(null, 0, "", LocalDate.now(), "", "", "") + + companion object { + fun from(notice: Notice): NoticeEntity { + return NoticeEntity( + number = notice.number, + type = notice.type, + date = notice.date, + title = notice.title, + author = notice.author, + url = notice.url + ) + } + } + + fun toNotice(): Notice { + return Notice( + number = this.number, + type = this.type, + date = this.date, + title = this.title, + author = this.author, + url = this.url + ) + } +} diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt new file mode 100644 index 0000000..8d3c358 --- /dev/null +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt @@ -0,0 +1,48 @@ +package com.dmforu.storage.db.mysql.notice + +import com.dmforu.domain.notice.Notice +import com.dmforu.domain.notice.NoticeRepository +import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Sort +import org.springframework.stereotype.Repository + +@Repository +internal class NoticeEntityRepository( + private val noticeJpaRepository: NoticeJpaRepository +) : NoticeRepository { + override fun write(notice: Notice) { + noticeJpaRepository.save(NoticeEntity.from(notice)) + } + + override fun findNoticesBySearchWord( + searchWord: String, + department: String, + page: Int, + size: Int + ): List { + val pageable = pageRequest(page, size) + val noticePage = noticeJpaRepository.findBySearchWordAndDepartment(searchWord, department, pageable) + return noticePage?.mapNotNull { it?.toNotice() }?.toList().orEmpty() + } + + override fun findDepartmentNotices( + department: String, + page: Int, + size: Int + ): List { + val pageable = pageRequest(page, size) + val departmentNoticePage = noticeJpaRepository.findByType(department, pageable) + return departmentNoticePage?.mapNotNull { it?.toNotice() }?.toList().orEmpty() + } + + override fun findUniversityNotices(page: Int, size: Int): List { + val pageable = pageRequest(page, size) + val universityNoticePage = noticeJpaRepository.findByType("대학", pageable) + return universityNoticePage?.mapNotNull { it?.toNotice() }?.toList().orEmpty() + } + + private fun pageRequest(page: Int, size: Int): PageRequest { + val pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "number")) + return pageable + } +} \ No newline at end of file diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt new file mode 100644 index 0000000..2d9f098 --- /dev/null +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt @@ -0,0 +1,41 @@ +package com.dmforu.storage.db.mysql.notice + +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 org.springframework.data.repository.query.Param + +internal interface NoticeJpaRepository : JpaRepository { + /** 원하는 타입의 가장 최신 공지사항 번호를 확인하는 메서드 + * + * @Param type (학과 이름 또는 대학) + * @Return type에 알맞는 최신 공지사항 번호, 만약 공지사항이 존재하지 않다면 Null을 반환한다. + */ + @Query("SELECT MAX(e.number) FROM NoticeEntity e WHERE e.type = :type") + fun findMaxNumberByType(@Param("type") type: String?): Int? + + /** + * 원하는 타입의 공지사항을 페이징네이션하는 메서드 + * + * @param type 공지사항 타입 (학과 이름 또는 대학) + * @param pageable 페이지 단위 + * @return 학과의 공지사항을 페이지 단위에 맞게 반환한다. + */ + fun findByType(type: String, pageable: Pageable): Page? + + /** + * 학과, 대학 공지사항을 검색하는 메서드

+ * 페이지네이션을 적용하여 페이지 단위에 알맞게 반환한다. + * + * @param searchWord 검색할 키워드 + * @param pageable 페이지 단위 + * @return 키워드에 맞는 공지사항 페이지 + */ + @Query( + value = "SELECT * FROM notice WHERE REPLACE(title, ' ', '') LIKE CONCAT('%', REPLACE(?1, ' ', ''), '%') AND type IN (?2, '대학')", + nativeQuery = true + ) + fun findBySearchWordAndDepartment(searchWord: String?, department: String?, pageable: Pageable?): Page? + +} \ No newline at end of file From 29cf9b180bfa53a674a4698a2c1eb72299952913 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 9 Oct 2024 22:41:23 +0900 Subject: [PATCH 038/223] =?UTF-8?q?feat:=20Notice=20Repository=20DIP=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/domain/notice/NoticeRepository.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt new file mode 100644 index 0000000..42ec4e4 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt @@ -0,0 +1,8 @@ +package com.dmforu.domain.notice + +interface NoticeRepository { + fun write(notice: Notice) + fun findNoticesBySearchWord(searchWord: String, department: String, page: Int, size: Int): List + fun findDepartmentNotices(department: String, page: Int, size: Int): List + fun findUniversityNotices(page: Int, size: Int): List +} \ No newline at end of file From bfc4615fed11232859040817463eeec5cce0f57f Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 9 Oct 2024 22:42:46 +0900 Subject: [PATCH 039/223] =?UTF-8?q?feat:=20Notice=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/notice/NoticeReader.kt | 20 +++++++++++++++++++ .../com/dmforu/domain/notice/NoticeWriter.kt | 12 +++++++++++ 2 files changed, 32 insertions(+) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeReader.kt create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeReader.kt new file mode 100644 index 0000000..240892b --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeReader.kt @@ -0,0 +1,20 @@ +package com.dmforu.domain.notice + +import org.springframework.stereotype.Component + +@Component +class NoticeReader( + private val noticeRepository: NoticeRepository +) { + fun searchNotice(searchWord:String, department:String, page:Int, size:Int): List { + return noticeRepository.findNoticesBySearchWord(searchWord, department, page, size) + } + + fun readDepartmentNotice(department: String, page: Int, size: Int): List { + return noticeRepository.findDepartmentNotices(department, page, size) + } + + fun readUniversityNotice(page: Int, size: Int): List { + return noticeRepository.findUniversityNotices(page, size) + } +} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt new file mode 100644 index 0000000..d1f7871 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt @@ -0,0 +1,12 @@ +package com.dmforu.domain.notice + +import org.springframework.stereotype.Component + +@Component +class NoticeWriter ( + private val noticeRepository: NoticeRepository +){ + fun write(notice: Notice) { + noticeRepository.write(notice) + } +} \ No newline at end of file From 4a1559a2f769e98876eb704ea2cec59e72cf01f2 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 9 Oct 2024 22:43:09 +0900 Subject: [PATCH 040/223] =?UTF-8?q?feat:=20Notice=20API=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/v1/NoticeController.kt | 103 ++++++++++++++++++ .../controller/v1/response/NoticeResponse.kt | 33 ++++++ 2 files changed, 136 insertions(+) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/response/NoticeResponse.kt diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt new file mode 100644 index 0000000..d802a77 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt @@ -0,0 +1,103 @@ +package com.dmforu.api.controller.v1 + +import com.dmforu.api.controller.v1.response.NoticeResponse +import com.dmforu.domain.notice.NoticeReader +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@Tag(name = "공지") +@RestController +class NoticeController( + private val noticeReader: NoticeReader +) { + @Operation( + summary = "대학 공지 API", + description = "대학 공지를 출력한다.
Page, Size의 default 값은 1, 20이다." + ) + @GetMapping("/api/v1/notice/university") + fun getUniversityNotice( + @RequestParam(name = "page", defaultValue = "1") page: Int, + @RequestParam(name = "size", defaultValue = "20") size: Int + ): ResponseEntity> { + val universityNotices = noticeReader.readUniversityNotice(page, size).map { NoticeResponse.form(it) } + return ResponseEntity.ok().body(universityNotices) + } + + @Operation( + summary = "학과 공지 API", + description = "해당하는 학과의 공지를 출력한다.
Page, Size의 default 값은 1, 20이다." + ) + @GetMapping("/api/v1/notice/department") + fun getDepartmentNotice( + @RequestParam(name = "department") department: String, + @RequestParam(name = "page", defaultValue = "1") page: Int, + @RequestParam(name = "size", defaultValue = "20") size: Int + ): ResponseEntity> { + val departmentNotices = + noticeReader.readDepartmentNotice(department, page, size).map { NoticeResponse.form(it) } + return ResponseEntity.ok().body(departmentNotices) + } + + @Operation( + summary = "공지 검색 API", + description = "해당하는 학과와 대학 공지에서 해당하는 공지를 출력한다.
Page, Size의 default 값은 1, 20이다." + ) + @GetMapping("/api/v1/notice/{searchWord}") + fun getNoticeByKeyword( + @PathVariable(name = "searchWord") searchWord: String, + @RequestParam(name = "department") department: String, + @RequestParam(name = "page", defaultValue = "1") page: Int, + @RequestParam(name = "size", defaultValue = "20") size: Int + ): ResponseEntity> { + val notices = noticeReader.searchNotice(searchWord, department, page, size).map { NoticeResponse.form(it) } + return ResponseEntity.ok().body(notices) + } + + @Operation( + summary = "[구버전] 대학 공지 API", + description = "대학 공지를 출력한다.
Page, Size의 default 값은 1, 20이다." + ) + @GetMapping("/api/v1/dmu/notice/universityNotice") + fun getOldUniversityNotice( + @RequestParam(name = "page", defaultValue = "1") page: Int, + @RequestParam(name = "size", defaultValue = "20") size: Int + ): ResponseEntity> { + val universityNotices = noticeReader.readUniversityNotice(page, size).map { NoticeResponse.form(it) } + return ResponseEntity.ok().body(universityNotices) + } + + @Operation( + summary = "[구버전] 학과 공지 API", + description = "해당하는 학과의 공지를 출력한다.
Page, Size의 default 값은 1, 20이다." + ) + @GetMapping("/api/v1/dmu/departmentNotice/{department}") + fun getOldDepartmentNotice( + @PathVariable(name = "department") department: String, + @RequestParam(name = "page", defaultValue = "1") page: Int, + @RequestParam(name = "size", defaultValue = "20") size: Int + ): ResponseEntity> { + val departmentNotices = + noticeReader.readDepartmentNotice(department, page, size).map { NoticeResponse.form(it) } + return ResponseEntity.ok().body(departmentNotices) + } + + @Operation( + summary = "[구버전] 공지 검색 API", + description = "해당하는 학과와 대학 공지에서 해당하는 공지를 출력한다.
Page, Size의 default 값은 1, 20이다." + ) + @GetMapping("/api/v1/dmu/notice/{searchWord}") + fun getOldNoticeByKeyword( + @PathVariable(name = "searchWord") searchWord: String, + @RequestParam(name = "department") department: String, + @RequestParam(name = "page", defaultValue = "1") page: Int, + @RequestParam(name = "size", defaultValue = "20") size: Int + ): ResponseEntity> { + val notices = noticeReader.searchNotice(searchWord, department, page, size).map { NoticeResponse.form(it) } + return ResponseEntity.ok().body(notices) + } +} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/response/NoticeResponse.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/response/NoticeResponse.kt new file mode 100644 index 0000000..2acd871 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/response/NoticeResponse.kt @@ -0,0 +1,33 @@ +package com.dmforu.api.controller.v1.response + +import com.dmforu.domain.notice.Notice +import io.swagger.v3.oas.annotations.media.Schema +import java.time.LocalDate + +data class NoticeResponse( + @Schema(description = "날짜", example = "2024-05-09") + val date: LocalDate, + + @Schema(description = "제목", example = "시흥시인재양성재단 24년 상반기 장학생 선발 안내") + val title: String, + + @Schema(description = "작성자", example = "최지예") + val author: String, + + @Schema( + description = "URL", + example = "https://www.dongyang.ac.kr/bbs/dongyang/7/124420/artclView.do?layout=unknown" + ) + val url: String, +) { + companion object { + fun form(notice: Notice): NoticeResponse { + return NoticeResponse( + date = notice.date, + title = notice.title, + author = notice.author, + url = notice.url + ) + } + } +} \ No newline at end of file From 909f43c84716055ffbff53eefcaf0e3828a6ed4e Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 02:33:08 +0900 Subject: [PATCH 041/223] =?UTF-8?q?feat:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=EC=9D=98=20Type=EC=9D=84=20=EC=A0=95=EB=A6=AC?= =?UTF-8?q?=ED=95=9C=20Major=20enum=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/domain/notice/Major.kt | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Major.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Major.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Major.kt new file mode 100644 index 0000000..1557591 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Major.kt @@ -0,0 +1,40 @@ +package com.dmforu.domain.notice + +enum class Major(val type: String, val majorPath: String, val noticePath: String) { + // 기계공학부 + MECHANICAL_ENGINEERING_DEPARTMENT("기계공학과", "dmu_23205", "1707"), + MECHANICAL_DESIGN_ENGINEERING("기계설계공학과", "dmu_23207", "1716"), + + // 로봇자동화공학부 + AUTOMATION_ENGINEERING("자동화공학과", "dmu_23209", "1728"), + ROBOT_ENGINEERING("로봇공학과", "dmu_23211", "1737"), + + // 전기전자통신공학부 + ELECTRICAL_ENGINEERING("전기공학과", "dmu_23212", "1749"), + INFORMATION_ELECTRONIC_ENGINEERING("정보전자공학과", "dmu_23214", "1758"), + SEMICONDUCTOR_ELECTRONIC_ENGINEERING("반도체전자공학과", "dmu_23216", "1767"), + INFORMATION_COMMUNICATION_ENGINEERING("정보통신공학과", "dmu_23218", "1776"), + FIRE_SAFETY_MANAGEMENT("소방안전관리과", "dmu_23268", "2503"), + + // 컴퓨터공학부 + COMPUTER_INFORMATION_ENGINEERING("컴퓨터정보공학과", "dmu_23220", "1788"), + COMPUTER_SOFTWARE_ENGINEERING("컴퓨터소프트웨어공학과", "dmu_23222", "1797"), + AI_SOFTWARE_ENGINEERING("인공지능소프트웨어학과", "dmu_23259", "1806"), + + // 생활환경공학부 + BIO_CHEMICAL_ENGINEERING("생명화학공학과", "dmu_23245", "1818"), + BIO_CONVERGENCE_ENGINEERING("바이오융합공학과", "dmu_23264", "1827"), + ARCHITECTURE("건축과", "dmu_23015", "1836"), + INTERIOR_ARCHITECTURE_DESIGN("실내건축디자인과", "dmu_23256", "1845"), + VISUAL_DESIGN("시각디자인과", "dmu_23068", "1854"), + AR_VR_CONTENTS_DESIGN("AR-VR콘텐츠디자인과", "dmu_23269", "2633"), + + // 경영학부 + BUSINESS_MANAGEMENT("경영학과", "dmu_23232", "1866"), + TAX_ACCOUNTING("세무회계학과", "dmu_23234", "1875"), + DISTRIBUTION_MARKETING("유통마케팅학과", "dmu_23236", "1884"), + HOTEL_TOURISM("호텔관광학과", "dmu_23250", "1893"), + BUSINESS_INFORMATION("경영정보학과", "dmu_23238", "1902"), + BIG_DATA_MANAGEMENT("빅데이터경영과", "dmu_23260", "1911"); +} + From 8c77ec9472f59b32edd58127e5a82754dc554717 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 02:36:32 +0900 Subject: [PATCH 042/223] =?UTF-8?q?feat:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=EC=9D=84=20=ED=81=AC=EB=A1=A4=EB=A7=81=ED=95=98?= =?UTF-8?q?=EB=8A=94=20Parser=20=EA=B5=AC=ED=98=84=EC=B2=B4=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/crawling/notice/UrlGenerator.kt | 6 + .../department/DepartmentNoticeParser.kt | 103 ++++++++++++++++++ .../university/UniversityNoticeParser.kt | 99 +++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/UrlGenerator.kt create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeParser.kt create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeParser.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/UrlGenerator.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/UrlGenerator.kt new file mode 100644 index 0000000..bb3cc02 --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/UrlGenerator.kt @@ -0,0 +1,6 @@ +package com.dmforu.crawling.notice + +abstract class UrlGenerator { + protected abstract fun generateSearchUrl(): String + protected abstract fun generateUrlFromSearch(url: String): String +} diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeParser.kt new file mode 100644 index 0000000..a4ce7e9 --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeParser.kt @@ -0,0 +1,103 @@ +package com.dmforu.crawling.notice.department + +import com.dmforu.crawling.Parser +import com.dmforu.crawling.notice.UrlGenerator +import com.dmforu.crawling.WebPageLoader +import com.dmforu.domain.notice.Notice +import com.dmforu.domain.notice.Major +import org.springframework.context.annotation.Scope +import org.springframework.stereotype.Component +import java.time.LocalDate + +@Scope("prototype") +@Component +class DepartmentNoticeParser : UrlGenerator(), Parser { + + private lateinit var major: Major + private var pageNumber: Int = 1 + + fun initialize(major: Major) { + this.major = major + } + + /** + * HTML을 파싱하여 학과 공지사항 목록을 반환한다. + * + * @return 학과 공지사항 목록 + */ + override fun parse(): List { + + val departmentNotices: MutableList = java.util.ArrayList() + + val document = WebPageLoader.getHTML(generateSearchUrl()) + + val rows = document.select(".board-table tbody tr") + + for (row in rows) { + var number: Int + + try { + number = row.select(".td-num").text().toInt() + } catch (e: java.lang.NumberFormatException) { + continue + } + + val title = row.select(".td-subject a").text() + val author = row.select(".td-write").text() + val url = generateUrlFromSearch(row.select(".td-subject a").attr("href")) + val date = LocalDate.parse(row.select(".td-date").text(), formatter) + + val departmentNotice = Notice( + number = number, + type = major.type, + date = date, + title = title, + author = author, + url = url, + ) + + departmentNotices.add(departmentNotice) + } + + return departmentNotices + } + + /** + * 파싱할 페이지의 URL을 생성한다. + * + * @return URL + */ + protected override fun generateSearchUrl(): String { + return java.lang.String.format( + "https://www.dongyang.ac.kr/%s/%s/subview.do?page=%d", + major.majorPath, major.noticePath, pageNumber++ + ) + } + + /** + * 파싱 결과를 통해 공지사항의 URL을 생성한다. + * + * @param url 파싱 결과 + * @return URL + * @throws IllegalArgumentException Matcher를 통해 URL을 생성할 수 없는 경우 예외 발생 + */ + protected override fun generateUrlFromSearch(url: String): String { + // URL에서 정보를 추출하기 위한 Matcher 생성 + + val matcher = pattern.matcher(url) + + require(matcher.find()) { "Matcher did not find any match" } + + return String.format( + "https://www.dongyang.ac.kr/combBbs/%s/%s/%s/view.do?layout=unknown", + matcher.group(1), matcher.group(2), matcher.group(4) + ) + } + + companion object { + private val pattern: java.util.regex.Pattern = + java.util.regex.Pattern.compile("\\('([^']+)'\\,'([^']+)'\\,'([^']+)'\\,'([^']+)'") + private val formatter: java.time.format.DateTimeFormatter = + java.time.format.DateTimeFormatter.ofPattern("yyyy.MM.dd") + } +} \ No newline at end of file diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeParser.kt new file mode 100644 index 0000000..f56998d --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeParser.kt @@ -0,0 +1,99 @@ +package com.dmforu.crawling.notice.university + +import com.dmforu.crawling.Parser +import com.dmforu.crawling.notice.UrlGenerator +import com.dmforu.crawling.WebPageLoader +import com.dmforu.domain.notice.Notice +import org.springframework.context.annotation.Scope +import org.springframework.stereotype.Component +import java.time.LocalDate +import java.time.format.DateTimeFormatter + +@Scope("prototype") +@Component +class UniversityNoticeParser : UrlGenerator(), Parser { + private var pageNumber = 1 + + /** + * HTML을 파싱하여 대학 공지사항 목록을 반환한다. + * + * @return 대학 공지사항 목록 + */ + override fun parse(): List { + val universityNotices: MutableList = java.util.ArrayList() + + val document = WebPageLoader.getHTML(generateSearchUrl()) + + val rows = document.select(".board-table tbody tr") + + for (row in rows) { + var number: Int + + try { + number = row.select(".td-num").text().toInt() + } catch (e: java.lang.NumberFormatException) { + continue + } + + val title = removeSuffix(row.select(".td-subject a").text(), SUFFIX_NEW_POST) + val author = row.select(".td-write").text() + val url = generateUrlFromSearch(row.select(".td-subject a").attr("href")) + val date = LocalDate.parse(row.select(".td-date").text(), DATE_FORMATTER) + + val universityNotice = Notice( + number = number, + type = NOTICE_TYPE, + date = date, + title = title, + author = author, + url = url + ) + + universityNotices.add(universityNotice) + } + + return universityNotices + } + + /** + * 파싱할 페이지의 URL을 생성한다. + * + * @return URL + */ + protected override fun generateSearchUrl(): String { + return String.format(SEARCH_URL, pageNumber++) + } + + /** + * 파싱 결과를 통해 공지사항의 URL를 생성한다. + * + * @param url URL 파싱결과 + * @return 공지사항 URL + */ + protected override fun generateUrlFromSearch(url: String): String { + return String.format(RESULT_URL, url) + } + + /** + * 접미사를 제거한다. + * + * @param title 원본 문자열 + * @param suffix 제거하고 싶은 접미사 + * @return 원본에서 접미사를 제거한 문자열 + */ + private fun removeSuffix(title: String, suffix: String): String { + if (title.endsWith(suffix)) { + return title.substring(0, title.length - suffix.length).trim { it <= ' ' } + } + + return title + } + + companion object { + private val DATE_FORMATTER: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") + private const val SEARCH_URL = "https://www.dongyang.ac.kr/dongyang/129/subview.do?page=%d" + private const val RESULT_URL = "https://www.dongyang.ac.kr%s?layout=unknown" + private const val SUFFIX_NEW_POST = "새글" + private const val NOTICE_TYPE = "대학" + } +} \ No newline at end of file From e373e7b8332af6d0d6aa241a05c4c8c1946f00ad Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 02:37:43 +0900 Subject: [PATCH 043/223] =?UTF-8?q?feat:=20=ED=81=AC=EB=A1=A4=EB=A7=81?= =?UTF-8?q?=ED=95=9C=20=EA=B3=B5=EC=A7=80=EC=82=AC=ED=95=AD=EC=9D=84=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DepartmentNoticeCrawlingService.kt | 77 +++++++++++++++++++ .../UniversityNoticeCrawlingService.kt | 57 ++++++++++++++ .../kotlin/com/dmforu/domain/notice/Notice.kt | 10 ++- .../dmforu/domain/notice/NoticeRepository.kt | 1 + .../db/mysql/notice/NoticeEntityRepository.kt | 4 + 5 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeCrawlingService.kt create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeCrawlingService.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeCrawlingService.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeCrawlingService.kt new file mode 100644 index 0000000..1f20667 --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeCrawlingService.kt @@ -0,0 +1,77 @@ +package com.dmforu.crawling.notice.department + +import com.dmforu.domain.notice.Notice +import com.dmforu.domain.notice.NoticeRepository +import com.dmforu.domain.notice.Major +import org.springframework.beans.factory.ObjectProvider +import org.springframework.stereotype.Service + +@Service +class DepartmentNoticeCrawlingService( + private val prototypeBeanProvider: ObjectProvider, + private val noticeRepository: NoticeRepository, +) { + /** + * Major 열거형의 모든 값을 반복하여 모든 학과의 공지사항을 크롤링한다.

+ * 데이터베이스에 저장된 공지사항이 존재한다면, 최신 공지사항만 크롤링하여 업데이트 한다.

+ * 평일 오전 10시, 오후 17시 자동으로 메서드를 실행한다. + */ + fun crawling() { + for (major in Major.entries) { + crawlMajorDepartment(major) + } + } + + /** + * 해당 학과의 모든 공지사항을 크롤링한다.

+ * 공지사항 첫번째 페이지부터 크롤링을 시작한다.

+ * 데이터베이스에 저장된 공지사항의 가장 최신 번호와, 파싱된 공지사항 목록을 saveNewNotices 메서드를 통해 저장할지 결정한다.

+ * 만일, 저장이 이뤄지지 않는다면 더이상 파싱할 필요가 없기 때문에 무한 루트에서 빠져나온다.

+ * + * @param major 학과 정보 + */ + private fun crawlMajorDepartment(major: Major) { + val parser = prototypeBeanProvider.getObject(major) + + parser.initialize(major) + + val maxNumber: Int? = noticeRepository.findMaxNumberByType(major.type) + val currentMaxNumber = maxNumber ?: 0 + + while (true) { + val notices: List = parser.parse() + val isNewNoticeFound = saveNewNotices(notices, currentMaxNumber) + + if (!isNewNoticeFound) { + return + } + } + } + + /** + * 새로운 학과 공지사항을 저장한다.

+ * 데이터베이스에 저장된 최신 공지사항 번호보다 큰 번호를 가진 학과 공지사항을 저장한다.

+ * 데이터베이스에 저장된 공지사항이 존재하지 않아 currentMaxNumber가 0이라면 게시글의 번호가 1번이 될 때 까지 저장한다.

+ * 위의 조건을 만족하기 전까지 true를 반환하고, 만족하게 되면 false를 반환한다. + * + * @param notices 저장할 학과의 공지사항 목록 + * @param currentMaxNumber 현재 데이터베이스에 저장된 최신 공지사항의 번호 + * @return 저장이 성공했다면 true, 그렇지 않다면 false + */ + private fun saveNewNotices(notices: List, currentMaxNumber: Int): Boolean { + for (notice in notices) { + if (notice.isNumberLessThanOrEqualTo(currentMaxNumber)) { + return false + } + + noticeRepository.write(notice) + // TODO: FCM 메세지 전송을 위한 이벤트 트리거 +// eventPublisher!!.publishEvent(notice) + if (notice.isLastInType()) { + return false + } + } + + return true + } +} diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeCrawlingService.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeCrawlingService.kt new file mode 100644 index 0000000..46a36ef --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeCrawlingService.kt @@ -0,0 +1,57 @@ +package com.dmforu.crawling.notice.university + +import com.dmforu.domain.notice.Notice +import com.dmforu.domain.notice.NoticeRepository +import org.springframework.beans.factory.ObjectProvider +import org.springframework.stereotype.Service + + +@Service +class UniversityNoticeCrawlingService( + private val prototypeBeanProvider: ObjectProvider, + private val noticeRepository: NoticeRepository + ) { + /** + * 모든 대학 공지사항을 크롤링한다.

+ * 데이터베이스에 저장된 공지사항이 존재한다면, 최신 공지사항만 크롤링하여 업데이트 한다.

+ * 평일 오전 10시, 오후 17시 자동으로 메서드를 실행한다. + */ + fun crawling() { + val parser: UniversityNoticeParser = prototypeBeanProvider.getObject() + val maxNumber: Int? = noticeRepository.findMaxNumberByType("대학") + val currentMaxNumber = maxNumber ?: 0 + + while (true) { + val departmentNotices: List = parser.parse() + val isNewNoticeFound = saveNewNotices(departmentNotices, currentMaxNumber) + if (!isNewNoticeFound) { + return + } + } + } + + /** + * 새로운 대학 공지사항을 저장한다.

+ * 데이터베이스에 저장된 최신 공지사항 번호보다 큰 번호를 가진 학과 공지사항을 저장한다.

+ * 데이터베이스에 저장된 공지사항이 존재하지 않아 currentMaxNumber가 0이라면 게시글의 번호가 1번이 될 때 까지 저장한다.

+ * 위의 조건을 만족하기 전까지 true를 반환하고, 만족하게 되면 false를 반환한다. + * + * @param notices 저장할 대학 공지사항 목록 + * @param currentMaxNumber 현재 데이터베이스에 저장된 최신 공지사항의 번호 + * @return 저장에 성공했다면 true, 그렇지 않다면 false + */ + private fun saveNewNotices(notices: List, currentMaxNumber: Int): Boolean { + for (notice in notices) { + if (notice.isNumberLessThanOrEqualTo(currentMaxNumber)) { + return false + } + noticeRepository.write(notice) +// eventPublisher!!.publishEvent(notice) + if (notice.isLastInType()) { + return false + } + } + + return true + } +} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt index 9fc2e13..c991fb0 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt @@ -20,4 +20,12 @@ data class Notice( // 공지사항 URL val url: String -) \ No newline at end of file +) { + fun isNumberLessThanOrEqualTo(number: Int): Boolean { + return this.number <= number + } + + fun isLastInType(): Boolean{ + return this.number == 1 + } +} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt index 42ec4e4..47f6e81 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt @@ -5,4 +5,5 @@ interface NoticeRepository { fun findNoticesBySearchWord(searchWord: String, department: String, page: Int, size: Int): List fun findDepartmentNotices(department: String, page: Int, size: Int): List fun findUniversityNotices(page: Int, size: Int): List + fun findMaxNumberByType(type: String): Int? } \ No newline at end of file diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt index 8d3c358..2afa03c 100644 --- a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt @@ -41,6 +41,10 @@ internal class NoticeEntityRepository( return universityNoticePage?.mapNotNull { it?.toNotice() }?.toList().orEmpty() } + override fun findMaxNumberByType(type: String): Int? { + return noticeJpaRepository.findMaxNumberByType(type) + } + private fun pageRequest(page: Int, size: Int): PageRequest { val pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "number")) return pageable From 85d575432f6cb1ccaaf19a2f71f71e37fdcad0a6 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 02:50:49 +0900 Subject: [PATCH 044/223] =?UTF-8?q?refactor:=20Batch=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=EC=97=90=EC=84=9C=20Admin=20=EB=AA=A8=EB=93=88=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {dmforu-batch => dmforu-admin}/build.gradle.kts | 1 - .../main/kotlin/com/dmforu/admin/AdminApplication.kt | 12 ++++++------ .../kotlin/com/dmforu/admin/AdminApplicationTests.kt | 4 ++-- .../src/main/kotlin/com/dmforu/api/ApiApplication.kt | 1 - settings.gradle.kts | 2 +- 5 files changed, 9 insertions(+), 11 deletions(-) rename {dmforu-batch => dmforu-admin}/build.gradle.kts (86%) rename dmforu-batch/src/main/kotlin/com/dmforu/batch/BatchApplication.kt => dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt (55%) rename dmforu-batch/src/test/kotlin/com/dmforu/batch/BatchApplicationTests.kt => dmforu-admin/src/test/kotlin/com/dmforu/admin/AdminApplicationTests.kt (74%) diff --git a/dmforu-batch/build.gradle.kts b/dmforu-admin/build.gradle.kts similarity index 86% rename from dmforu-batch/build.gradle.kts rename to dmforu-admin/build.gradle.kts index d89c59e..f5e559b 100644 --- a/dmforu-batch/build.gradle.kts +++ b/dmforu-admin/build.gradle.kts @@ -12,7 +12,6 @@ dependencies { runtimeOnly(project(":dmforu-storage:db-mysql")) runtimeOnly(project(":dmforu-storage:db-redis")) - implementation("org.springframework.boot:spring-boot-starter-batch") // Jackson Library implementation("com.fasterxml.jackson.core:jackson-databind") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") diff --git a/dmforu-batch/src/main/kotlin/com/dmforu/batch/BatchApplication.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt similarity index 55% rename from dmforu-batch/src/main/kotlin/com/dmforu/batch/BatchApplication.kt rename to dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt index c341140..bbcc32f 100644 --- a/dmforu-batch/src/main/kotlin/com/dmforu/batch/BatchApplication.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt @@ -1,19 +1,19 @@ -package com.dmforu.batch +package com.dmforu.admin -import com.dmforu.crawling.diet.DietParser -import com.dmforu.domain.diet.DietRepository import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication @SpringBootApplication( scanBasePackages = [ + "com.dmforu.admin", "com.dmforu.domain", "com.dmforu.crawling", - "com.dmforu.storage.db.redis" + "com.dmforu.storage.db.redis", + "com.dmforu.storage.db.mysql" ] ) -class BatchApplication +class AdminApplication fun main(args: Array) { - runApplication(*args) + runApplication(*args) } diff --git a/dmforu-batch/src/test/kotlin/com/dmforu/batch/BatchApplicationTests.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/AdminApplicationTests.kt similarity index 74% rename from dmforu-batch/src/test/kotlin/com/dmforu/batch/BatchApplicationTests.kt rename to dmforu-admin/src/test/kotlin/com/dmforu/admin/AdminApplicationTests.kt index a39ddfb..e0ba44b 100644 --- a/dmforu-batch/src/test/kotlin/com/dmforu/batch/BatchApplicationTests.kt +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/AdminApplicationTests.kt @@ -1,10 +1,10 @@ -package com.dmforu.batch +package com.dmforu.admin import org.junit.jupiter.api.Test import org.springframework.boot.test.context.SpringBootTest @SpringBootTest -class BatchApplicationTests { +class AdminApplicationTests { @Test fun contextLoads() { diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt index 1359758..bc79386 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt @@ -7,7 +7,6 @@ import org.springframework.boot.runApplication scanBasePackages = [ "com.dmforu.api", "com.dmforu.domain", - "com.dmforu.crawling", "com.dmforu.storage.db.redis", "com.dmforu.storage.db.mysql" ] diff --git a/settings.gradle.kts b/settings.gradle.kts index 589c39b..62b5bd0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ rootProject.name = "DMU-BackEnd" include( "dmforu-api", - "dmforu-batch", + "dmforu-admin", "dmforu-domain", "dmforu-crawling", "dmforu-storage:db-mysql", From 57bb39a98d36d366ee641a8c3dc77cc42833f6a7 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 03:43:35 +0900 Subject: [PATCH 045/223] =?UTF-8?q?chore:=20=ED=81=AC=EB=A1=A4=EB=A7=81=20?= =?UTF-8?q?=EB=AA=A8=EB=93=88=EC=97=90=20=EC=9E=88=EB=8D=98=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scheduler/crawling}/DepartmentNoticeCrawlingService.kt | 3 ++- .../dmforu/admin/scheduler/crawling}/DietCrawlingService.kt | 3 ++- .../admin/scheduler/crawling}/ScheduleCrawlingService.kt | 3 ++- .../scheduler/crawling}/UniversityNoticeCrawlingService.kt | 3 ++- .../{notice/department => }/DepartmentNoticeParser.kt | 5 +---- .../kotlin/com/dmforu/crawling/{diet => }/DietParser.kt | 4 +--- .../com/dmforu/crawling/{schedule => }/ScheduleParser.kt | 6 ++---- .../{notice/university => }/UniversityNoticeParser.kt | 5 +---- .../kotlin/com/dmforu/crawling/{notice => }/UrlGenerator.kt | 2 +- 9 files changed, 14 insertions(+), 20 deletions(-) rename {dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department => dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling}/DepartmentNoticeCrawlingService.kt (97%) rename {dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet => dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling}/DietCrawlingService.kt (74%) rename {dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule => dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling}/ScheduleCrawlingService.kt (75%) rename {dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university => dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling}/UniversityNoticeCrawlingService.kt (96%) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{notice/department => }/DepartmentNoticeParser.kt (94%) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{diet => }/DietParser.kt (94%) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{schedule => }/ScheduleParser.kt (95%) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{notice/university => }/UniversityNoticeParser.kt (94%) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{notice => }/UrlGenerator.kt (81%) diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt similarity index 97% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeCrawlingService.kt rename to dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index 1f20667..43ae48c 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -1,5 +1,6 @@ -package com.dmforu.crawling.notice.department +package com.dmforu.admin.scheduler.crawling +import com.dmforu.crawling.DepartmentNoticeParser import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.NoticeRepository import com.dmforu.domain.notice.Major diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt similarity index 74% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietCrawlingService.kt rename to dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt index 8e27d82..21b3c35 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt @@ -1,5 +1,6 @@ -package com.dmforu.crawling.diet +package com.dmforu.admin.scheduler.crawling +import com.dmforu.crawling.DietParser import com.dmforu.domain.diet.DietService class DietCrawlingService( diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt similarity index 75% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleCrawlingService.kt rename to dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt index 59adbc2..481efb4 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt @@ -1,5 +1,6 @@ -package com.dmforu.crawling.schedule +package com.dmforu.admin.scheduler.crawling +import com.dmforu.crawling.ScheduleParser import com.dmforu.domain.schedule.ScheduleService class ScheduleCrawlingService( diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt similarity index 96% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeCrawlingService.kt rename to dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt index 46a36ef..8a02efa 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt @@ -1,5 +1,6 @@ -package com.dmforu.crawling.notice.university +package com.dmforu.admin.scheduler.crawling +import com.dmforu.crawling.UniversityNoticeParser import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.NoticeRepository import org.springframework.beans.factory.ObjectProvider diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt similarity index 94% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeParser.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt index a4ce7e9..c47bc60 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/department/DepartmentNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt @@ -1,8 +1,5 @@ -package com.dmforu.crawling.notice.department +package com.dmforu.crawling -import com.dmforu.crawling.Parser -import com.dmforu.crawling.notice.UrlGenerator -import com.dmforu.crawling.WebPageLoader import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.Major import org.springframework.context.annotation.Scope diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt similarity index 94% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietParser.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt index 4e24e55..bda989f 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/diet/DietParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt @@ -1,7 +1,5 @@ -package com.dmforu.crawling.diet +package com.dmforu.crawling -import com.dmforu.crawling.Parser -import com.dmforu.crawling.WebPageLoader import com.dmforu.domain.diet.Diet import org.jsoup.nodes.Element import org.springframework.stereotype.Service diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt similarity index 95% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleParser.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt index 7d51e7b..5e59fca 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/schedule/ScheduleParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt @@ -1,7 +1,5 @@ -package com.dmforu.crawling.schedule +package com.dmforu.crawling -import com.dmforu.crawling.Parser -import com.dmforu.crawling.WebPageLoader import com.dmforu.domain.schedule.Schedule import org.jsoup.nodes.Element import org.springframework.stereotype.Service @@ -9,7 +7,7 @@ import java.time.LocalDate import java.time.ZoneId @Service -class ScheduleParser : Parser { +class ScheduleParser : Parser { override fun parse(): List { val currentYear = LocalDate.now(ZoneId.of(TIME_ZONE)).year diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt similarity index 94% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeParser.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt index f56998d..7888ee8 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/university/UniversityNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt @@ -1,8 +1,5 @@ -package com.dmforu.crawling.notice.university +package com.dmforu.crawling -import com.dmforu.crawling.Parser -import com.dmforu.crawling.notice.UrlGenerator -import com.dmforu.crawling.WebPageLoader import com.dmforu.domain.notice.Notice import org.springframework.context.annotation.Scope import org.springframework.stereotype.Component diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/UrlGenerator.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UrlGenerator.kt similarity index 81% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/UrlGenerator.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UrlGenerator.kt index bb3cc02..cff76ae 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/notice/UrlGenerator.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UrlGenerator.kt @@ -1,4 +1,4 @@ -package com.dmforu.crawling.notice +package com.dmforu.crawling abstract class UrlGenerator { protected abstract fun generateSearchUrl(): String From 5ef07bbf327b80319b720767314e9e92df675d44 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 03:52:24 +0900 Subject: [PATCH 046/223] =?UTF-8?q?refactor:=20=EB=8B=A8=EC=88=9C=ED=9E=88?= =?UTF-8?q?=20=EB=AA=A8=EB=93=A0=20Repository=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=EC=9D=84=20=EB=8B=B4=EC=9D=80=20Service=EB=A5=BC=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=ED=95=98=EA=B3=A0=20=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=EB=A5=BC=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scheduler/crawling/DietCrawlingService.kt | 7 ++++--- .../crawling/ScheduleCrawlingService.kt | 8 ++++---- .../dmforu/api/controller/v1/DietController.kt | 8 ++++---- .../api/controller/v1/ScheduleController.kt | 8 ++++---- .../com/dmforu/domain/diet/DietService.kt | 17 ----------------- .../kotlin/com/dmforu/domain/diet/DietWriter.kt | 2 +- .../com/dmforu/domain/notice/NoticeWriter.kt | 2 +- .../dmforu/domain/schedule/ScheduleService.kt | 17 ----------------- .../dmforu/domain/schedule/ScheduleWriter.kt | 2 +- 9 files changed, 19 insertions(+), 52 deletions(-) delete mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietService.kt delete mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt index 21b3c35..7ad4b8b 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt @@ -2,12 +2,13 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.DietParser import com.dmforu.domain.diet.DietService +import com.dmforu.domain.diet.DietWriter class DietCrawlingService( private val dietParser: DietParser, - private val dietService: DietService + private val dietWriter: DietWriter, ) { - fun rewriteToRedis() { - dietService.write(dietParser.parse()) + fun overwriteToRedis() { + dietWriter.overwrite(dietParser.parse()) } } \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt index 481efb4..989ba63 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt @@ -1,13 +1,13 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.ScheduleParser -import com.dmforu.domain.schedule.ScheduleService +import com.dmforu.domain.schedule.ScheduleWriter class ScheduleCrawlingService( private val scheduleParser: ScheduleParser, - private val scheduleService: ScheduleService + private val scheduleWriter: ScheduleWriter ) { - fun rewriteToRedis() { - scheduleService.write(scheduleParser.parse()) + fun overwriteToRedis() { + scheduleWriter.overwrite(scheduleParser.parse()) } } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt index be284ae..d76cf09 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt @@ -1,7 +1,7 @@ package com.dmforu.api.controller.v1 import com.dmforu.domain.diet.Diet -import com.dmforu.domain.diet.DietService +import com.dmforu.domain.diet.DietReader import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.ResponseEntity @@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RestController @Tag(name = "식단") @RestController class DietController( - private val dietService: DietService + private val dietReader: DietReader ) { @Operation( summary = "[구버전] 식단표 API", @@ -19,7 +19,7 @@ class DietController( ) @GetMapping("/api/v1/dmu/cafeteria") fun readDietOld(): ResponseEntity> { - return ResponseEntity.ok().body(dietService.read()) + return ResponseEntity.ok().body(dietReader.read()) } @Operation( @@ -28,6 +28,6 @@ class DietController( ) @GetMapping("/api/v1/cafeteria") fun readDiet(): ResponseEntity> { - return ResponseEntity.ok().body(dietService.read()) + return ResponseEntity.ok().body(dietReader.read()) } } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt index 8c0eaef..ad4b90a 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt @@ -2,7 +2,7 @@ package com.dmforu.api.controller.v1 import com.dmforu.api.controller.v1.response.LegacySchedule import com.dmforu.domain.schedule.Schedule -import com.dmforu.domain.schedule.ScheduleService +import com.dmforu.domain.schedule.ScheduleReader import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.ResponseEntity @@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RestController @Tag(name = "학사일정") @RestController class ScheduleController( - private val scheduleService: ScheduleService + private val scheduleReader: ScheduleReader ) { @GetMapping("/api/v1/dmu/schedule") @Operation( @@ -20,7 +20,7 @@ class ScheduleController( description = "현재년도를 기준으로 작년부터 내년 2월까지의 학사일정을 출력한다." ) fun readScheduleOld(): ResponseEntity> { - val schedules = LegacySchedule.fromScheduleYears(scheduleService.read()) + val schedules = LegacySchedule.fromScheduleYears(scheduleReader.read()) return ResponseEntity.ok().body(schedules) } @@ -30,6 +30,6 @@ class ScheduleController( description = "현재년도를 기준으로 작년부터 내년 2월까지의 학사일정을 출력한다." ) fun raedSchedule(): ResponseEntity> { - return ResponseEntity.ok().body(scheduleService.read()) + return ResponseEntity.ok().body(scheduleReader.read()) } } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietService.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietService.kt deleted file mode 100644 index 7f45825..0000000 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietService.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.dmforu.domain.diet - -import org.springframework.stereotype.Service - -@Service -class DietService( - private val dietReader: DietReader, - private val dietWriter: DietWriter -) { - fun read(): List { - return dietReader.read() - } - - fun write(diets: List) { - return dietWriter.write(diets) - } -} diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietWriter.kt index 34b7853..c720257 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietWriter.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietWriter.kt @@ -6,7 +6,7 @@ import org.springframework.stereotype.Component class DietWriter( private val dietRepository: DietRepository ) { - fun write(diets: List) { + fun overwrite(diets: List) { dietRepository.write(diets) } } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt index d1f7871..dce97d8 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt @@ -6,7 +6,7 @@ import org.springframework.stereotype.Component class NoticeWriter ( private val noticeRepository: NoticeRepository ){ - fun write(notice: Notice) { + fun overwrite(notice: Notice) { noticeRepository.write(notice) } } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt deleted file mode 100644 index 1690d00..0000000 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleService.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.dmforu.domain.schedule - -import org.springframework.stereotype.Service - -@Service -class ScheduleService( - private val scheduleReader: ScheduleReader, - private val scheduleWriter: ScheduleWriter -) { - fun read(): List { - return scheduleReader.read() - } - - fun write(schedules: List) { - return scheduleWriter.write(schedules) - } -} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt index 6d07836..356576d 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt @@ -6,7 +6,7 @@ import org.springframework.stereotype.Component class ScheduleWriter( private val scheduleRepository: ScheduleRepository ) { - fun write(schedules: List) { + fun overwrite(schedules: List) { scheduleRepository.write(schedules) } } \ No newline at end of file From 0b6c0812c61be1d510bc6dba3c115dd9bbad73ea Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 04:14:16 +0900 Subject: [PATCH 047/223] =?UTF-8?q?refactor:=20=ED=81=AC=EB=A1=A4=EB=A7=81?= =?UTF-8?q?=20=EC=9E=91=EC=97=85=EC=97=90=EC=84=9C=20Repository=EB=A5=BC?= =?UTF-8?q?=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80=20=EC=95=8A=EA=B3=A0,?= =?UTF-8?q?=20CrawlWriter=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawling/DepartmentNoticeCrawlingService.kt | 8 ++++---- .../crawling/UniversityNoticeCrawlingService.kt | 10 +++++----- .../notice/{NoticeWriter.kt => NoticeCrawlWriter.kt} | 10 +++++++--- 3 files changed, 16 insertions(+), 12 deletions(-) rename dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/{NoticeWriter.kt => NoticeCrawlWriter.kt} (52%) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index 43ae48c..e46235a 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -2,15 +2,15 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.DepartmentNoticeParser import com.dmforu.domain.notice.Notice -import com.dmforu.domain.notice.NoticeRepository import com.dmforu.domain.notice.Major +import com.dmforu.domain.notice.NoticeCrawlWriter import org.springframework.beans.factory.ObjectProvider import org.springframework.stereotype.Service @Service class DepartmentNoticeCrawlingService( private val prototypeBeanProvider: ObjectProvider, - private val noticeRepository: NoticeRepository, + private val noticeCrawlWriter: NoticeCrawlWriter ) { /** * Major 열거형의 모든 값을 반복하여 모든 학과의 공지사항을 크롤링한다.

@@ -36,7 +36,7 @@ class DepartmentNoticeCrawlingService( parser.initialize(major) - val maxNumber: Int? = noticeRepository.findMaxNumberByType(major.type) + val maxNumber: Int? = noticeCrawlWriter.findMaxNumberByType(major.type) val currentMaxNumber = maxNumber ?: 0 while (true) { @@ -65,7 +65,7 @@ class DepartmentNoticeCrawlingService( return false } - noticeRepository.write(notice) + noticeCrawlWriter.write(notice) // TODO: FCM 메세지 전송을 위한 이벤트 트리거 // eventPublisher!!.publishEvent(notice) if (notice.isLastInType()) { diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt index 8a02efa..9562384 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt @@ -2,7 +2,7 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.UniversityNoticeParser import com.dmforu.domain.notice.Notice -import com.dmforu.domain.notice.NoticeRepository +import com.dmforu.domain.notice.NoticeCrawlWriter import org.springframework.beans.factory.ObjectProvider import org.springframework.stereotype.Service @@ -10,8 +10,8 @@ import org.springframework.stereotype.Service @Service class UniversityNoticeCrawlingService( private val prototypeBeanProvider: ObjectProvider, - private val noticeRepository: NoticeRepository - ) { + private val noticeCrawlWriter: NoticeCrawlWriter +) { /** * 모든 대학 공지사항을 크롤링한다.

* 데이터베이스에 저장된 공지사항이 존재한다면, 최신 공지사항만 크롤링하여 업데이트 한다.

@@ -19,7 +19,7 @@ class UniversityNoticeCrawlingService( */ fun crawling() { val parser: UniversityNoticeParser = prototypeBeanProvider.getObject() - val maxNumber: Int? = noticeRepository.findMaxNumberByType("대학") + val maxNumber: Int? = noticeCrawlWriter.findMaxNumberByType("대학") val currentMaxNumber = maxNumber ?: 0 while (true) { @@ -46,7 +46,7 @@ class UniversityNoticeCrawlingService( if (notice.isNumberLessThanOrEqualTo(currentMaxNumber)) { return false } - noticeRepository.write(notice) + noticeCrawlWriter.write(notice) // eventPublisher!!.publishEvent(notice) if (notice.isLastInType()) { return false diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlWriter.kt similarity index 52% rename from dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt rename to dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlWriter.kt index dce97d8..0160a39 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlWriter.kt @@ -3,10 +3,14 @@ package com.dmforu.domain.notice import org.springframework.stereotype.Component @Component -class NoticeWriter ( +class NoticeCrawlWriter( private val noticeRepository: NoticeRepository -){ - fun overwrite(notice: Notice) { +) { + fun findMaxNumberByType(type: String): Int? { + return noticeRepository.findMaxNumberByType(type) + } + + fun write(notice: Notice) { noticeRepository.write(notice) } } \ No newline at end of file From 972ebc6d83713c2e87d892cee7a3f7ba7a7635cf Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 04:18:21 +0900 Subject: [PATCH 048/223] =?UTF-8?q?feat:=20=ED=81=AC=EB=A1=A4=EB=A7=81=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=8A=A4=EC=BC=80=EC=A4=84=EB=9F=AC=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/dmforu/admin/AdminApplication.kt | 2 ++ .../scheduler/crawling/DepartmentNoticeCrawlingService.kt | 2 ++ .../dmforu/admin/scheduler/crawling/DietCrawlingService.kt | 5 ++++- .../admin/scheduler/crawling/ScheduleCrawlingService.kt | 4 ++++ .../scheduler/crawling/UniversityNoticeCrawlingService.kt | 2 ++ 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt index bbcc32f..f29014e 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt @@ -2,6 +2,7 @@ package com.dmforu.admin import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication +import org.springframework.scheduling.annotation.EnableScheduling @SpringBootApplication( scanBasePackages = [ @@ -12,6 +13,7 @@ import org.springframework.boot.runApplication "com.dmforu.storage.db.mysql" ] ) +@EnableScheduling class AdminApplication fun main(args: Array) { diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index e46235a..ec2f378 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -5,6 +5,7 @@ import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.Major import com.dmforu.domain.notice.NoticeCrawlWriter import org.springframework.beans.factory.ObjectProvider +import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Service @Service @@ -17,6 +18,7 @@ class DepartmentNoticeCrawlingService( * 데이터베이스에 저장된 공지사항이 존재한다면, 최신 공지사항만 크롤링하여 업데이트 한다.

* 평일 오전 10시, 오후 17시 자동으로 메서드를 실행한다. */ + @Scheduled(cron = "0 */10 9-19 * * MON-FRI") fun crawling() { for (major in Major.entries) { crawlMajorDepartment(major) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt index 7ad4b8b..4f1ed5c 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt @@ -1,13 +1,16 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.DietParser -import com.dmforu.domain.diet.DietService import com.dmforu.domain.diet.DietWriter +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Service +@Service class DietCrawlingService( private val dietParser: DietParser, private val dietWriter: DietWriter, ) { + @Scheduled(cron = "0 0 8,20 * * *") fun overwriteToRedis() { dietWriter.overwrite(dietParser.parse()) } diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt index 989ba63..0b1c40d 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt @@ -2,11 +2,15 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.ScheduleParser import com.dmforu.domain.schedule.ScheduleWriter +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Service +@Service class ScheduleCrawlingService( private val scheduleParser: ScheduleParser, private val scheduleWriter: ScheduleWriter ) { + @Scheduled(cron = "0 0 8,20 * * *") fun overwriteToRedis() { scheduleWriter.overwrite(scheduleParser.parse()) } diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt index 9562384..f8bb5bd 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt @@ -4,6 +4,7 @@ import com.dmforu.crawling.UniversityNoticeParser import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.NoticeCrawlWriter import org.springframework.beans.factory.ObjectProvider +import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Service @@ -17,6 +18,7 @@ class UniversityNoticeCrawlingService( * 데이터베이스에 저장된 공지사항이 존재한다면, 최신 공지사항만 크롤링하여 업데이트 한다.

* 평일 오전 10시, 오후 17시 자동으로 메서드를 실행한다. */ + @Scheduled(cron = "0 */10 9-19 * * MON-FRI") fun crawling() { val parser: UniversityNoticeParser = prototypeBeanProvider.getObject() val maxNumber: Int? = noticeCrawlWriter.findMaxNumberByType("대학") From c7c94144a569bb9d627571200a874ee06dca2d39 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 04:30:29 +0900 Subject: [PATCH 049/223] =?UTF-8?q?refactor:=20=EC=8A=A4=EC=BC=80=EC=A4=84?= =?UTF-8?q?=EB=9F=AC=EC=9D=98=20=EC=B1=85=EC=9E=84=EC=9D=84=20=ED=95=9C=20?= =?UTF-8?q?=EA=B3=B3=EC=9C=BC=EB=A1=9C=20=EC=9D=91=EC=A7=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/scheduler/CrawlingScheduler.kt | 28 +++++++++++++++++++ .../DepartmentNoticeCrawlingService.kt | 1 - .../scheduler/crawling/DietCrawlingService.kt | 2 -- .../crawling/ScheduleCrawlingService.kt | 2 -- .../UniversityNoticeCrawlingService.kt | 2 -- 5 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/CrawlingScheduler.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/CrawlingScheduler.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/CrawlingScheduler.kt new file mode 100644 index 0000000..471aeb2 --- /dev/null +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/CrawlingScheduler.kt @@ -0,0 +1,28 @@ +package com.dmforu.admin.scheduler + +import com.dmforu.admin.scheduler.crawling.DepartmentNoticeCrawlingService +import com.dmforu.admin.scheduler.crawling.DietCrawlingService +import com.dmforu.admin.scheduler.crawling.ScheduleCrawlingService +import com.dmforu.admin.scheduler.crawling.UniversityNoticeCrawlingService +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Service + +@Service +class CrawlingScheduler ( + private val departmentNoticeCrawlingService: DepartmentNoticeCrawlingService, + private val universityNoticeCrawlingService: UniversityNoticeCrawlingService, + private val dietCrawlingService: DietCrawlingService, + private val scheduleCrawlingService: ScheduleCrawlingService, +) { + @Scheduled(cron = "0 */10 9-19 * * MON-FRI") + fun noticeCrawling() { + departmentNoticeCrawlingService.crawling() + universityNoticeCrawlingService.crawling() + } + + @Scheduled(cron = "0 0 8,20 * * *") + fun dietCrawling() { + dietCrawlingService.overwriteToRedis() + scheduleCrawlingService.overwriteToRedis() + } +} \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index ec2f378..9e57e48 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -18,7 +18,6 @@ class DepartmentNoticeCrawlingService( * 데이터베이스에 저장된 공지사항이 존재한다면, 최신 공지사항만 크롤링하여 업데이트 한다.

* 평일 오전 10시, 오후 17시 자동으로 메서드를 실행한다. */ - @Scheduled(cron = "0 */10 9-19 * * MON-FRI") fun crawling() { for (major in Major.entries) { crawlMajorDepartment(major) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt index 4f1ed5c..0425da4 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt @@ -2,7 +2,6 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.DietParser import com.dmforu.domain.diet.DietWriter -import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Service @Service @@ -10,7 +9,6 @@ class DietCrawlingService( private val dietParser: DietParser, private val dietWriter: DietWriter, ) { - @Scheduled(cron = "0 0 8,20 * * *") fun overwriteToRedis() { dietWriter.overwrite(dietParser.parse()) } diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt index 0b1c40d..768dc8e 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt @@ -2,7 +2,6 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.ScheduleParser import com.dmforu.domain.schedule.ScheduleWriter -import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Service @Service @@ -10,7 +9,6 @@ class ScheduleCrawlingService( private val scheduleParser: ScheduleParser, private val scheduleWriter: ScheduleWriter ) { - @Scheduled(cron = "0 0 8,20 * * *") fun overwriteToRedis() { scheduleWriter.overwrite(scheduleParser.parse()) } diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt index f8bb5bd..9562384 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt @@ -4,7 +4,6 @@ import com.dmforu.crawling.UniversityNoticeParser import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.NoticeCrawlWriter import org.springframework.beans.factory.ObjectProvider -import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Service @@ -18,7 +17,6 @@ class UniversityNoticeCrawlingService( * 데이터베이스에 저장된 공지사항이 존재한다면, 최신 공지사항만 크롤링하여 업데이트 한다.

* 평일 오전 10시, 오후 17시 자동으로 메서드를 실행한다. */ - @Scheduled(cron = "0 */10 9-19 * * MON-FRI") fun crawling() { val parser: UniversityNoticeParser = prototypeBeanProvider.getObject() val maxNumber: Int? = noticeCrawlWriter.findMaxNumberByType("대학") From cfc84150f7504fa2d527cacda407a8058c911bfc Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 04:38:20 +0900 Subject: [PATCH 050/223] =?UTF-8?q?style:=20=EC=9E=90=EB=B0=94=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=BD=94=ED=8B=80=EB=A6=B0=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=B4=20import=EB=AC=B8?= =?UTF-8?q?=EC=9D=B4=20=EC=83=9D=EC=84=B1=EB=90=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EC=9D=80=20=EB=B6=80=EB=B6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt | 3 ++- .../main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt index c47bc60..1b10eff 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt @@ -4,6 +4,7 @@ import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.Major import org.springframework.context.annotation.Scope import org.springframework.stereotype.Component +import java.lang.NumberFormatException import java.time.LocalDate @Scope("prototype") @@ -35,7 +36,7 @@ class DepartmentNoticeParser : UrlGenerator(), Parser { try { number = row.select(".td-num").text().toInt() - } catch (e: java.lang.NumberFormatException) { + } catch (e: NumberFormatException) { continue } diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt index 7888ee8..fc4efc2 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt @@ -3,6 +3,7 @@ package com.dmforu.crawling import com.dmforu.domain.notice.Notice import org.springframework.context.annotation.Scope import org.springframework.stereotype.Component +import java.lang.NumberFormatException import java.time.LocalDate import java.time.format.DateTimeFormatter @@ -28,7 +29,7 @@ class UniversityNoticeParser : UrlGenerator(), Parser { try { number = row.select(".td-num").text().toInt() - } catch (e: java.lang.NumberFormatException) { + } catch (e: NumberFormatException) { continue } From dbb48f2845c05794afb12c4f98c36c4e804ed81d Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:44:37 +0900 Subject: [PATCH 051/223] =?UTF-8?q?feat:=20=EC=95=8C=EB=A6=BC=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/subscribe/Subscribe.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt new file mode 100644 index 0000000..7bc6437 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt @@ -0,0 +1,25 @@ +package com.dmforu.domain.subscribe + +data class Subscribe( + val token: String, + var department: String, + var keywords: List, + var isDepartmentSubscribed: Boolean, + var areKeywordsSubscribed: Boolean, +) { + fun subscribeDepartment() { + this.isDepartmentSubscribed = true; + } + + fun unsubscribeDepartment() { + this.isDepartmentSubscribed = false; + } + + fun subscribeKeywords() { + this.areKeywordsSubscribed = true; + } + + fun unsubscribeKeywords() { + this.areKeywordsSubscribed = false; + } +} \ No newline at end of file From c466b99d4ee6b2ff65ebe1526a3592be63f3e265 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:46:01 +0900 Subject: [PATCH 052/223] =?UTF-8?q?feat:=20=EC=95=8C=EB=A6=BC=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../db/mysql/subscribe/SubscribeEntity.kt | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt new file mode 100644 index 0000000..0b04ff2 --- /dev/null +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt @@ -0,0 +1,39 @@ +package com.dmforu.storage.db.mysql.subscribe + +import com.dmforu.domain.subscribe.Subscribe +import com.dmforu.storage.db.mysql.converter.StringListConverter +import jakarta.persistence.Convert +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.Table + + +@Table(name = "token") +@Entity +internal class SubscribeEntity( + @Id + val token: String, + + val department: String, + + @Convert(converter = StringListConverter::class) + val keywords: List?, + + val isDepartmentSubscribed: Boolean, + + val areKeywordsSubscribed: Boolean, +) { + constructor() : this("", "", emptyList(), false, false) + + companion object { + fun from(subscribe: Subscribe): SubscribeEntity { + return SubscribeEntity( + token = subscribe.token, + department = subscribe.department, + keywords = subscribe.keywords, + isDepartmentSubscribed = false, + areKeywordsSubscribed = false + ) + } + } +} \ No newline at end of file From 6120d5d8ae07b25462b805fec5e9d53921ed354a Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:46:34 +0900 Subject: [PATCH 053/223] =?UTF-8?q?feat:=20=EC=95=8C=EB=A6=BC=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=A0=88=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=20?= =?UTF-8?q?=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/subscribe/SubscribeRepository.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt new file mode 100644 index 0000000..3fa57d1 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt @@ -0,0 +1,5 @@ +package com.dmforu.domain.subscribe + +interface SubscribeRepository { + fun save(subscribe: Subscribe) +} \ No newline at end of file From 23052746b52378bb8457458b9f541890d6b7277f Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:47:21 +0900 Subject: [PATCH 054/223] =?UTF-8?q?feat:=20=EC=95=8C=EB=A6=BC=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=A0=88=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=EC=B2=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-storage/db-mysql/build.gradle.kts | 3 ++ .../db/mysql/converter/StringListConverter.kt | 29 +++++++++++++++++++ .../subscribe/SubscribeEntityRepository.kt | 15 ++++++++++ .../mysql/subscribe/SubscribeJpaRepository.kt | 7 +++++ 4 files changed, 54 insertions(+) create mode 100644 dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt create mode 100644 dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt create mode 100644 dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt diff --git a/dmforu-storage/db-mysql/build.gradle.kts b/dmforu-storage/db-mysql/build.gradle.kts index 767cc0d..4bb6941 100644 --- a/dmforu-storage/db-mysql/build.gradle.kts +++ b/dmforu-storage/db-mysql/build.gradle.kts @@ -6,6 +6,9 @@ allOpen { dependencies { compileOnly(project(":dmforu-domain")) + implementation("org.springframework.boot:spring-boot-starter-data-jpa") + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.0") + runtimeOnly ("com.mysql:mysql-connector-j") } \ No newline at end of file diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt new file mode 100644 index 0000000..a34dea8 --- /dev/null +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt @@ -0,0 +1,29 @@ +package com.dmforu.storage.db.mysql.converter + +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import jakarta.persistence.AttributeConverter +import jakarta.persistence.Converter + +@Converter +class StringListConverter : AttributeConverter, String> { + + private val mapper: ObjectMapper = ObjectMapper() + + override fun convertToDatabaseColumn(datas: List): String { + try { + return mapper.writeValueAsString(datas) + } catch (e: JsonProcessingException) { + throw IllegalArgumentException("Error converting list to JSON: ${e.message}", e) + } + } + + override fun convertToEntityAttribute(data: String): List { + try { + return mapper.readValue(data, object : TypeReference>() {}) + } catch (e: JsonProcessingException) { + throw IllegalArgumentException("Error converting JSON to list: ${e.message}", e) + } + } +} \ No newline at end of file diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt new file mode 100644 index 0000000..cf5b01e --- /dev/null +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt @@ -0,0 +1,15 @@ +package com.dmforu.storage.db.mysql.subscribe + +import com.dmforu.domain.subscribe.Subscribe +import com.dmforu.domain.subscribe.SubscribeRepository +import org.springframework.stereotype.Repository + +@Repository +internal class SubscribeEntityRepository( + private val subscribeJpaRepository: SubscribeJpaRepository, +) : SubscribeRepository { + override fun save(subscribe: Subscribe) { + subscribeJpaRepository.save(SubscribeEntity.from(subscribe)) + } + +} \ No newline at end of file diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt new file mode 100644 index 0000000..8160a9a --- /dev/null +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt @@ -0,0 +1,7 @@ +package com.dmforu.storage.db.mysql.subscribe + +import org.springframework.data.jpa.repository.JpaRepository + +internal interface SubscribeJpaRepository : JpaRepository { + +} \ No newline at end of file From 93470ea0ff764453251e4d8223eded83666d9718 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:48:39 +0900 Subject: [PATCH 055/223] =?UTF-8?q?feat:=20=EC=95=8C=EB=A6=BC=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=B5=9C=EC=B4=88=20=EB=93=B1=EB=A1=9D=20API=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/v1/SubscribeController.kt | 32 +++++++++++++++++++ .../v1/request/OldRegisterSubscribeRequest.kt | 22 +++++++++++++ .../v1/request/RegisterSubscribeRequest.kt | 21 ++++++++++++ .../domain/subscribe/SubscribeWriter.kt | 12 +++++++ 4 files changed, 87 insertions(+) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldRegisterSubscribeRequest.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeWriter.kt diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt new file mode 100644 index 0000000..b8d98e9 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt @@ -0,0 +1,32 @@ +package com.dmforu.api.controller.v1 + +import com.dmforu.api.controller.v1.request.OldRegisterSubscribeRequest +import com.dmforu.api.controller.v1.request.RegisterSubscribeRequest +import com.dmforu.domain.subscribe.SubscribeWriter +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RestController + +@Tag(name = "알림 설정") +@RestController +class SubscribeController( + private val subscribeWriter: SubscribeWriter, +) { + @Operation(summary = "[구버전] 최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") + @PostMapping("/token/v1/dmu/initToken") + fun oldTokenSubscribe(@RequestBody oldRegisterSubscribeRequest: OldRegisterSubscribeRequest): ResponseEntity { + subscribeWriter.write(oldRegisterSubscribeRequest.toSubscribe()) + return ResponseEntity.status(HttpStatus.CREATED).build() + } + + @Operation(summary = "최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") + @PostMapping("/api/v1/subscribe/registration") + fun tokenSubscribe(@RequestBody registerSubscribeRequest: RegisterSubscribeRequest): ResponseEntity { + subscribeWriter.write(registerSubscribeRequest.toSubscribe()) + return ResponseEntity.status(HttpStatus.CREATED).build() + } +} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldRegisterSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldRegisterSubscribeRequest.kt new file mode 100644 index 0000000..2f3be34 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldRegisterSubscribeRequest.kt @@ -0,0 +1,22 @@ +package com.dmforu.api.controller.v1.request + +import com.dmforu.domain.subscribe.Subscribe + +data class OldRegisterSubscribeRequest( + val token: String, + val department: String, + val topic: List +) { + fun toSubscribe(): Subscribe { + val isDepartmentSubscribed = department.isNotBlank() + val areKeywordsSubscribed = topic.isNotEmpty() + + return Subscribe( + token = token, + department = department, + keywords = topic, + isDepartmentSubscribed = isDepartmentSubscribed, + areKeywordsSubscribed = areKeywordsSubscribed + ) + } +} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt new file mode 100644 index 0000000..4de5433 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt @@ -0,0 +1,21 @@ +package com.dmforu.api.controller.v1.request + +import com.dmforu.domain.subscribe.Subscribe + +data class RegisterSubscribeRequest ( + val token: String, + val department: String, + val keywords: List, + val isDepartmentSubscribed: Boolean, + val areKeywordSubscribed: Boolean, +) { + fun toSubscribe(): Subscribe { + return Subscribe( + token = token, + department = department, + keywords = keywords, + isDepartmentSubscribed = isDepartmentSubscribed, + areKeywordsSubscribed = areKeywordSubscribed + ) + } +} diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeWriter.kt new file mode 100644 index 0000000..5633797 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeWriter.kt @@ -0,0 +1,12 @@ +package com.dmforu.domain.subscribe + +import org.springframework.stereotype.Service + +@Service +class SubscribeWriter( + private val subscribeRepository: SubscribeRepository, +) { + fun write(subscribe: Subscribe) { + subscribeRepository.save(subscribe) + } +} \ No newline at end of file From 02a25ef84a376e2df2c2f7e6ae3bc297ac852fd4 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:51:02 +0900 Subject: [PATCH 056/223] =?UTF-8?q?feat:=20=EC=95=8C=EB=A6=BC=20=EA=B5=AC?= =?UTF-8?q?=EB=8F=85,=20=EA=B5=AC=EB=8F=85=20=ED=95=B4=EC=A7=80=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/v1/SubscribeController.kt | 38 ++++++++++++++++-- .../v1/request/OldDepartmentRequest.kt | 6 +++ .../v1/request/OldKeywordsSubscribeRequest.kt | 6 +++ .../controller/v1/request/OldTokenRequest.kt | 5 +++ .../subscribe/OldSubscribeRepository.kt | 8 ++++ .../domain/subscribe/OldSubscribeUpdater.kt | 30 ++++++++++++++ .../subscribe/SubscribeEntityRepository.kt | 40 ++++++++++++++++++- 7 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldDepartmentRequest.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldKeywordsSubscribeRequest.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldTokenRequest.kt create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt index b8d98e9..be97f32 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt @@ -1,7 +1,7 @@ package com.dmforu.api.controller.v1 -import com.dmforu.api.controller.v1.request.OldRegisterSubscribeRequest -import com.dmforu.api.controller.v1.request.RegisterSubscribeRequest +import com.dmforu.api.controller.v1.request.* +import com.dmforu.domain.subscribe.OldSubscribeUpdater import com.dmforu.domain.subscribe.SubscribeWriter import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag @@ -15,12 +15,41 @@ import org.springframework.web.bind.annotation.RestController @RestController class SubscribeController( private val subscribeWriter: SubscribeWriter, + private val subscribeUpdater: OldSubscribeUpdater, ) { @Operation(summary = "[구버전] 최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") @PostMapping("/token/v1/dmu/initToken") fun oldTokenSubscribe(@RequestBody oldRegisterSubscribeRequest: OldRegisterSubscribeRequest): ResponseEntity { subscribeWriter.write(oldRegisterSubscribeRequest.toSubscribe()) - return ResponseEntity.status(HttpStatus.CREATED).build() + return ResponseEntity.ok().build() + } + + @Operation(summary = "[구버전] 학사 알림 구독", description = "학사 알림을 받도록 설정한다.") + @PostMapping("/department/v1/dmu/updateDepartment") + fun oldDepartmentSubscribe(@RequestBody departmentRequest: OldDepartmentRequest): ResponseEntity { + subscribeUpdater.subscribeDepartment(token = departmentRequest.token, department = departmentRequest.department) + return ResponseEntity.ok().build() + } + + @Operation(summary = "[구버전] 학사 알림 구독해제", description = "학사 알림을 받지 않도록 설정한다.") + @PostMapping("/department/v1/dmu/deleteDepartment") + fun oldDepartmentUnsubscribe(@RequestBody tokenRequest: OldTokenRequest): ResponseEntity { + subscribeUpdater.unsubscribeDepartment(token = tokenRequest.token) + return ResponseEntity.ok().build() + } + + @Operation(summary = "[구버전] 키워드 알림 구독", description = "키워드 알림을 받도록 설정한다.") + @PostMapping("/token/v1/dmu/updateTopic") + fun oldKeywordsSubscribe(@RequestBody keywordsRequest: OldKeywordsSubscribeRequest): ResponseEntity { + subscribeUpdater.subscribeKeywords(token = keywordsRequest.token, keywords = keywordsRequest.topics) + return ResponseEntity.ok().build() + } + + @Operation(summary = "[구버전] 키워드 알림 구독해제", description = "키워드 알림을 받지 않도록 설정한다.") + @PostMapping("/token/v1/dmu/deleteTopic") + fun oldKeywordsUnsubscribe(@RequestBody tokenRequest: OldTokenRequest): ResponseEntity { + subscribeUpdater.unsubscribeKeywords(token = tokenRequest.token) + return ResponseEntity.ok().build() } @Operation(summary = "최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") @@ -29,4 +58,5 @@ class SubscribeController( subscribeWriter.write(registerSubscribeRequest.toSubscribe()) return ResponseEntity.status(HttpStatus.CREATED).build() } -} \ No newline at end of file +} + diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldDepartmentRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldDepartmentRequest.kt new file mode 100644 index 0000000..ef6a2eb --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldDepartmentRequest.kt @@ -0,0 +1,6 @@ +package com.dmforu.api.controller.v1.request + +data class OldDepartmentRequest( + val token: String, + val department: String, +) \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldKeywordsSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldKeywordsSubscribeRequest.kt new file mode 100644 index 0000000..a9c007d --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldKeywordsSubscribeRequest.kt @@ -0,0 +1,6 @@ +package com.dmforu.api.controller.v1.request + +data class OldKeywordsSubscribeRequest ( + val token: String, + val topics: List +) \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldTokenRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldTokenRequest.kt new file mode 100644 index 0000000..181e17d --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldTokenRequest.kt @@ -0,0 +1,5 @@ +package com.dmforu.api.controller.v1.request + +data class OldTokenRequest( + val token: String, +) \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt new file mode 100644 index 0000000..17aef3c --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt @@ -0,0 +1,8 @@ +package com.dmforu.domain.subscribe + +interface OldSubscribeRepository { + fun findByIdAndSubscribeDepartment(token: String, department: String) + fun findByIdAndUnsubscribeDepartment(token: String) + fun findByIdAndSubscribeKeywords(token: String, keywords: List) + fun findByIdAndUnsubscribeKeywords(token: String) +} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt new file mode 100644 index 0000000..06680fd --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt @@ -0,0 +1,30 @@ +package com.dmforu.domain.subscribe + +import org.springframework.stereotype.Service + +@Service +class OldSubscribeUpdater( + private val subscribeRepository: OldSubscribeRepository, +) { + fun subscribeDepartment(token: String, department: String) { + subscribeRepository.findByIdAndSubscribeDepartment( + token = token, + department = department + ) + } + + fun unsubscribeDepartment(token: String) { + subscribeRepository.findByIdAndUnsubscribeDepartment(token = token) + } + + fun subscribeKeywords(token: String, keywords: List) { + subscribeRepository.findByIdAndSubscribeKeywords( + token = token, + keywords = keywords + ) + } + + fun unsubscribeKeywords(token: String) { + subscribeRepository.findByIdAndUnsubscribeKeywords(token = token) + } +} \ No newline at end of file diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt index cf5b01e..2e05e12 100644 --- a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt @@ -1,15 +1,53 @@ package com.dmforu.storage.db.mysql.subscribe +import com.dmforu.domain.subscribe.OldSubscribeRepository import com.dmforu.domain.subscribe.Subscribe import com.dmforu.domain.subscribe.SubscribeRepository +import jakarta.transaction.Transactional import org.springframework.stereotype.Repository @Repository internal class SubscribeEntityRepository( private val subscribeJpaRepository: SubscribeJpaRepository, -) : SubscribeRepository { +) : SubscribeRepository, OldSubscribeRepository { override fun save(subscribe: Subscribe) { subscribeJpaRepository.save(SubscribeEntity.from(subscribe)) } + @Transactional + override fun findByIdAndSubscribeDepartment(token: String, department: String) { + val subscribe = findNotNullById(token) + + subscribe.changeDepartment(department) + + subscribe.subscribeDepartment() + } + + @Transactional + override fun findByIdAndUnsubscribeDepartment(token: String) { + val subscribe = findNotNullById(token) + + subscribe.unsubscribeDepartment() + } + + @Transactional + override fun findByIdAndSubscribeKeywords(token: String, keywords: List) { + val subscribe = findNotNullById(token) + + subscribe.changeKeywords(keywords) + + subscribe.subscribeKeywords() + } + + @Transactional + override fun findByIdAndUnsubscribeKeywords(token: String) { + val subscribe = findNotNullById(token) + + subscribe.unsubscribeKeywords() + } + + private fun findNotNullById(token: String): SubscribeEntity { + return subscribeJpaRepository.findById(token).orElseThrow { throw IllegalArgumentException("존재하지 않은 토큰입니다.") } + } + } \ No newline at end of file From 1acacd22fad2c5fea9bdc71d706082966abbdeba Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:52:51 +0900 Subject: [PATCH 057/223] =?UTF-8?q?feat:=20SubscribeEntity=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=EB=A5=BC=20=EC=83=81=ED=83=9C=EB=B3=80=ED=99=94=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../db/mysql/subscribe/SubscribeEntity.kt | 51 ++++++++++++++++--- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt index 0b04ff2..6573d8f 100644 --- a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt @@ -2,10 +2,7 @@ package com.dmforu.storage.db.mysql.subscribe import com.dmforu.domain.subscribe.Subscribe import com.dmforu.storage.db.mysql.converter.StringListConverter -import jakarta.persistence.Convert -import jakarta.persistence.Entity -import jakarta.persistence.Id -import jakarta.persistence.Table +import jakarta.persistence.* @Table(name = "token") @@ -14,14 +11,18 @@ internal class SubscribeEntity( @Id val token: String, - val department: String, + @Column(nullable = true) + var department: String, @Convert(converter = StringListConverter::class) - val keywords: List?, + @Column(name = "keywords_list",nullable = true) + var keywords: List, - val isDepartmentSubscribed: Boolean, + @Column(name = "department_onoff") + var isDepartmentSubscribed: Boolean, - val areKeywordsSubscribed: Boolean, + @Column(name = "keyword_onoff") + var areKeywordsSubscribed: Boolean, ) { constructor() : this("", "", emptyList(), false, false) @@ -36,4 +37,38 @@ internal class SubscribeEntity( ) } } + + fun toSubscribe(): Subscribe { + return Subscribe( + token = token, + department = department, + keywords = keywords, + isDepartmentSubscribed = isDepartmentSubscribed, + areKeywordsSubscribed = areKeywordsSubscribed + ) + } + + fun changeDepartment(department: String) { + this.department = department + } + + fun subscribeDepartment() { + this.isDepartmentSubscribed = true + } + + fun unsubscribeDepartment() { + this.isDepartmentSubscribed = false + } + + fun changeKeywords(keywords: List) { + this.keywords = keywords + } + + fun subscribeKeywords() { + this.areKeywordsSubscribed = true + } + + fun unsubscribeKeywords() { + this.areKeywordsSubscribed = false + } } \ No newline at end of file From 0cb9231e1926ecc7f7bc74114ae63be81b04f1e4 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:57:04 +0900 Subject: [PATCH 058/223] =?UTF-8?q?refactor:=20=EA=B5=AC=EB=B2=84=EC=A0=84?= =?UTF-8?q?=20Subscribe=20Controller=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/old/OldSubscribeController.kt | 56 +++++++++++++++++++ .../request/OldDepartmentRequest.kt | 2 +- .../request/OldKeywordsSubscribeRequest.kt | 2 +- .../request/OldRegisterSubscribeRequest.kt | 2 +- .../{v1 => old}/request/OldTokenRequest.kt | 2 +- .../request/RegisterSubscribeRequest.kt | 2 +- .../api/controller/v1/SubscribeController.kt | 39 +------------ 7 files changed, 62 insertions(+), 43 deletions(-) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldSubscribeController.kt rename dmforu-api/src/main/kotlin/com/dmforu/api/controller/{v1 => old}/request/OldDepartmentRequest.kt (65%) rename dmforu-api/src/main/kotlin/com/dmforu/api/controller/{v1 => old}/request/OldKeywordsSubscribeRequest.kt (67%) rename dmforu-api/src/main/kotlin/com/dmforu/api/controller/{v1 => old}/request/OldRegisterSubscribeRequest.kt (92%) rename dmforu-api/src/main/kotlin/com/dmforu/api/controller/{v1 => old}/request/OldTokenRequest.kt (53%) rename dmforu-api/src/main/kotlin/com/dmforu/api/controller/{v1 => old}/request/RegisterSubscribeRequest.kt (92%) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldSubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldSubscribeController.kt new file mode 100644 index 0000000..c919818 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldSubscribeController.kt @@ -0,0 +1,56 @@ +package com.dmforu.api.controller.old + +import com.dmforu.api.controller.old.request.OldDepartmentRequest +import com.dmforu.api.controller.old.request.OldKeywordsSubscribeRequest +import com.dmforu.api.controller.old.request.OldRegisterSubscribeRequest +import com.dmforu.api.controller.old.request.OldTokenRequest +import com.dmforu.domain.subscribe.OldSubscribeUpdater +import com.dmforu.domain.subscribe.SubscribeWriter +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RestController + +@Tag(name = "[구버전] 알림 설정") +@RestController +class OldSubscribeController( + private val subscribeWriter: SubscribeWriter, + private val subscribeUpdater: OldSubscribeUpdater, +) { + @Operation(summary = "[구버전] 최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") + @PostMapping("/token/v1/dmu/initToken") + fun oldTokenSubscribe(@RequestBody oldRegisterSubscribeRequest: OldRegisterSubscribeRequest): ResponseEntity { + subscribeWriter.write(oldRegisterSubscribeRequest.toSubscribe()) + return ResponseEntity.ok().build() + } + + @Operation(summary = "[구버전] 학사 알림 구독", description = "학사 알림을 받도록 설정한다.") + @PostMapping("/department/v1/dmu/updateDepartment") + fun oldDepartmentSubscribe(@RequestBody departmentRequest: OldDepartmentRequest): ResponseEntity { + subscribeUpdater.subscribeDepartment(token = departmentRequest.token, department = departmentRequest.department) + return ResponseEntity.ok().build() + } + + @Operation(summary = "[구버전] 학사 알림 구독해제", description = "학사 알림을 받지 않도록 설정한다.") + @PostMapping("/department/v1/dmu/deleteDepartment") + fun oldDepartmentUnsubscribe(@RequestBody tokenRequest: OldTokenRequest): ResponseEntity { + subscribeUpdater.unsubscribeDepartment(token = tokenRequest.token) + return ResponseEntity.ok().build() + } + + @Operation(summary = "[구버전] 키워드 알림 구독", description = "키워드 알림을 받도록 설정한다.") + @PostMapping("/token/v1/dmu/updateTopic") + fun oldKeywordsSubscribe(@RequestBody keywordsRequest: OldKeywordsSubscribeRequest): ResponseEntity { + subscribeUpdater.subscribeKeywords(token = keywordsRequest.token, keywords = keywordsRequest.topics) + return ResponseEntity.ok().build() + } + + @Operation(summary = "[구버전] 키워드 알림 구독해제", description = "키워드 알림을 받지 않도록 설정한다.") + @PostMapping("/token/v1/dmu/deleteTopic") + fun oldKeywordsUnsubscribe(@RequestBody tokenRequest: OldTokenRequest): ResponseEntity { + subscribeUpdater.unsubscribeKeywords(token = tokenRequest.token) + return ResponseEntity.ok().build() + } +} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldDepartmentRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldDepartmentRequest.kt similarity index 65% rename from dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldDepartmentRequest.kt rename to dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldDepartmentRequest.kt index ef6a2eb..83e2d2e 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldDepartmentRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldDepartmentRequest.kt @@ -1,4 +1,4 @@ -package com.dmforu.api.controller.v1.request +package com.dmforu.api.controller.old.request data class OldDepartmentRequest( val token: String, diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldKeywordsSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldKeywordsSubscribeRequest.kt similarity index 67% rename from dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldKeywordsSubscribeRequest.kt rename to dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldKeywordsSubscribeRequest.kt index a9c007d..d2f3216 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldKeywordsSubscribeRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldKeywordsSubscribeRequest.kt @@ -1,4 +1,4 @@ -package com.dmforu.api.controller.v1.request +package com.dmforu.api.controller.old.request data class OldKeywordsSubscribeRequest ( val token: String, diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldRegisterSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt similarity index 92% rename from dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldRegisterSubscribeRequest.kt rename to dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt index 2f3be34..602ffbb 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldRegisterSubscribeRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt @@ -1,4 +1,4 @@ -package com.dmforu.api.controller.v1.request +package com.dmforu.api.controller.old.request import com.dmforu.domain.subscribe.Subscribe diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldTokenRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldTokenRequest.kt similarity index 53% rename from dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldTokenRequest.kt rename to dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldTokenRequest.kt index 181e17d..1a55706 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/OldTokenRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldTokenRequest.kt @@ -1,4 +1,4 @@ -package com.dmforu.api.controller.v1.request +package com.dmforu.api.controller.old.request data class OldTokenRequest( val token: String, diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/RegisterSubscribeRequest.kt similarity index 92% rename from dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt rename to dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/RegisterSubscribeRequest.kt index 4de5433..3133e66 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/RegisterSubscribeRequest.kt @@ -1,4 +1,4 @@ -package com.dmforu.api.controller.v1.request +package com.dmforu.api.controller.old.request import com.dmforu.domain.subscribe.Subscribe diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt index be97f32..78ceb51 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt @@ -1,7 +1,6 @@ package com.dmforu.api.controller.v1 -import com.dmforu.api.controller.v1.request.* -import com.dmforu.domain.subscribe.OldSubscribeUpdater +import com.dmforu.api.controller.old.request.RegisterSubscribeRequest import com.dmforu.domain.subscribe.SubscribeWriter import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag @@ -15,43 +14,7 @@ import org.springframework.web.bind.annotation.RestController @RestController class SubscribeController( private val subscribeWriter: SubscribeWriter, - private val subscribeUpdater: OldSubscribeUpdater, ) { - @Operation(summary = "[구버전] 최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") - @PostMapping("/token/v1/dmu/initToken") - fun oldTokenSubscribe(@RequestBody oldRegisterSubscribeRequest: OldRegisterSubscribeRequest): ResponseEntity { - subscribeWriter.write(oldRegisterSubscribeRequest.toSubscribe()) - return ResponseEntity.ok().build() - } - - @Operation(summary = "[구버전] 학사 알림 구독", description = "학사 알림을 받도록 설정한다.") - @PostMapping("/department/v1/dmu/updateDepartment") - fun oldDepartmentSubscribe(@RequestBody departmentRequest: OldDepartmentRequest): ResponseEntity { - subscribeUpdater.subscribeDepartment(token = departmentRequest.token, department = departmentRequest.department) - return ResponseEntity.ok().build() - } - - @Operation(summary = "[구버전] 학사 알림 구독해제", description = "학사 알림을 받지 않도록 설정한다.") - @PostMapping("/department/v1/dmu/deleteDepartment") - fun oldDepartmentUnsubscribe(@RequestBody tokenRequest: OldTokenRequest): ResponseEntity { - subscribeUpdater.unsubscribeDepartment(token = tokenRequest.token) - return ResponseEntity.ok().build() - } - - @Operation(summary = "[구버전] 키워드 알림 구독", description = "키워드 알림을 받도록 설정한다.") - @PostMapping("/token/v1/dmu/updateTopic") - fun oldKeywordsSubscribe(@RequestBody keywordsRequest: OldKeywordsSubscribeRequest): ResponseEntity { - subscribeUpdater.subscribeKeywords(token = keywordsRequest.token, keywords = keywordsRequest.topics) - return ResponseEntity.ok().build() - } - - @Operation(summary = "[구버전] 키워드 알림 구독해제", description = "키워드 알림을 받지 않도록 설정한다.") - @PostMapping("/token/v1/dmu/deleteTopic") - fun oldKeywordsUnsubscribe(@RequestBody tokenRequest: OldTokenRequest): ResponseEntity { - subscribeUpdater.unsubscribeKeywords(token = tokenRequest.token) - return ResponseEntity.ok().build() - } - @Operation(summary = "최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") @PostMapping("/api/v1/subscribe/registration") fun tokenSubscribe(@RequestBody registerSubscribeRequest: RegisterSubscribeRequest): ResponseEntity { From 9c133f2f0513ea8f0aa7db14f1b7277842fb433a Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:50:21 +0900 Subject: [PATCH 059/223] =?UTF-8?q?style:=20=ED=95=84=EB=93=9C=EB=AA=85=20?= =?UTF-8?q?areKeywrodsSubscribed=20->=20isKeywordSubscribed=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/OldRegisterSubscribeRequest.kt | 2 +- .../old/request/RegisterSubscribeRequest.kt | 2 +- .../com/dmforu/domain/subscribe/Subscribe.kt | 10 ++++----- .../db/mysql/subscribe/SubscribeEntity.kt | 22 +++++-------------- 4 files changed, 13 insertions(+), 23 deletions(-) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt index 602ffbb..c336ab9 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt @@ -16,7 +16,7 @@ data class OldRegisterSubscribeRequest( department = department, keywords = topic, isDepartmentSubscribed = isDepartmentSubscribed, - areKeywordsSubscribed = areKeywordsSubscribed + isKeywordSubscribed = areKeywordsSubscribed ) } } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/RegisterSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/RegisterSubscribeRequest.kt index 3133e66..c2c42bb 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/RegisterSubscribeRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/RegisterSubscribeRequest.kt @@ -15,7 +15,7 @@ data class RegisterSubscribeRequest ( department = department, keywords = keywords, isDepartmentSubscribed = isDepartmentSubscribed, - areKeywordsSubscribed = areKeywordSubscribed + isKeywordSubscribed = areKeywordSubscribed ) } } diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt index 7bc6437..425a1d4 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt @@ -5,7 +5,7 @@ data class Subscribe( var department: String, var keywords: List, var isDepartmentSubscribed: Boolean, - var areKeywordsSubscribed: Boolean, + var isKeywordSubscribed: Boolean, ) { fun subscribeDepartment() { this.isDepartmentSubscribed = true; @@ -15,11 +15,11 @@ data class Subscribe( this.isDepartmentSubscribed = false; } - fun subscribeKeywords() { - this.areKeywordsSubscribed = true; + fun subscribeKeyword() { + this.isKeywordSubscribed = true; } - fun unsubscribeKeywords() { - this.areKeywordsSubscribed = false; + fun unsubscribeKeyword() { + this.isKeywordSubscribed = false; } } \ No newline at end of file diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt index 6573d8f..16c247f 100644 --- a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt @@ -22,7 +22,7 @@ internal class SubscribeEntity( var isDepartmentSubscribed: Boolean, @Column(name = "keyword_onoff") - var areKeywordsSubscribed: Boolean, + var isKeywordSubscribed: Boolean, ) { constructor() : this("", "", emptyList(), false, false) @@ -33,21 +33,11 @@ internal class SubscribeEntity( department = subscribe.department, keywords = subscribe.keywords, isDepartmentSubscribed = false, - areKeywordsSubscribed = false + isKeywordSubscribed = false ) } } - fun toSubscribe(): Subscribe { - return Subscribe( - token = token, - department = department, - keywords = keywords, - isDepartmentSubscribed = isDepartmentSubscribed, - areKeywordsSubscribed = areKeywordsSubscribed - ) - } - fun changeDepartment(department: String) { this.department = department } @@ -64,11 +54,11 @@ internal class SubscribeEntity( this.keywords = keywords } - fun subscribeKeywords() { - this.areKeywordsSubscribed = true + fun subscribeKeyword() { + this.isKeywordSubscribed = true } - fun unsubscribeKeywords() { - this.areKeywordsSubscribed = false + fun unsubscribeKeyword() { + this.isKeywordSubscribed = false } } \ No newline at end of file From 9ec4c72b16fd6cf97c50aa9eb30dddc9514ae233 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:11:21 +0900 Subject: [PATCH 060/223] =?UTF-8?q?feat:=20=ED=82=A4=EC=9B=8C=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=ED=82=A4=EC=9B=8C=EB=93=9C=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=20=EC=83=81=ED=83=9C=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/v1/SubscribeController.kt | 19 +++++++++++++++++ .../UpdateKeywordSubscribeStatusRequest.kt | 6 ++++++ .../request/UpdateSubscribeKeywordsRequest.kt | 6 ++++++ .../domain/subscribe/SubscribeRepository.kt | 3 +++ .../domain/subscribe/SubscribeUpdater.kt | 21 +++++++++++++++++++ .../subscribe/SubscribeEntityRepository.kt | 20 +++++++++++++++--- 6 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateKeywordSubscribeStatusRequest.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeKeywordsRequest.kt create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt index 78ceb51..58352cb 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt @@ -1,11 +1,15 @@ package com.dmforu.api.controller.v1 import com.dmforu.api.controller.old.request.RegisterSubscribeRequest +import com.dmforu.api.controller.v1.request.UpdateKeywordSubscribeStatusRequest +import com.dmforu.api.controller.v1.request.UpdateSubscribeKeywordsRequest +import com.dmforu.domain.subscribe.SubscribeUpdater import com.dmforu.domain.subscribe.SubscribeWriter import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.PatchMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RestController @@ -14,6 +18,7 @@ import org.springframework.web.bind.annotation.RestController @RestController class SubscribeController( private val subscribeWriter: SubscribeWriter, + private val subscribeUpdater: SubscribeUpdater ) { @Operation(summary = "최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") @PostMapping("/api/v1/subscribe/registration") @@ -21,5 +26,19 @@ class SubscribeController( subscribeWriter.write(registerSubscribeRequest.toSubscribe()) return ResponseEntity.status(HttpStatus.CREATED).build() } + + @Operation(summary = "키워드 수정 API", description = "알림 키워드를 수정한다.") + @PatchMapping("/api/v1/subscribe/keywords") + fun updateSubscribeKeywords(@RequestBody request: UpdateSubscribeKeywordsRequest): ResponseEntity { + subscribeUpdater.updateKeywords(request.token, request.keywords) + return ResponseEntity.status(HttpStatus.NO_CONTENT).build() + } + + @Operation(summary = "키워드 알림 상태 API", description = "키워드 알림 상태를 수정한다.") + @PatchMapping("/api/v1/subscribe/keyword/status") + fun updateSubscribeKeywordStatus(@RequestBody request: UpdateKeywordSubscribeStatusRequest): ResponseEntity { + subscribeUpdater.updateKeywordSubscribeStatus(request.token, request.isSubscribed) + return ResponseEntity.status(HttpStatus.NO_CONTENT).build() + } } diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateKeywordSubscribeStatusRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateKeywordSubscribeStatusRequest.kt new file mode 100644 index 0000000..2d9ee95 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateKeywordSubscribeStatusRequest.kt @@ -0,0 +1,6 @@ +package com.dmforu.api.controller.v1.request + +data class UpdateKeywordSubscribeStatusRequest ( + val token: String, + val isSubscribed: Boolean +) \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeKeywordsRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeKeywordsRequest.kt new file mode 100644 index 0000000..5f95a5c --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeKeywordsRequest.kt @@ -0,0 +1,6 @@ +package com.dmforu.api.controller.v1.request + +data class UpdateSubscribeKeywordsRequest( + val token: String, + val keywords: List +) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt index 3fa57d1..9b5d28b 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt @@ -2,4 +2,7 @@ package com.dmforu.domain.subscribe interface SubscribeRepository { fun save(subscribe: Subscribe) + fun findByIdAndUpdateKeywords(token: String, keywords: List) + fun findByIdAndUpdateKeywordSubscribe(token: String) + fun findByIdAndUpdateKeywordUnsubscribe(token: String) } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt new file mode 100644 index 0000000..92f005a --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt @@ -0,0 +1,21 @@ +package com.dmforu.domain.subscribe + +import org.springframework.stereotype.Service + +@Service +class SubscribeUpdater( + private val subscribeRepository: SubscribeRepository, +) { + fun updateKeywords(token: String, keywords: List) { + subscribeRepository.findByIdAndUpdateKeywords(token, keywords) + } + + fun updateKeywordSubscribeStatus(token: String, keywordSubscribeStatus: Boolean) { + if (keywordSubscribeStatus) { + subscribeRepository.findByIdAndUpdateKeywordSubscribe(token) + return + } + + subscribeRepository.findByIdAndUpdateKeywordUnsubscribe(token) + } +} \ No newline at end of file diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt index 2e05e12..63e2496 100644 --- a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt @@ -36,14 +36,28 @@ internal class SubscribeEntityRepository( subscribe.changeKeywords(keywords) - subscribe.subscribeKeywords() + subscribe.subscribeKeyword() } @Transactional - override fun findByIdAndUnsubscribeKeywords(token: String) { + override fun findByIdAndUpdateKeywords(token: String, keywords: List) { val subscribe = findNotNullById(token) - subscribe.unsubscribeKeywords() + subscribe.changeKeywords(keywords) + } + + @Transactional + override fun findByIdAndUpdateKeywordSubscribe(token: String) { + val subscribe = findNotNullById(token) + + subscribe.subscribeKeyword() + } + + @Transactional + override fun findByIdAndUpdateKeywordUnsubscribe(token: String) { + val subscribe = findNotNullById(token) + + subscribe.unsubscribeKeyword() } private fun findNotNullById(token: String): SubscribeEntity { From 1e683fa3367b71ce10c2ef8d914316b0a414657f Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:17:04 +0900 Subject: [PATCH 061/223] =?UTF-8?q?fix:=20=EB=88=84=EB=9D=BD=EB=90=9C=20?= =?UTF-8?q?=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/subscribe/OldSubscribeRepository.kt | 4 ++-- .../kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt index 17aef3c..f276274 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt @@ -2,7 +2,7 @@ package com.dmforu.domain.subscribe interface OldSubscribeRepository { fun findByIdAndSubscribeDepartment(token: String, department: String) - fun findByIdAndUnsubscribeDepartment(token: String) fun findByIdAndSubscribeKeywords(token: String, keywords: List) - fun findByIdAndUnsubscribeKeywords(token: String) + fun findByIdAndUnsubscribeDepartment(token: String) + fun findByIdAndUpdateKeywordUnsubscribe(token: String) } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt index 06680fd..c739e36 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt @@ -25,6 +25,6 @@ class OldSubscribeUpdater( } fun unsubscribeKeywords(token: String) { - subscribeRepository.findByIdAndUnsubscribeKeywords(token = token) + subscribeRepository.findByIdAndUpdateKeywordUnsubscribe(token = token) } } \ No newline at end of file From 7475c1c18ca90682a7037b3ad2c211e0b4c45f38 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:18:26 +0900 Subject: [PATCH 062/223] =?UTF-8?q?chore:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=EC=97=90=20=EC=9D=B4=EB=8F=99?= =?UTF-8?q?=EC=8B=9C=ED=82=A8=20Request=20=EC=9B=90=EB=9E=98=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/api/controller/v1/SubscribeController.kt | 2 +- .../controller/{old => v1}/request/RegisterSubscribeRequest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename dmforu-api/src/main/kotlin/com/dmforu/api/controller/{old => v1}/request/RegisterSubscribeRequest.kt (92%) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt index 58352cb..dcd0e8c 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt @@ -1,6 +1,6 @@ package com.dmforu.api.controller.v1 -import com.dmforu.api.controller.old.request.RegisterSubscribeRequest +import com.dmforu.api.controller.v1.request.RegisterSubscribeRequest import com.dmforu.api.controller.v1.request.UpdateKeywordSubscribeStatusRequest import com.dmforu.api.controller.v1.request.UpdateSubscribeKeywordsRequest import com.dmforu.domain.subscribe.SubscribeUpdater diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/RegisterSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt similarity index 92% rename from dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/RegisterSubscribeRequest.kt rename to dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt index c2c42bb..3f25ded 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/RegisterSubscribeRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt @@ -1,4 +1,4 @@ -package com.dmforu.api.controller.old.request +package com.dmforu.api.controller.v1.request import com.dmforu.domain.subscribe.Subscribe From 8404f0325df5f767a975591bea7a01ee9f591234 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 11 Oct 2024 17:05:04 +0900 Subject: [PATCH 063/223] =?UTF-8?q?feat:=20=ED=95=99=EA=B3=BC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=ED=95=99=EA=B3=BC=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EC=83=81=ED=83=9C=20=EB=B3=80=EA=B2=BD=20API=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DepartmentNoticeCrawlingService.kt | 2 +- .../api/controller/v1/SubscribeController.kt | 22 ++++++++++++++----- .../UpdateSubscribeDepartmentRequest.kt | 6 +++++ ...est.kt => UpdateSubscribeStatusRequest.kt} | 2 +- .../subscribe/OldSubscribeRepository.kt | 3 ++- .../domain/subscribe/OldSubscribeUpdater.kt | 2 +- .../domain/subscribe/SubscribeRepository.kt | 5 +++++ .../domain/subscribe/SubscribeUpdater.kt | 13 +++++++++++ .../subscribe/SubscribeEntityRepository.kt | 19 +++++++++++++++- 9 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeDepartmentRequest.kt rename dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/{UpdateKeywordSubscribeStatusRequest.kt => UpdateSubscribeStatusRequest.kt} (67%) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index 9e57e48..56ea1d2 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -33,7 +33,7 @@ class DepartmentNoticeCrawlingService( * @param major 학과 정보 */ private fun crawlMajorDepartment(major: Major) { - val parser = prototypeBeanProvider.getObject(major) + val parser = prototypeBeanProvider.getObject() parser.initialize(major) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt index dcd0e8c..e256508 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt @@ -1,8 +1,6 @@ package com.dmforu.api.controller.v1 -import com.dmforu.api.controller.v1.request.RegisterSubscribeRequest -import com.dmforu.api.controller.v1.request.UpdateKeywordSubscribeStatusRequest -import com.dmforu.api.controller.v1.request.UpdateSubscribeKeywordsRequest +import com.dmforu.api.controller.v1.request.* import com.dmforu.domain.subscribe.SubscribeUpdater import com.dmforu.domain.subscribe.SubscribeWriter import io.swagger.v3.oas.annotations.Operation @@ -34,11 +32,25 @@ class SubscribeController( return ResponseEntity.status(HttpStatus.NO_CONTENT).build() } - @Operation(summary = "키워드 알림 상태 API", description = "키워드 알림 상태를 수정한다.") + @Operation(summary = "키워드 알림 상태 변경 API", description = "키워드 알림 상태를 변경한다.") @PatchMapping("/api/v1/subscribe/keyword/status") - fun updateSubscribeKeywordStatus(@RequestBody request: UpdateKeywordSubscribeStatusRequest): ResponseEntity { + fun updateSubscribeKeywordStatus(@RequestBody request: UpdateSubscribeStatusRequest): ResponseEntity { subscribeUpdater.updateKeywordSubscribeStatus(request.token, request.isSubscribed) return ResponseEntity.status(HttpStatus.NO_CONTENT).build() } + + @Operation(summary = "학과 수정 API", description = "학과 정보를 수정한다.") + @PatchMapping("/api/v1/subscribe/department") + fun updateSubscribeDepartment(@RequestBody request: UpdateSubscribeDepartmentRequest): ResponseEntity { + subscribeUpdater.updateDepartment(request.token, request.department) + return ResponseEntity.status(HttpStatus.NO_CONTENT).build() + } + + @Operation(summary = "학과 알림 상태 변경 API", description = "학과 알림 상태를 변경한다.") + @PatchMapping("/api/v1/subscribe/department/status") + fun updateSubscribeDepartmentStatus(@RequestBody request: UpdateSubscribeStatusRequest): ResponseEntity { + subscribeUpdater.updateDepartmentSubscribeStatus(token = request.token, request.isSubscribed) + return ResponseEntity.status(HttpStatus.NO_CONTENT).build() + } } diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeDepartmentRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeDepartmentRequest.kt new file mode 100644 index 0000000..0f35df2 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeDepartmentRequest.kt @@ -0,0 +1,6 @@ +package com.dmforu.api.controller.v1.request + +data class UpdateSubscribeDepartmentRequest ( + val token: String, + val department: String +) \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateKeywordSubscribeStatusRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeStatusRequest.kt similarity index 67% rename from dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateKeywordSubscribeStatusRequest.kt rename to dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeStatusRequest.kt index 2d9ee95..a1cf615 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateKeywordSubscribeStatusRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeStatusRequest.kt @@ -1,6 +1,6 @@ package com.dmforu.api.controller.v1.request -data class UpdateKeywordSubscribeStatusRequest ( +data class UpdateSubscribeStatusRequest ( val token: String, val isSubscribed: Boolean ) \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt index f276274..8e23c77 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt @@ -2,7 +2,8 @@ package com.dmforu.domain.subscribe interface OldSubscribeRepository { fun findByIdAndSubscribeDepartment(token: String, department: String) + fun findByIdAndUpdateDepartmentUnsubscribe(token: String) + fun findByIdAndSubscribeKeywords(token: String, keywords: List) - fun findByIdAndUnsubscribeDepartment(token: String) fun findByIdAndUpdateKeywordUnsubscribe(token: String) } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt index c739e36..47c4397 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt @@ -14,7 +14,7 @@ class OldSubscribeUpdater( } fun unsubscribeDepartment(token: String) { - subscribeRepository.findByIdAndUnsubscribeDepartment(token = token) + subscribeRepository.findByIdAndUpdateDepartmentUnsubscribe(token = token) } fun subscribeKeywords(token: String, keywords: List) { diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt index 9b5d28b..290d8f6 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt @@ -2,7 +2,12 @@ package com.dmforu.domain.subscribe interface SubscribeRepository { fun save(subscribe: Subscribe) + fun findByIdAndUpdateKeywords(token: String, keywords: List) fun findByIdAndUpdateKeywordSubscribe(token: String) fun findByIdAndUpdateKeywordUnsubscribe(token: String) + + fun findByIdAndUpdateDepartment(token: String, department: String) + fun findByIdAndUpdateDepartmentSubscribe(token: String) + fun findByIdAndUpdateDepartmentUnsubscribe(token: String) } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt index 92f005a..029db08 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt @@ -18,4 +18,17 @@ class SubscribeUpdater( subscribeRepository.findByIdAndUpdateKeywordUnsubscribe(token) } + + fun updateDepartment(token: String, department: String) { + subscribeRepository.findByIdAndUpdateDepartment(token, department) + } + + fun updateDepartmentSubscribeStatus(token: String, departmentSubscribeStatus: Boolean) { + if (departmentSubscribeStatus) { + subscribeRepository.findByIdAndUpdateDepartmentSubscribe(token) + return + } + + subscribeRepository.findByIdAndUpdateDepartmentUnsubscribe(token) + } } \ No newline at end of file diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt index 63e2496..d0db4c2 100644 --- a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt @@ -10,11 +10,13 @@ import org.springframework.stereotype.Repository internal class SubscribeEntityRepository( private val subscribeJpaRepository: SubscribeJpaRepository, ) : SubscribeRepository, OldSubscribeRepository { + override fun save(subscribe: Subscribe) { subscribeJpaRepository.save(SubscribeEntity.from(subscribe)) } @Transactional + @Deprecated("구버전 호환성을 위해 남겨둔 메서드입니다.") override fun findByIdAndSubscribeDepartment(token: String, department: String) { val subscribe = findNotNullById(token) @@ -24,13 +26,28 @@ internal class SubscribeEntityRepository( } @Transactional - override fun findByIdAndUnsubscribeDepartment(token: String) { + override fun findByIdAndUpdateDepartmentUnsubscribe(token: String) { val subscribe = findNotNullById(token) subscribe.unsubscribeDepartment() } @Transactional + override fun findByIdAndUpdateDepartment(token: String, department: String) { + val subscribe = findNotNullById(token) + + subscribe.changeDepartment(department) + } + + @Transactional + override fun findByIdAndUpdateDepartmentSubscribe(token: String) { + val subscribe = findNotNullById(token) + + subscribe.subscribeDepartment() + } + + @Transactional + @Deprecated("구버전 호환성을 위해 남겨둔 메서드입니다.") override fun findByIdAndSubscribeKeywords(token: String, keywords: List) { val subscribe = findNotNullById(token) From f7ddfa6fc97101c5826348afcda35bf86137153d Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 11 Oct 2024 17:11:24 +0900 Subject: [PATCH 064/223] =?UTF-8?q?style:=20NoticeCrawlWirter=20->=20Notic?= =?UTF-8?q?eCrawlServie=EB=A1=9C=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawling/DepartmentNoticeCrawlingService.kt | 9 ++++----- .../crawling/UniversityNoticeCrawlingService.kt | 8 ++++---- .../{NoticeCrawlWriter.kt => NoticeCrawlService.kt} | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) rename dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/{NoticeCrawlWriter.kt => NoticeCrawlService.kt} (92%) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index 56ea1d2..c08d650 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -3,15 +3,14 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.DepartmentNoticeParser import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.Major -import com.dmforu.domain.notice.NoticeCrawlWriter +import com.dmforu.domain.notice.NoticeCrawlService import org.springframework.beans.factory.ObjectProvider -import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Service @Service class DepartmentNoticeCrawlingService( private val prototypeBeanProvider: ObjectProvider, - private val noticeCrawlWriter: NoticeCrawlWriter + private val noticeCrawlService: NoticeCrawlService ) { /** * Major 열거형의 모든 값을 반복하여 모든 학과의 공지사항을 크롤링한다.

@@ -37,7 +36,7 @@ class DepartmentNoticeCrawlingService( parser.initialize(major) - val maxNumber: Int? = noticeCrawlWriter.findMaxNumberByType(major.type) + val maxNumber: Int? = noticeCrawlService.findMaxNumberByType(major.type) val currentMaxNumber = maxNumber ?: 0 while (true) { @@ -66,7 +65,7 @@ class DepartmentNoticeCrawlingService( return false } - noticeCrawlWriter.write(notice) + noticeCrawlService.write(notice) // TODO: FCM 메세지 전송을 위한 이벤트 트리거 // eventPublisher!!.publishEvent(notice) if (notice.isLastInType()) { diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt index 9562384..b411ee3 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt @@ -2,7 +2,7 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.UniversityNoticeParser import com.dmforu.domain.notice.Notice -import com.dmforu.domain.notice.NoticeCrawlWriter +import com.dmforu.domain.notice.NoticeCrawlService import org.springframework.beans.factory.ObjectProvider import org.springframework.stereotype.Service @@ -10,7 +10,7 @@ import org.springframework.stereotype.Service @Service class UniversityNoticeCrawlingService( private val prototypeBeanProvider: ObjectProvider, - private val noticeCrawlWriter: NoticeCrawlWriter + private val noticeCrawlService: NoticeCrawlService ) { /** * 모든 대학 공지사항을 크롤링한다.

@@ -19,7 +19,7 @@ class UniversityNoticeCrawlingService( */ fun crawling() { val parser: UniversityNoticeParser = prototypeBeanProvider.getObject() - val maxNumber: Int? = noticeCrawlWriter.findMaxNumberByType("대학") + val maxNumber: Int? = noticeCrawlService.findMaxNumberByType("대학") val currentMaxNumber = maxNumber ?: 0 while (true) { @@ -46,7 +46,7 @@ class UniversityNoticeCrawlingService( if (notice.isNumberLessThanOrEqualTo(currentMaxNumber)) { return false } - noticeCrawlWriter.write(notice) + noticeCrawlService.write(notice) // eventPublisher!!.publishEvent(notice) if (notice.isLastInType()) { return false diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlService.kt similarity index 92% rename from dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlWriter.kt rename to dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlService.kt index 0160a39..054353b 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlWriter.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlService.kt @@ -3,7 +3,7 @@ package com.dmforu.domain.notice import org.springframework.stereotype.Component @Component -class NoticeCrawlWriter( +class NoticeCrawlService( private val noticeRepository: NoticeRepository ) { fun findMaxNumberByType(type: String): Int? { From 7a5df228ea30172ba2ad96062e323d1f55dc6b32 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 11 Oct 2024 20:46:12 +0900 Subject: [PATCH 065/223] =?UTF-8?q?chore:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/build.gradle.kts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dmforu-admin/build.gradle.kts b/dmforu-admin/build.gradle.kts index f5e559b..5989c47 100644 --- a/dmforu-admin/build.gradle.kts +++ b/dmforu-admin/build.gradle.kts @@ -11,8 +11,4 @@ dependencies { implementation(project(":dmforu-crawling")) runtimeOnly(project(":dmforu-storage:db-mysql")) runtimeOnly(project(":dmforu-storage:db-redis")) - - // Jackson Library - implementation("com.fasterxml.jackson.core:jackson-databind") - implementation("com.fasterxml.jackson.module:jackson-module-kotlin") } \ No newline at end of file From 128af65630b32363d7ae6d74f230fec5a36dbbb3 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 17 Oct 2024 18:01:16 +0900 Subject: [PATCH 066/223] =?UTF-8?q?feat:=20FCM=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/build.gradle.kts | 2 ++ .../src/main/kotlin/com/dmforu/admin/AdminApplication.kt | 1 + dmforu-fcm/build.gradle.kts | 7 +++++++ settings.gradle.kts | 1 + 4 files changed, 11 insertions(+) create mode 100644 dmforu-fcm/build.gradle.kts diff --git a/dmforu-admin/build.gradle.kts b/dmforu-admin/build.gradle.kts index 5989c47..8fad878 100644 --- a/dmforu-admin/build.gradle.kts +++ b/dmforu-admin/build.gradle.kts @@ -9,6 +9,8 @@ tasks.getByName("jar") { dependencies { implementation(project(":dmforu-domain")) implementation(project(":dmforu-crawling")) + + runtimeOnly(project(":dmforu-fcm")) runtimeOnly(project(":dmforu-storage:db-mysql")) runtimeOnly(project(":dmforu-storage:db-redis")) } \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt index f29014e..a41f52b 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt @@ -9,6 +9,7 @@ import org.springframework.scheduling.annotation.EnableScheduling "com.dmforu.admin", "com.dmforu.domain", "com.dmforu.crawling", + "com.dmforu.fcm", "com.dmforu.storage.db.redis", "com.dmforu.storage.db.mysql" ] diff --git a/dmforu-fcm/build.gradle.kts b/dmforu-fcm/build.gradle.kts new file mode 100644 index 0000000..070542f --- /dev/null +++ b/dmforu-fcm/build.gradle.kts @@ -0,0 +1,7 @@ +dependencies { + compileOnly(project(":dmforu-domain")) + compileOnly(project(":dmforu-admin")) + implementation ("com.google.firebase:firebase-admin:9.2.0") + + compileOnly("org.springframework:spring-context") +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 62b5bd0..28bbb21 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,6 +5,7 @@ include( "dmforu-admin", "dmforu-domain", "dmforu-crawling", + "dmforu-fcm", "dmforu-storage:db-mysql", "dmforu-storage:db-redis" ) From 08235b6668e65622fea7b46222ee0fb74c747768 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 17 Oct 2024 18:03:22 +0900 Subject: [PATCH 067/223] =?UTF-8?q?feat:=20=EA=B5=AC=EB=8F=85=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EC=97=90=20=EB=94=B0=EB=9D=BC=20=ED=86=A0=ED=81=B0?= =?UTF-8?q?=EC=9D=84=20=EB=B6=88=EB=9F=AC=EC=98=A4=EB=8A=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/subscribe/SubscribeRepository.kt | 3 +++ .../db/mysql/subscribe/SubscribeEntityRepository.kt | 8 ++++++++ .../db/mysql/subscribe/SubscribeJpaRepository.kt | 10 ++++++++++ 3 files changed, 21 insertions(+) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt index 290d8f6..146dbc5 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt @@ -10,4 +10,7 @@ interface SubscribeRepository { fun findByIdAndUpdateDepartment(token: String, department: String) fun findByIdAndUpdateDepartmentSubscribe(token: String) fun findByIdAndUpdateDepartmentUnsubscribe(token: String) + + fun findTokensByDepartment(department: String): List + fun findTokensContainingKeyword(keyword: String): List } \ No newline at end of file diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt index d0db4c2..d6cadc7 100644 --- a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt @@ -77,6 +77,14 @@ internal class SubscribeEntityRepository( subscribe.unsubscribeKeyword() } + override fun findTokensByDepartment(department: String): List { + return subscribeJpaRepository.findTokensByDepartment(department) + } + + override fun findTokensContainingKeyword(keyword: String): List { + return subscribeJpaRepository.findTokensContainingKeyword(keyword) + } + private fun findNotNullById(token: String): SubscribeEntity { return subscribeJpaRepository.findById(token).orElseThrow { throw IllegalArgumentException("존재하지 않은 토큰입니다.") } } diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt index 8160a9a..c1831cb 100644 --- a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt +++ b/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt @@ -1,7 +1,17 @@ package com.dmforu.storage.db.mysql.subscribe import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.query.Param internal interface SubscribeJpaRepository : JpaRepository { + @Query("SELECT t.token FROM SubscribeEntity t WHERE t.isDepartmentSubscribed = true AND t.department = :department") + fun findTokensByDepartment(@Param("department") department: String): List + + @Query( + value = "SELECT token.token FROM token WHERE keyword_onoff = true AND keywords_list LIKE %:keyword%", + nativeQuery = true + ) + fun findTokensContainingKeyword(@Param("keyword") keyword: String): List } \ No newline at end of file From b871006580f81ca495e61389ea9d0287058b5267 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 17 Oct 2024 18:05:40 +0900 Subject: [PATCH 068/223] =?UTF-8?q?feat:=20=EB=8C=80=ED=95=99=20=EA=B3=B5?= =?UTF-8?q?=EC=A7=80=EC=9D=B8=EC=A7=80=20=ED=99=95=EC=9D=B8=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/dmforu/domain/notice/Notice.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt index c991fb0..5813e05 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt @@ -28,4 +28,9 @@ data class Notice( fun isLastInType(): Boolean{ return this.number == 1 } + + fun isUniversityNotice(): Boolean{ + return "대학".equals(this.type) + } + } \ No newline at end of file From c6a254435550b8e369231ebf2bd183cd291fa4d2 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:06:54 +0900 Subject: [PATCH 069/223] =?UTF-8?q?feat:=20=EA=B5=AC=EB=8F=85=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EB=B6=88=EB=9F=AC=EC=98=A4=EB=8A=94=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/domain/subscribe/SubscribeReader.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeReader.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeReader.kt new file mode 100644 index 0000000..6502fc3 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeReader.kt @@ -0,0 +1,16 @@ +package com.dmforu.domain.subscribe + +import org.springframework.stereotype.Service + +@Service +class SubscribeReader ( + private val subscribeRepository: SubscribeRepository, +){ + fun getTokensBySubscribedToDepartment(department: String): List { + return subscribeRepository.findTokensByDepartment(department) + } + + fun getTokensBySubscribedToKeyword(keyword: String): List { + return subscribeRepository.findTokensContainingKeyword(keyword) + } +} \ No newline at end of file From 1431d1aadd4fbcc6eef709d6492f6f8098f48272 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:08:04 +0900 Subject: [PATCH 070/223] =?UTF-8?q?feat:=20FCM=20Config=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/fcm/config/FCMConfig.kt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt new file mode 100644 index 0000000..65b4544 --- /dev/null +++ b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt @@ -0,0 +1,32 @@ +package com.dmforu.fcm.config + +import com.google.auth.oauth2.GoogleCredentials +import com.google.firebase.FirebaseApp +import com.google.firebase.FirebaseOptions +import com.google.firebase.messaging.FirebaseMessaging +import org.springframework.boot.autoconfigure.domain.EntityScan +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.core.io.ClassPathResource +import org.springframework.core.io.Resource +import org.springframework.util.FileCopyUtils +import java.io.ByteArrayInputStream +import java.io.IOException +import java.nio.charset.StandardCharsets + +@Configuration +@EntityScan(basePackages = ["com.dmforu.fcm"]) +class FCMConfig { + @Bean + @Throws(IOException::class) + fun someAppProdFirebaseApp(): FirebaseApp { + val credentials = GoogleCredentials.fromStream(ClassPathResource("key/fire-base-key.json").inputStream) + + val options = FirebaseOptions + .builder() + .setCredentials(credentials) + .build() + + return FirebaseApp.initializeApp(options, "DMFORU_APP_PROD") + } +} \ No newline at end of file From e3ee22906befd5d14c855fda195864991dec0b86 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:09:03 +0900 Subject: [PATCH 071/223] =?UTF-8?q?feat:=20FirebaseMessage=20=EC=A0=84?= =?UTF-8?q?=EC=86=A1=20=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/fcm/FirebaseMessageConverter.kt | 24 +++++++++++++++++++ .../com/dmforu/fcm/FirebaseMessageSender.kt | 19 +++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt create mode 100644 dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt new file mode 100644 index 0000000..3119fab --- /dev/null +++ b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt @@ -0,0 +1,24 @@ +package com.dmforu.fcm + +import com.dmforu.admin.message.NoticeMessage +import com.google.firebase.messaging.MulticastMessage +import com.google.firebase.messaging.Notification + +class FirebaseMessageConverter { + + fun buildMessageToNotice(message: NoticeMessage, tokens: List): MulticastMessage { + val notification = Notification.builder() + .setTitle(message.title) + .setBody(message.body) + .build() + + return MulticastMessage.builder() + .setNotification(notification) + .addAllTokens(tokens) + .putData("url", message.url) + .putData("type", message.type) + .build() + } + + +} \ No newline at end of file diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt new file mode 100644 index 0000000..8003f60 --- /dev/null +++ b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt @@ -0,0 +1,19 @@ +package com.dmforu.fcm + +import com.dmforu.admin.message.MessageSender +import com.dmforu.admin.message.NoticeMessage +import com.google.firebase.messaging.FirebaseMessaging + +class FirebaseMessageSender( + private val firebaseMessageConverter: FirebaseMessageConverter, +) : MessageSender { + + override fun sendNoticeMessage(message: NoticeMessage, tokens: List) { + + val firebaseMessage = firebaseMessageConverter.buildMessageToNotice(message, tokens) + + FirebaseMessaging.getInstance().sendEachForMulticast(firebaseMessage) + } + + +} \ No newline at end of file From f012e0d42d7308b749228625009623e7fea2bfdc Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 18 Oct 2024 01:05:53 +0900 Subject: [PATCH 072/223] =?UTF-8?q?feat:=20=EA=B5=AC=ED=98=84=EC=B2=B4?= =?UTF-8?q?=EB=A5=BC=20=EC=88=A8=EA=B8=B8=20MessageSender=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/com/dmforu/admin/message/MessageSender.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageSender.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageSender.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageSender.kt new file mode 100644 index 0000000..9479a96 --- /dev/null +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageSender.kt @@ -0,0 +1,5 @@ +package com.dmforu.admin.message + +interface MessageSender { + fun sendNoticeMessage(message: NoticeMessage, tokens: List) +} \ No newline at end of file From 066ab0d9947d9a7090501cfcf99ceed9f8b9e9ca Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 18 Oct 2024 01:06:50 +0900 Subject: [PATCH 073/223] =?UTF-8?q?feat:=20Notice=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20=EB=8B=B4=EC=9D=84=20Message=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/admin/message/NoticeMessage.kt | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeMessage.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeMessage.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeMessage.kt new file mode 100644 index 0000000..3b5617a --- /dev/null +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeMessage.kt @@ -0,0 +1,43 @@ +package com.dmforu.admin.message + +import com.dmforu.domain.notice.Notice + +class NoticeMessage { + val title: String + val type: String + val body: String + val url: String + + companion object { + fun createUniversityNoticeMessage(notice: Notice, keyword: String): NoticeMessage { + return NoticeMessage(notice, keyword) + } + + fun createDepartmentNoticeMessage(notice: Notice): NoticeMessage { + return NoticeMessage(notice) + } + } + + private constructor(notice: Notice, keyword: String) { + title = initTitleFrom(keyword) + type = notice.type + body = notice.title + url = notice.url + } + + // 학과 공지사항의 경우, "[ 컴퓨터소프트웨어공학과 ] 키워드 알림 도착" 형식으로 제목을 만들어줘야 함 + private constructor(notice: Notice) { + title = initTitleFrom(notice.type) + type = notice.type + body = notice.title + url = notice.url + } + + private fun initTitleFrom(keyword: String): String { + val addedPrefixTitle = StringBuilder() + return addedPrefixTitle + .append("[ ").append(keyword).append(" ] ") + .append(" 키워드 알림 도착").toString() + } +} + From 7a1d0108abbae64a471cc51ab175f0979b7796c2 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 18 Oct 2024 02:31:40 +0900 Subject: [PATCH 074/223] =?UTF-8?q?refactor:=20=EC=A0=91=EA=B7=BC=20?= =?UTF-8?q?=EC=A0=9C=EC=96=B4=EC=9E=90=20internal=EB=A1=9C=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=EC=99=80=20=EA=B2=A9=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt | 4 +++- .../src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt | 4 +++- dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt index 3119fab..8bd7978 100644 --- a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt +++ b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt @@ -3,8 +3,10 @@ package com.dmforu.fcm import com.dmforu.admin.message.NoticeMessage import com.google.firebase.messaging.MulticastMessage import com.google.firebase.messaging.Notification +import org.springframework.stereotype.Component -class FirebaseMessageConverter { +@Component +internal class FirebaseMessageConverter { fun buildMessageToNotice(message: NoticeMessage, tokens: List): MulticastMessage { val notification = Notification.builder() diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt index 8003f60..7954ba1 100644 --- a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt +++ b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt @@ -3,8 +3,10 @@ package com.dmforu.fcm import com.dmforu.admin.message.MessageSender import com.dmforu.admin.message.NoticeMessage import com.google.firebase.messaging.FirebaseMessaging +import org.springframework.stereotype.Component -class FirebaseMessageSender( +@Component +internal class FirebaseMessageSender( private val firebaseMessageConverter: FirebaseMessageConverter, ) : MessageSender { diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt index 65b4544..1218563 100644 --- a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt +++ b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt @@ -16,7 +16,7 @@ import java.nio.charset.StandardCharsets @Configuration @EntityScan(basePackages = ["com.dmforu.fcm"]) -class FCMConfig { +internal class FCMConfig { @Bean @Throws(IOException::class) fun someAppProdFirebaseApp(): FirebaseApp { From 9bad3da428cc27d0c8652e213e4b26115c8f4d77 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 18 Oct 2024 02:31:48 +0900 Subject: [PATCH 075/223] =?UTF-8?q?chore:=20spring-context=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-fcm/build.gradle.kts | 2 -- 1 file changed, 2 deletions(-) diff --git a/dmforu-fcm/build.gradle.kts b/dmforu-fcm/build.gradle.kts index 070542f..b3b2e92 100644 --- a/dmforu-fcm/build.gradle.kts +++ b/dmforu-fcm/build.gradle.kts @@ -2,6 +2,4 @@ dependencies { compileOnly(project(":dmforu-domain")) compileOnly(project(":dmforu-admin")) implementation ("com.google.firebase:firebase-admin:9.2.0") - - compileOnly("org.springframework:spring-context") } \ No newline at end of file From 61fd6f3b33bd3c148929f8acfcc4caa6bca9a7f3 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 18 Oct 2024 02:32:48 +0900 Subject: [PATCH 076/223] =?UTF-8?q?feat:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=A0=9C=EB=AA=A9=EC=9D=84=20=ED=95=84=ED=84=B0?= =?UTF-8?q?=EB=A7=81=ED=95=98=EC=97=AC=20=EB=A9=94=EC=84=B8=EC=A7=80?= =?UTF-8?q?=EB=A5=BC=20=EB=A7=8C=EB=93=A4=EA=B3=A0=20=EB=B0=9C=EC=86=A1?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/admin/message/Keywords.kt | 27 +++++++++++++ .../dmforu/admin/message/MessageService.kt | 39 +++++++++++++++++++ .../filter/NoticeMessageKeywordFilter.kt | 22 +++++++++++ 3 files changed, 88 insertions(+) create mode 100644 dmforu-admin/src/main/kotlin/com/dmforu/admin/message/Keywords.kt create mode 100644 dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt create mode 100644 dmforu-admin/src/main/kotlin/com/dmforu/admin/message/filter/NoticeMessageKeywordFilter.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/Keywords.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/Keywords.kt new file mode 100644 index 0000000..50bee5d --- /dev/null +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/Keywords.kt @@ -0,0 +1,27 @@ +package com.dmforu.admin.message + +enum class Keywords (val korean: String){ + EXAM("시험"), + SIGN_UP("수강"), + SPECIAL_LECTURE("특강"), + SEASONAL_SEMESTER("계절학기"), + LEAVE_OF_ABSENCE("휴학"), + RETURN_TO_SCHOOL("복학"), + GRADUATE("졸업"), + SWITCH_MAJORS("전과"), + GIVING_UP_THE_SEMESTER("학기포기"), + SCHOLARSHIP("장학"), + NATIONAL_SCHOLARSHIP("국가장학"), + REGISTRATION("등록금"), + EMPLOYMENT("채용"), + CONTEST("공모전"), + COMPETITION("대회"), + FIELD_TRAINING("현장실습"), + VOLUNTEER("봉사"), + DORMITORY("기숙사"), + GROUP("동아리"), + STUDENT_COUNCIL("학생회"), + OVERSEAS_TRAINING("해외연수"), + RESERVE_FORCES("예비군"), + WORK("근로"); +} \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt new file mode 100644 index 0000000..44d87a3 --- /dev/null +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt @@ -0,0 +1,39 @@ +package com.dmforu.admin.message + +import com.dmforu.admin.message.filter.keywordFilter +import com.dmforu.domain.notice.Notice +import com.dmforu.domain.subscribe.SubscribeReader +import org.springframework.stereotype.Service + +@Service +class MessageService( + private val subscribeReader: SubscribeReader, + private val messageSender: MessageSender, +) { + + fun sendNoticeMessage(notice: Notice) { + if (notice.isUniversityNotice()) { + sendUniversityNoticeMessage(notice) + } + + sendDepartmentNoticeMessage(notice) + } + + private fun sendUniversityNoticeMessage(notice: Notice) { + val keyword = keywordFilter(notice.title) ?: return + + val tokens = subscribeReader.getTokensBySubscribedToKeyword(keyword = keyword) + + val message = NoticeMessage.createUniversityNoticeMessage(notice = notice, keyword = keyword) + + messageSender.sendNoticeMessage(message = message, tokens = tokens) + } + + private fun sendDepartmentNoticeMessage(notice: Notice) { + val tokens = subscribeReader.getTokensBySubscribedToDepartment(department = notice.type) + + val message = NoticeMessage.createDepartmentNoticeMessage(notice = notice) + + messageSender.sendNoticeMessage(message = message, tokens = tokens) + } +} \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/filter/NoticeMessageKeywordFilter.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/filter/NoticeMessageKeywordFilter.kt new file mode 100644 index 0000000..e99367f --- /dev/null +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/filter/NoticeMessageKeywordFilter.kt @@ -0,0 +1,22 @@ +package com.dmforu.admin.message.filter + +import com.dmforu.admin.message.Keywords + +fun keywordFilter(title: String): String? { + Keywords.entries.forEach { + if (title.contains(it.korean)) { + return it.korean + } + } + + val whiteSpaceRemovedTitle = title.replace(" ", "") + if (whiteSpaceRemovedTitle.contains("중간고사")) { + return "시험" + } + + if (whiteSpaceRemovedTitle.contains("기말고사")) { + return "시험" + } + + return null +} \ No newline at end of file From 639c6003e9602141a6efc6604934a5c411c13df0 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 18 Oct 2024 03:06:46 +0900 Subject: [PATCH 077/223] =?UTF-8?q?fix:=20FirebaseApp=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EB=A5=BC=20=EC=A3=BC=EC=9E=85=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EC=9D=80=20=EB=B6=80=EB=B6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt index 7954ba1..6074d50 100644 --- a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt +++ b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt @@ -2,6 +2,7 @@ package com.dmforu.fcm import com.dmforu.admin.message.MessageSender import com.dmforu.admin.message.NoticeMessage +import com.google.firebase.FirebaseApp import com.google.firebase.messaging.FirebaseMessaging import org.springframework.stereotype.Component @@ -13,8 +14,9 @@ internal class FirebaseMessageSender( override fun sendNoticeMessage(message: NoticeMessage, tokens: List) { val firebaseMessage = firebaseMessageConverter.buildMessageToNotice(message, tokens) + val firebaseApp = FirebaseApp.getInstance("DMFORU_APP_PROD") - FirebaseMessaging.getInstance().sendEachForMulticast(firebaseMessage) + FirebaseMessaging.getInstance(firebaseApp).sendEachForMulticast(firebaseMessage) } From cdf39442244be73a189103277ed9ffa4736efe26 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 18 Oct 2024 03:08:10 +0900 Subject: [PATCH 078/223] =?UTF-8?q?feat:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=EC=9D=B4=20=EC=B6=94=EA=B0=80=EB=90=A0=20=EB=95=8C=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=EC=9D=84=20=EC=A0=84=EC=86=A1=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=EB=84=88=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/admin/message/NoticeListener.kt | 16 ++++++++++++++++ .../dmforu/domain/notice/NoticeCrawlService.kt | 5 ++++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeListener.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeListener.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeListener.kt new file mode 100644 index 0000000..46c0c22 --- /dev/null +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeListener.kt @@ -0,0 +1,16 @@ +package com.dmforu.admin.message + +import com.dmforu.domain.notice.Notice +import org.springframework.context.event.EventListener +import org.springframework.stereotype.Component + +@Component +class NoticeListener ( + private val messageService: MessageService +) { + @EventListener + fun onNoticeMessageSendEventHandler(notice: Notice) { + println(notice.title) + messageService.sendNoticeMessage(notice) + } +} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlService.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlService.kt index 054353b..05ed9b1 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlService.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlService.kt @@ -1,10 +1,12 @@ package com.dmforu.domain.notice +import org.springframework.context.ApplicationEventPublisher import org.springframework.stereotype.Component @Component class NoticeCrawlService( - private val noticeRepository: NoticeRepository + private val noticeRepository: NoticeRepository, + private val applicationEventPublisher: ApplicationEventPublisher, ) { fun findMaxNumberByType(type: String): Int? { return noticeRepository.findMaxNumberByType(type) @@ -12,5 +14,6 @@ class NoticeCrawlService( fun write(notice: Notice) { noticeRepository.write(notice) + applicationEventPublisher.publishEvent(notice) } } \ No newline at end of file From f26b55ad537f7a557d03932d2e0b229cd9f8dffe Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 18 Oct 2024 03:08:37 +0900 Subject: [PATCH 079/223] =?UTF-8?q?fix:=20=ED=86=A0=ED=81=B0=EC=9D=B4=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=9E=84=EC=8B=9C=20=ED=95=B8=EB=93=A4=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/admin/message/MessageService.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt index 44d87a3..c6dbb34 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt @@ -24,6 +24,10 @@ class MessageService( val tokens = subscribeReader.getTokensBySubscribedToKeyword(keyword = keyword) + if (tokens.isEmpty()) { + return + } + val message = NoticeMessage.createUniversityNoticeMessage(notice = notice, keyword = keyword) messageSender.sendNoticeMessage(message = message, tokens = tokens) @@ -32,6 +36,10 @@ class MessageService( private fun sendDepartmentNoticeMessage(notice: Notice) { val tokens = subscribeReader.getTokensBySubscribedToDepartment(department = notice.type) + if (tokens.isEmpty()) { + return + } + val message = NoticeMessage.createDepartmentNoticeMessage(notice = notice) messageSender.sendNoticeMessage(message = message, tokens = tokens) From db2112e21ba0bd0cc15dc540044f834e5fd59c9b Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 18 Oct 2024 12:04:33 +0900 Subject: [PATCH 080/223] =?UTF-8?q?rename:=20Message=EB=A5=BC=20domain?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/com/dmforu/admin/message/NoticeListener.kt | 2 +- .../src/main/kotlin/com/dmforu/domain}/message/Keywords.kt | 2 +- .../main/kotlin/com/dmforu/domain}/message/MessageSender.kt | 2 +- .../main/kotlin/com/dmforu/domain}/message/MessageService.kt | 4 ++-- .../main/kotlin/com/dmforu/domain}/message/NoticeMessage.kt | 2 +- .../domain}/message/filter/NoticeMessageKeywordFilter.kt | 4 ++-- dmforu-fcm/build.gradle.kts | 4 ++-- .../main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt | 2 +- .../src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt | 4 ++-- .../src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt | 5 ----- 10 files changed, 13 insertions(+), 18 deletions(-) rename {dmforu-admin/src/main/kotlin/com/dmforu/admin => dmforu-domain/src/main/kotlin/com/dmforu/domain}/message/Keywords.kt (95%) rename {dmforu-admin/src/main/kotlin/com/dmforu/admin => dmforu-domain/src/main/kotlin/com/dmforu/domain}/message/MessageSender.kt (74%) rename {dmforu-admin/src/main/kotlin/com/dmforu/admin => dmforu-domain/src/main/kotlin/com/dmforu/domain}/message/MessageService.kt (93%) rename {dmforu-admin/src/main/kotlin/com/dmforu/admin => dmforu-domain/src/main/kotlin/com/dmforu/domain}/message/NoticeMessage.kt (97%) rename {dmforu-admin/src/main/kotlin/com/dmforu/admin => dmforu-domain/src/main/kotlin/com/dmforu/domain}/message/filter/NoticeMessageKeywordFilter.kt (83%) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeListener.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeListener.kt index 46c0c22..3c1873b 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeListener.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeListener.kt @@ -1,5 +1,6 @@ package com.dmforu.admin.message +import com.dmforu.domain.message.MessageService import com.dmforu.domain.notice.Notice import org.springframework.context.event.EventListener import org.springframework.stereotype.Component @@ -10,7 +11,6 @@ class NoticeListener ( ) { @EventListener fun onNoticeMessageSendEventHandler(notice: Notice) { - println(notice.title) messageService.sendNoticeMessage(notice) } } \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/Keywords.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/Keywords.kt similarity index 95% rename from dmforu-admin/src/main/kotlin/com/dmforu/admin/message/Keywords.kt rename to dmforu-domain/src/main/kotlin/com/dmforu/domain/message/Keywords.kt index 50bee5d..5d32da2 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/Keywords.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/Keywords.kt @@ -1,4 +1,4 @@ -package com.dmforu.admin.message +package com.dmforu.domain.message enum class Keywords (val korean: String){ EXAM("시험"), diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageSender.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/MessageSender.kt similarity index 74% rename from dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageSender.kt rename to dmforu-domain/src/main/kotlin/com/dmforu/domain/message/MessageSender.kt index 9479a96..d41b90e 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageSender.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/MessageSender.kt @@ -1,4 +1,4 @@ -package com.dmforu.admin.message +package com.dmforu.domain.message interface MessageSender { fun sendNoticeMessage(message: NoticeMessage, tokens: List) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/MessageService.kt similarity index 93% rename from dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt rename to dmforu-domain/src/main/kotlin/com/dmforu/domain/message/MessageService.kt index c6dbb34..c7c2a51 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/MessageService.kt @@ -1,6 +1,6 @@ -package com.dmforu.admin.message +package com.dmforu.domain.message -import com.dmforu.admin.message.filter.keywordFilter +import com.dmforu.domain.message.filter.keywordFilter import com.dmforu.domain.notice.Notice import com.dmforu.domain.subscribe.SubscribeReader import org.springframework.stereotype.Service diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeMessage.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/NoticeMessage.kt similarity index 97% rename from dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeMessage.kt rename to dmforu-domain/src/main/kotlin/com/dmforu/domain/message/NoticeMessage.kt index 3b5617a..1dc818c 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeMessage.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/NoticeMessage.kt @@ -1,4 +1,4 @@ -package com.dmforu.admin.message +package com.dmforu.domain.message import com.dmforu.domain.notice.Notice diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/filter/NoticeMessageKeywordFilter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/filter/NoticeMessageKeywordFilter.kt similarity index 83% rename from dmforu-admin/src/main/kotlin/com/dmforu/admin/message/filter/NoticeMessageKeywordFilter.kt rename to dmforu-domain/src/main/kotlin/com/dmforu/domain/message/filter/NoticeMessageKeywordFilter.kt index e99367f..8dd1aea 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/filter/NoticeMessageKeywordFilter.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/filter/NoticeMessageKeywordFilter.kt @@ -1,6 +1,6 @@ -package com.dmforu.admin.message.filter +package com.dmforu.domain.message.filter -import com.dmforu.admin.message.Keywords +import com.dmforu.domain.message.Keywords fun keywordFilter(title: String): String? { Keywords.entries.forEach { diff --git a/dmforu-fcm/build.gradle.kts b/dmforu-fcm/build.gradle.kts index b3b2e92..d333b10 100644 --- a/dmforu-fcm/build.gradle.kts +++ b/dmforu-fcm/build.gradle.kts @@ -1,5 +1,5 @@ dependencies { compileOnly(project(":dmforu-domain")) - compileOnly(project(":dmforu-admin")) - implementation ("com.google.firebase:firebase-admin:9.2.0") + + implementation("com.google.firebase:firebase-admin:9.2.0") } \ No newline at end of file diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt index 8bd7978..321110f 100644 --- a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt +++ b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt @@ -1,6 +1,6 @@ package com.dmforu.fcm -import com.dmforu.admin.message.NoticeMessage +import com.dmforu.domain.message.NoticeMessage import com.google.firebase.messaging.MulticastMessage import com.google.firebase.messaging.Notification import org.springframework.stereotype.Component diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt index 6074d50..2de946a 100644 --- a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt +++ b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt @@ -1,7 +1,7 @@ package com.dmforu.fcm -import com.dmforu.admin.message.MessageSender -import com.dmforu.admin.message.NoticeMessage +import com.dmforu.domain.message.MessageSender +import com.dmforu.domain.message.NoticeMessage import com.google.firebase.FirebaseApp import com.google.firebase.messaging.FirebaseMessaging import org.springframework.stereotype.Component diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt index 1218563..9dd7846 100644 --- a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt +++ b/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt @@ -3,16 +3,11 @@ package com.dmforu.fcm.config import com.google.auth.oauth2.GoogleCredentials import com.google.firebase.FirebaseApp import com.google.firebase.FirebaseOptions -import com.google.firebase.messaging.FirebaseMessaging import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.core.io.ClassPathResource -import org.springframework.core.io.Resource -import org.springframework.util.FileCopyUtils -import java.io.ByteArrayInputStream import java.io.IOException -import java.nio.charset.StandardCharsets @Configuration @EntityScan(basePackages = ["com.dmforu.fcm"]) From f93fcf6d72a574addcabea3df30377a9dfe93491 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 18 Oct 2024 12:42:47 +0900 Subject: [PATCH 081/223] =?UTF-8?q?chore:=20infra=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=EB=A1=9C=20storage,=20fcm=20=EC=9D=91=EC=A7=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++- dmforu-admin/build.gradle.kts | 6 +++--- dmforu-api/build.gradle.kts | 5 +++-- dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt | 1 + {dmforu-fcm => dmforu-infra/fcm}/build.gradle.kts | 0 .../main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt | 0 .../src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt | 0 .../fcm}/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt | 0 .../storage}/db-mysql/build.gradle.kts | 0 .../com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt | 0 .../storage/db/mysql/converter/StringListConverter.kt | 0 .../com/dmforu/storage/db/mysql/notice/NoticeEntity.kt | 0 .../storage/db/mysql/notice/NoticeEntityRepository.kt | 0 .../dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt | 0 .../dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt | 0 .../storage/db/mysql/subscribe/SubscribeEntityRepository.kt | 0 .../storage/db/mysql/subscribe/SubscribeJpaRepository.kt | 0 .../storage}/db-redis/build.gradle.kts | 0 .../com/dmforu/storage/db/redis/config/RedisConfig.kt | 0 .../kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt | 0 .../dmforu/storage/db/redis/diet/DietEntityRepository.kt | 0 .../com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt | 0 .../storage/db/redis/schedule/ScheduleEntityRepository.kt | 0 settings.gradle.kts | 6 +++--- 24 files changed, 12 insertions(+), 9 deletions(-) rename {dmforu-fcm => dmforu-infra/fcm}/build.gradle.kts (100%) rename {dmforu-fcm => dmforu-infra/fcm}/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt (100%) rename {dmforu-fcm => dmforu-infra/fcm}/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt (100%) rename {dmforu-fcm => dmforu-infra/fcm}/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-mysql/build.gradle.kts (100%) rename {dmforu-storage => dmforu-infra/storage}/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-redis/build.gradle.kts (100%) rename {dmforu-storage => dmforu-infra/storage}/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt (100%) rename {dmforu-storage => dmforu-infra/storage}/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt (100%) diff --git a/.gitignore b/.gitignore index 73465a0..6aff4ad 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,5 @@ out/ ### Configuration Settings ### **/application.yml -**/*.yml \ No newline at end of file +**/*.yml +**/fire-base-key.json \ No newline at end of file diff --git a/dmforu-admin/build.gradle.kts b/dmforu-admin/build.gradle.kts index 8fad878..0769723 100644 --- a/dmforu-admin/build.gradle.kts +++ b/dmforu-admin/build.gradle.kts @@ -10,7 +10,7 @@ dependencies { implementation(project(":dmforu-domain")) implementation(project(":dmforu-crawling")) - runtimeOnly(project(":dmforu-fcm")) - runtimeOnly(project(":dmforu-storage:db-mysql")) - runtimeOnly(project(":dmforu-storage:db-redis")) + runtimeOnly(project(":dmforu-infra:fcm")) + runtimeOnly(project(":dmforu-infra:storage:db-mysql")) + runtimeOnly(project(":dmforu-infra:storage:db-redis")) } \ No newline at end of file diff --git a/dmforu-api/build.gradle.kts b/dmforu-api/build.gradle.kts index d774cac..c8e0821 100644 --- a/dmforu-api/build.gradle.kts +++ b/dmforu-api/build.gradle.kts @@ -9,8 +9,9 @@ tasks.getByName("jar") { dependencies { implementation(project(":dmforu-domain")) implementation(project(":dmforu-crawling")) - runtimeOnly(project(":dmforu-storage:db-mysql")) - runtimeOnly(project(":dmforu-storage:db-redis")) + runtimeOnly(project(":dmforu-infra:fcm")) + runtimeOnly(project(":dmforu-infra:storage:db-mysql")) + runtimeOnly(project(":dmforu-infra:storage:db-redis")) implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0") diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt index bc79386..da7fdcd 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt @@ -7,6 +7,7 @@ import org.springframework.boot.runApplication scanBasePackages = [ "com.dmforu.api", "com.dmforu.domain", + "com.dmforu.fcm", "com.dmforu.storage.db.redis", "com.dmforu.storage.db.mysql" ] diff --git a/dmforu-fcm/build.gradle.kts b/dmforu-infra/fcm/build.gradle.kts similarity index 100% rename from dmforu-fcm/build.gradle.kts rename to dmforu-infra/fcm/build.gradle.kts diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt b/dmforu-infra/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt similarity index 100% rename from dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt rename to dmforu-infra/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt b/dmforu-infra/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt similarity index 100% rename from dmforu-fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt rename to dmforu-infra/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt diff --git a/dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt b/dmforu-infra/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt similarity index 100% rename from dmforu-fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt rename to dmforu-infra/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt diff --git a/dmforu-storage/db-mysql/build.gradle.kts b/dmforu-infra/storage/db-mysql/build.gradle.kts similarity index 100% rename from dmforu-storage/db-mysql/build.gradle.kts rename to dmforu-infra/storage/db-mysql/build.gradle.kts diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt b/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt similarity index 100% rename from dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt rename to dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt b/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt similarity index 100% rename from dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt rename to dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt b/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt similarity index 100% rename from dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt rename to dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt b/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt similarity index 100% rename from dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt rename to dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt b/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt similarity index 100% rename from dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt rename to dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt b/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt similarity index 100% rename from dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt rename to dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt b/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt similarity index 100% rename from dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt rename to dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt diff --git a/dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt b/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt similarity index 100% rename from dmforu-storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt rename to dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt diff --git a/dmforu-storage/db-redis/build.gradle.kts b/dmforu-infra/storage/db-redis/build.gradle.kts similarity index 100% rename from dmforu-storage/db-redis/build.gradle.kts rename to dmforu-infra/storage/db-redis/build.gradle.kts diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt b/dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt similarity index 100% rename from dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt rename to dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt b/dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt similarity index 100% rename from dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt rename to dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt b/dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt similarity index 100% rename from dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt rename to dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt b/dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt similarity index 100% rename from dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt rename to dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt diff --git a/dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt b/dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt similarity index 100% rename from dmforu-storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt rename to dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index 28bbb21..db1d905 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,9 +5,9 @@ include( "dmforu-admin", "dmforu-domain", "dmforu-crawling", - "dmforu-fcm", - "dmforu-storage:db-mysql", - "dmforu-storage:db-redis" + "dmforu-infra:fcm", + "dmforu-infra:storage:db-mysql", + "dmforu-infra:storage:db-redis" ) pluginManagement { From 219c1c819233b03fb1db99eeda8bde97cdedebfc Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:47:55 +0900 Subject: [PATCH 082/223] =?UTF-8?q?refactor:=20Message=20Service=20?= =?UTF-8?q?=EC=B1=85=EC=9E=84=EC=9D=84=20domain=EC=97=90=EC=84=9C=20admin?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/admin}/message/MessageService.kt | 25 +++++++++++++++++-- .../dmforu/admin/message/NoticeListener.kt | 1 - dmforu-api/build.gradle.kts | 3 +-- .../kotlin/com/dmforu/api/ApiApplication.kt | 1 - .../filter/NoticeMessageKeywordFilter.kt | 22 ---------------- 5 files changed, 24 insertions(+), 28 deletions(-) rename {dmforu-domain/src/main/kotlin/com/dmforu/domain => dmforu-admin/src/main/kotlin/com/dmforu/admin}/message/MessageService.kt (66%) delete mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/message/filter/NoticeMessageKeywordFilter.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/MessageService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt similarity index 66% rename from dmforu-domain/src/main/kotlin/com/dmforu/domain/message/MessageService.kt rename to dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt index c7c2a51..9269f67 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/MessageService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt @@ -1,6 +1,8 @@ -package com.dmforu.domain.message +package com.dmforu.admin.message -import com.dmforu.domain.message.filter.keywordFilter +import com.dmforu.domain.message.Keywords +import com.dmforu.domain.message.MessageSender +import com.dmforu.domain.message.NoticeMessage import com.dmforu.domain.notice.Notice import com.dmforu.domain.subscribe.SubscribeReader import org.springframework.stereotype.Service @@ -44,4 +46,23 @@ class MessageService( messageSender.sendNoticeMessage(message = message, tokens = tokens) } + + private fun keywordFilter(title: String): String? { + Keywords.entries.forEach { + if (title.contains(it.korean)) { + return it.korean + } + } + + val whiteSpaceRemovedTitle = title.replace(" ", "") + if (whiteSpaceRemovedTitle.contains("중간고사")) { + return "시험" + } + + if (whiteSpaceRemovedTitle.contains("기말고사")) { + return "시험" + } + + return null + } } \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeListener.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeListener.kt index 3c1873b..c11fd50 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeListener.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/NoticeListener.kt @@ -1,6 +1,5 @@ package com.dmforu.admin.message -import com.dmforu.domain.message.MessageService import com.dmforu.domain.notice.Notice import org.springframework.context.event.EventListener import org.springframework.stereotype.Component diff --git a/dmforu-api/build.gradle.kts b/dmforu-api/build.gradle.kts index c8e0821..bd484d5 100644 --- a/dmforu-api/build.gradle.kts +++ b/dmforu-api/build.gradle.kts @@ -8,8 +8,7 @@ tasks.getByName("jar") { dependencies { implementation(project(":dmforu-domain")) - implementation(project(":dmforu-crawling")) - runtimeOnly(project(":dmforu-infra:fcm")) + runtimeOnly(project(":dmforu-infra:storage:db-mysql")) runtimeOnly(project(":dmforu-infra:storage:db-redis")) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt index da7fdcd..bc79386 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt @@ -7,7 +7,6 @@ import org.springframework.boot.runApplication scanBasePackages = [ "com.dmforu.api", "com.dmforu.domain", - "com.dmforu.fcm", "com.dmforu.storage.db.redis", "com.dmforu.storage.db.mysql" ] diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/filter/NoticeMessageKeywordFilter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/filter/NoticeMessageKeywordFilter.kt deleted file mode 100644 index 8dd1aea..0000000 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/filter/NoticeMessageKeywordFilter.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.dmforu.domain.message.filter - -import com.dmforu.domain.message.Keywords - -fun keywordFilter(title: String): String? { - Keywords.entries.forEach { - if (title.contains(it.korean)) { - return it.korean - } - } - - val whiteSpaceRemovedTitle = title.replace(" ", "") - if (whiteSpaceRemovedTitle.contains("중간고사")) { - return "시험" - } - - if (whiteSpaceRemovedTitle.contains("기말고사")) { - return "시험" - } - - return null -} \ No newline at end of file From aeee552c855548321f0e27362d6f9dc925e892c0 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:49:25 +0900 Subject: [PATCH 083/223] =?UTF-8?q?refactor:=20Crawl=20Service=EB=A5=BC=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=ED=95=98=EA=B3=A0,=20admin=20Crawling=20Serv?= =?UTF-8?q?ice=EC=97=90=EC=84=9C=20Wirter=EC=99=80=20Reader=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DepartmentNoticeCrawlingService.kt | 16 +++++++++------- .../UniversityNoticeCrawlingService.kt | 15 +++++++++++---- .../domain/notice/NoticeCrawlService.kt | 19 ------------------- .../com/dmforu/domain/notice/NoticeReader.kt | 4 ++++ .../com/dmforu/domain/notice/NoticeWriter.kt | 12 ++++++++++++ 5 files changed, 36 insertions(+), 30 deletions(-) delete mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlService.kt create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index c08d650..f9fc572 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -1,16 +1,17 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.DepartmentNoticeParser -import com.dmforu.domain.notice.Notice -import com.dmforu.domain.notice.Major -import com.dmforu.domain.notice.NoticeCrawlService +import com.dmforu.domain.notice.* import org.springframework.beans.factory.ObjectProvider +import org.springframework.context.ApplicationEventPublisher import org.springframework.stereotype.Service @Service class DepartmentNoticeCrawlingService( private val prototypeBeanProvider: ObjectProvider, - private val noticeCrawlService: NoticeCrawlService + private val noticeWriter: NoticeWriter, + private val noticeReader: NoticeReader, + private val applicationEventPublisher: ApplicationEventPublisher, ) { /** * Major 열거형의 모든 값을 반복하여 모든 학과의 공지사항을 크롤링한다.

@@ -36,7 +37,7 @@ class DepartmentNoticeCrawlingService( parser.initialize(major) - val maxNumber: Int? = noticeCrawlService.findMaxNumberByType(major.type) + val maxNumber: Int? = noticeReader.findMaxNumberByType(major.type) val currentMaxNumber = maxNumber ?: 0 while (true) { @@ -65,9 +66,10 @@ class DepartmentNoticeCrawlingService( return false } - noticeCrawlService.write(notice) + noticeWriter.write(notice) // TODO: FCM 메세지 전송을 위한 이벤트 트리거 -// eventPublisher!!.publishEvent(notice) + applicationEventPublisher.publishEvent(notice) + if (notice.isLastInType()) { return false } diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt index b411ee3..f2c78ee 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt @@ -3,14 +3,19 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.UniversityNoticeParser import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.NoticeCrawlService +import com.dmforu.domain.notice.NoticeReader +import com.dmforu.domain.notice.NoticeWriter import org.springframework.beans.factory.ObjectProvider +import org.springframework.context.ApplicationEventPublisher import org.springframework.stereotype.Service @Service class UniversityNoticeCrawlingService( private val prototypeBeanProvider: ObjectProvider, - private val noticeCrawlService: NoticeCrawlService + private val applicationEventPublisher: ApplicationEventPublisher, + private val noticeWriter: NoticeWriter, + private val noticeReader: NoticeReader, ) { /** * 모든 대학 공지사항을 크롤링한다.

@@ -19,7 +24,7 @@ class UniversityNoticeCrawlingService( */ fun crawling() { val parser: UniversityNoticeParser = prototypeBeanProvider.getObject() - val maxNumber: Int? = noticeCrawlService.findMaxNumberByType("대학") + val maxNumber: Int? = noticeReader.findMaxNumberByType("대학") val currentMaxNumber = maxNumber ?: 0 while (true) { @@ -46,8 +51,10 @@ class UniversityNoticeCrawlingService( if (notice.isNumberLessThanOrEqualTo(currentMaxNumber)) { return false } - noticeCrawlService.write(notice) -// eventPublisher!!.publishEvent(notice) + + noticeWriter.write(notice) + applicationEventPublisher.publishEvent(notice) + if (notice.isLastInType()) { return false } diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlService.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlService.kt deleted file mode 100644 index 05ed9b1..0000000 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeCrawlService.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.dmforu.domain.notice - -import org.springframework.context.ApplicationEventPublisher -import org.springframework.stereotype.Component - -@Component -class NoticeCrawlService( - private val noticeRepository: NoticeRepository, - private val applicationEventPublisher: ApplicationEventPublisher, -) { - fun findMaxNumberByType(type: String): Int? { - return noticeRepository.findMaxNumberByType(type) - } - - fun write(notice: Notice) { - noticeRepository.write(notice) - applicationEventPublisher.publishEvent(notice) - } -} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeReader.kt index 240892b..600a01d 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeReader.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeReader.kt @@ -17,4 +17,8 @@ class NoticeReader( fun readUniversityNotice(page: Int, size: Int): List { return noticeRepository.findUniversityNotices(page, size) } + + fun findMaxNumberByType(type: String): Int? { + return noticeRepository.findMaxNumberByType(type) + } } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt new file mode 100644 index 0000000..a873634 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt @@ -0,0 +1,12 @@ +package com.dmforu.domain.notice + +import org.springframework.stereotype.Component + +@Component +class NoticeWriter( + private val noticeRepository: NoticeRepository, +) { + fun write(notice: Notice) { + noticeRepository.write(notice) + } +} \ No newline at end of file From ba04bcef7525114763dcb734d4e5d937e10f9167 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:53:31 +0900 Subject: [PATCH 084/223] =?UTF-8?q?chore:=20infra=EC=97=90=EC=84=9C=20infr?= =?UTF-8?q?astructure=EB=A1=9C=20=ED=8C=A8=ED=82=A4=EC=A7=80=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/build.gradle.kts | 6 +++--- .../scheduler/crawling/UniversityNoticeCrawlingService.kt | 1 - dmforu-api/build.gradle.kts | 4 ++-- .../fcm/build.gradle.kts | 0 .../main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt | 0 .../src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt | 0 .../fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt | 0 .../storage/db-mysql/build.gradle.kts | 0 .../com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt | 0 .../storage/db/mysql/converter/StringListConverter.kt | 0 .../com/dmforu/storage/db/mysql/notice/NoticeEntity.kt | 0 .../storage/db/mysql/notice/NoticeEntityRepository.kt | 0 .../dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt | 0 .../dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt | 0 .../storage/db/mysql/subscribe/SubscribeEntityRepository.kt | 0 .../storage/db/mysql/subscribe/SubscribeJpaRepository.kt | 0 .../storage/db-redis/build.gradle.kts | 0 .../com/dmforu/storage/db/redis/config/RedisConfig.kt | 0 .../kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt | 0 .../dmforu/storage/db/redis/diet/DietEntityRepository.kt | 0 .../com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt | 0 .../storage/db/redis/schedule/ScheduleEntityRepository.kt | 0 settings.gradle.kts | 6 +++--- 23 files changed, 8 insertions(+), 9 deletions(-) rename {dmforu-infra => dmforu-infrastructure}/fcm/build.gradle.kts (100%) rename {dmforu-infra => dmforu-infrastructure}/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-mysql/build.gradle.kts (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-redis/build.gradle.kts (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt (100%) rename {dmforu-infra => dmforu-infrastructure}/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt (100%) diff --git a/dmforu-admin/build.gradle.kts b/dmforu-admin/build.gradle.kts index 0769723..a77bd3c 100644 --- a/dmforu-admin/build.gradle.kts +++ b/dmforu-admin/build.gradle.kts @@ -10,7 +10,7 @@ dependencies { implementation(project(":dmforu-domain")) implementation(project(":dmforu-crawling")) - runtimeOnly(project(":dmforu-infra:fcm")) - runtimeOnly(project(":dmforu-infra:storage:db-mysql")) - runtimeOnly(project(":dmforu-infra:storage:db-redis")) + runtimeOnly(project(":dmforu-infrastructure:fcm")) + runtimeOnly(project(":dmforu-infrastructure:storage:db-mysql")) + runtimeOnly(project(":dmforu-infrastructure:storage:db-redis")) } \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt index f2c78ee..f9d31ac 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt @@ -2,7 +2,6 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.UniversityNoticeParser import com.dmforu.domain.notice.Notice -import com.dmforu.domain.notice.NoticeCrawlService import com.dmforu.domain.notice.NoticeReader import com.dmforu.domain.notice.NoticeWriter import org.springframework.beans.factory.ObjectProvider diff --git a/dmforu-api/build.gradle.kts b/dmforu-api/build.gradle.kts index bd484d5..b72f29a 100644 --- a/dmforu-api/build.gradle.kts +++ b/dmforu-api/build.gradle.kts @@ -9,8 +9,8 @@ tasks.getByName("jar") { dependencies { implementation(project(":dmforu-domain")) - runtimeOnly(project(":dmforu-infra:storage:db-mysql")) - runtimeOnly(project(":dmforu-infra:storage:db-redis")) + runtimeOnly(project(":dmforu-infrastructure:storage:db-mysql")) + runtimeOnly(project(":dmforu-infrastructure:storage:db-redis")) implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0") diff --git a/dmforu-infra/fcm/build.gradle.kts b/dmforu-infrastructure/fcm/build.gradle.kts similarity index 100% rename from dmforu-infra/fcm/build.gradle.kts rename to dmforu-infrastructure/fcm/build.gradle.kts diff --git a/dmforu-infra/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt similarity index 100% rename from dmforu-infra/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt rename to dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt diff --git a/dmforu-infra/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt similarity index 100% rename from dmforu-infra/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt rename to dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt diff --git a/dmforu-infra/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt similarity index 100% rename from dmforu-infra/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt rename to dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt diff --git a/dmforu-infra/storage/db-mysql/build.gradle.kts b/dmforu-infrastructure/storage/db-mysql/build.gradle.kts similarity index 100% rename from dmforu-infra/storage/db-mysql/build.gradle.kts rename to dmforu-infrastructure/storage/db-mysql/build.gradle.kts diff --git a/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt similarity index 100% rename from dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt rename to dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt diff --git a/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt similarity index 100% rename from dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt rename to dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt diff --git a/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt similarity index 100% rename from dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt rename to dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt diff --git a/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt similarity index 100% rename from dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt rename to dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt diff --git a/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt similarity index 100% rename from dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt rename to dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt diff --git a/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt similarity index 100% rename from dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt rename to dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt diff --git a/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt similarity index 100% rename from dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt rename to dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt diff --git a/dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt similarity index 100% rename from dmforu-infra/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt rename to dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt diff --git a/dmforu-infra/storage/db-redis/build.gradle.kts b/dmforu-infrastructure/storage/db-redis/build.gradle.kts similarity index 100% rename from dmforu-infra/storage/db-redis/build.gradle.kts rename to dmforu-infrastructure/storage/db-redis/build.gradle.kts diff --git a/dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt similarity index 100% rename from dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt rename to dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt diff --git a/dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt similarity index 100% rename from dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt rename to dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt diff --git a/dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt similarity index 100% rename from dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt rename to dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt diff --git a/dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt similarity index 100% rename from dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt rename to dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt diff --git a/dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt similarity index 100% rename from dmforu-infra/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt rename to dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index db1d905..55435b3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,9 +5,9 @@ include( "dmforu-admin", "dmforu-domain", "dmforu-crawling", - "dmforu-infra:fcm", - "dmforu-infra:storage:db-mysql", - "dmforu-infra:storage:db-redis" + "dmforu-infrastructure:fcm", + "dmforu-infrastructure:storage:db-mysql", + "dmforu-infrastructure:storage:db-redis" ) pluginManagement { From b5b3b29b036b1ed730c75c5d7613c80d9e7af2e7 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:34:01 +0900 Subject: [PATCH 085/223] =?UTF-8?q?refactor:=20Updater=EA=B0=80=20Reader?= =?UTF-8?q?=EC=99=80=20Writer=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EB=B9=84?= =?UTF-8?q?=EC=A7=80=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=EC=B1=85?= =?UTF-8?q?=EC=9E=84=EC=9D=84=20=EC=97=94=ED=8B=B0=ED=8B=B0=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=8F=84=EB=A9=94=EC=9D=B8=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EC=A0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/subscribe/Subscribe.kt | 43 ++++++++++++++----- .../domain/subscribe/SubscribeReader.kt | 4 ++ .../domain/subscribe/SubscribeRepository.kt | 9 +--- .../domain/subscribe/SubscribeUpdater.kt | 41 ++++++++++++++---- .../db/mysql/subscribe/SubscribeEntity.kt | 16 +++++-- .../subscribe/SubscribeEntityRepository.kt | 36 ++++------------ 6 files changed, 92 insertions(+), 57 deletions(-) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt index 425a1d4..b394450 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt @@ -1,25 +1,48 @@ package com.dmforu.domain.subscribe -data class Subscribe( - val token: String, - var department: String, - var keywords: List, - var isDepartmentSubscribed: Boolean, - var isKeywordSubscribed: Boolean, +class Subscribe( + token: String, + department: String, + keywords: List, + isDepartmentSubscribed: Boolean, + isKeywordSubscribed: Boolean, ) { + val token: String = token + + var department: String = department + private set + + var keywords: List = keywords + private set + + var isDepartmentSubscribed: Boolean = isDepartmentSubscribed + private set + + var isKeywordSubscribed: Boolean = isKeywordSubscribed + private set + + fun changeDepartment(department: String) { + this.department = department + } + fun subscribeDepartment() { - this.isDepartmentSubscribed = true; + this.isDepartmentSubscribed = true } fun unsubscribeDepartment() { - this.isDepartmentSubscribed = false; + this.isDepartmentSubscribed = false + } + + fun changeKeywords(keywords: List) { + this.keywords = keywords } fun subscribeKeyword() { - this.isKeywordSubscribed = true; + this.isKeywordSubscribed = true } fun unsubscribeKeyword() { - this.isKeywordSubscribed = false; + this.isKeywordSubscribed = false } + } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeReader.kt index 6502fc3..95abf49 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeReader.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeReader.kt @@ -6,6 +6,10 @@ import org.springframework.stereotype.Service class SubscribeReader ( private val subscribeRepository: SubscribeRepository, ){ + fun findById(token: String): Subscribe { + return subscribeRepository.findByToken(token) ?: throw IllegalArgumentException("존재하지 않는 토큰입니다.") + } + fun getTokensBySubscribedToDepartment(department: String): List { return subscribeRepository.findTokensByDepartment(department) } diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt index 146dbc5..4bf743d 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeRepository.kt @@ -2,14 +2,7 @@ package com.dmforu.domain.subscribe interface SubscribeRepository { fun save(subscribe: Subscribe) - - fun findByIdAndUpdateKeywords(token: String, keywords: List) - fun findByIdAndUpdateKeywordSubscribe(token: String) - fun findByIdAndUpdateKeywordUnsubscribe(token: String) - - fun findByIdAndUpdateDepartment(token: String, department: String) - fun findByIdAndUpdateDepartmentSubscribe(token: String) - fun findByIdAndUpdateDepartmentUnsubscribe(token: String) + fun findByToken(token: String): Subscribe? fun findTokensByDepartment(department: String): List fun findTokensContainingKeyword(keyword: String): List diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt index 029db08..9469dfb 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt @@ -4,31 +4,56 @@ import org.springframework.stereotype.Service @Service class SubscribeUpdater( - private val subscribeRepository: SubscribeRepository, + private val subscribeReader: SubscribeReader, + private val subscribeWriter: SubscribeWriter, ) { fun updateKeywords(token: String, keywords: List) { - subscribeRepository.findByIdAndUpdateKeywords(token, keywords) + val subscribe = subscribeReader.findById(token) + + subscribe.changeKeywords(keywords) + + subscribeWriter.write(subscribe) } fun updateKeywordSubscribeStatus(token: String, keywordSubscribeStatus: Boolean) { if (keywordSubscribeStatus) { - subscribeRepository.findByIdAndUpdateKeywordSubscribe(token) - return + val subscribe = subscribeReader.findById(token) + + subscribe.subscribeKeyword() + + subscribeWriter.write(subscribe) } - subscribeRepository.findByIdAndUpdateKeywordUnsubscribe(token) + val subscribe = subscribeReader.findById(token) + + subscribe.unsubscribeKeyword() + + subscribeWriter.write(subscribe) } fun updateDepartment(token: String, department: String) { - subscribeRepository.findByIdAndUpdateDepartment(token, department) + val subscribe = subscribeReader.findById(token) + + subscribe.changeDepartment(department) + + subscribeWriter.write(subscribe) } fun updateDepartmentSubscribeStatus(token: String, departmentSubscribeStatus: Boolean) { if (departmentSubscribeStatus) { - subscribeRepository.findByIdAndUpdateDepartmentSubscribe(token) + val subscribe = subscribeReader.findById(token) + + subscribe.subscribeDepartment() + + subscribeWriter.write(subscribe) + return } - subscribeRepository.findByIdAndUpdateDepartmentUnsubscribe(token) + val subscribe = subscribeReader.findById(token) + + subscribe.unsubscribeDepartment() + + subscribeWriter.write(subscribe) } } \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt index 16c247f..80779ff 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt @@ -15,7 +15,7 @@ internal class SubscribeEntity( var department: String, @Convert(converter = StringListConverter::class) - @Column(name = "keywords_list",nullable = true) + @Column(name = "keywords_list", nullable = true) var keywords: List, @Column(name = "department_onoff") @@ -32,12 +32,22 @@ internal class SubscribeEntity( token = subscribe.token, department = subscribe.department, keywords = subscribe.keywords, - isDepartmentSubscribed = false, - isKeywordSubscribed = false + isDepartmentSubscribed = subscribe.isDepartmentSubscribed, + isKeywordSubscribed = subscribe.isKeywordSubscribed, ) } } + fun toSubscribe(): Subscribe { + return Subscribe( + token = token, + department = department, + keywords = keywords, + isDepartmentSubscribed = isDepartmentSubscribed, + isKeywordSubscribed = isKeywordSubscribed + ) + } + fun changeDepartment(department: String) { this.department = department } diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt index d6cadc7..3d80e10 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt @@ -5,16 +5,24 @@ import com.dmforu.domain.subscribe.Subscribe import com.dmforu.domain.subscribe.SubscribeRepository import jakarta.transaction.Transactional import org.springframework.stereotype.Repository +import java.util.* +import kotlin.jvm.optionals.getOrNull @Repository internal class SubscribeEntityRepository( private val subscribeJpaRepository: SubscribeJpaRepository, ) : SubscribeRepository, OldSubscribeRepository { + @Transactional override fun save(subscribe: Subscribe) { subscribeJpaRepository.save(SubscribeEntity.from(subscribe)) } + override fun findByToken(token: String): Subscribe? { + val foundSubscribe = subscribeJpaRepository.findById(token) + return foundSubscribe.getOrNull()?.toSubscribe() + } + @Transactional @Deprecated("구버전 호환성을 위해 남겨둔 메서드입니다.") override fun findByIdAndSubscribeDepartment(token: String, department: String) { @@ -32,20 +40,6 @@ internal class SubscribeEntityRepository( subscribe.unsubscribeDepartment() } - @Transactional - override fun findByIdAndUpdateDepartment(token: String, department: String) { - val subscribe = findNotNullById(token) - - subscribe.changeDepartment(department) - } - - @Transactional - override fun findByIdAndUpdateDepartmentSubscribe(token: String) { - val subscribe = findNotNullById(token) - - subscribe.subscribeDepartment() - } - @Transactional @Deprecated("구버전 호환성을 위해 남겨둔 메서드입니다.") override fun findByIdAndSubscribeKeywords(token: String, keywords: List) { @@ -56,20 +50,6 @@ internal class SubscribeEntityRepository( subscribe.subscribeKeyword() } - @Transactional - override fun findByIdAndUpdateKeywords(token: String, keywords: List) { - val subscribe = findNotNullById(token) - - subscribe.changeKeywords(keywords) - } - - @Transactional - override fun findByIdAndUpdateKeywordSubscribe(token: String) { - val subscribe = findNotNullById(token) - - subscribe.subscribeKeyword() - } - @Transactional override fun findByIdAndUpdateKeywordUnsubscribe(token: String) { val subscribe = findNotNullById(token) From 42911e0f4395667f8d96c678112ab853fc597d5b Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:49:55 +0900 Subject: [PATCH 086/223] =?UTF-8?q?refactor:=20=EA=B5=AC=EB=B2=84=EC=A0=84?= =?UTF-8?q?=20Updater=EA=B0=80=20Reader=EC=99=80=20Writer=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EB=B0=8F=20=EB=B9=84=EC=A7=80=EB=8B=88=EC=8A=A4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B1=85=EC=9E=84=EC=9D=84=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=EC=97=90=EC=84=9C=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EC=A0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../subscribe/OldSubscribeRepository.kt | 9 ---- .../domain/subscribe/OldSubscribeUpdater.kt | 40 +++++++++++++----- .../subscribe/SubscribeEntityRepository.kt | 42 +------------------ 3 files changed, 30 insertions(+), 61 deletions(-) delete mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt deleted file mode 100644 index 8e23c77..0000000 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeRepository.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.dmforu.domain.subscribe - -interface OldSubscribeRepository { - fun findByIdAndSubscribeDepartment(token: String, department: String) - fun findByIdAndUpdateDepartmentUnsubscribe(token: String) - - fun findByIdAndSubscribeKeywords(token: String, keywords: List) - fun findByIdAndUpdateKeywordUnsubscribe(token: String) -} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt index 47c4397..1c12e51 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt @@ -2,29 +2,47 @@ package com.dmforu.domain.subscribe import org.springframework.stereotype.Service +@Deprecated("구버전 사용자를 위해 남겨둔 Updater 입니다.") @Service class OldSubscribeUpdater( - private val subscribeRepository: OldSubscribeRepository, + private val subscribeReader: SubscribeReader, + private val subscribeWriter: SubscribeWriter, ) { + @Deprecated("구버전 사용자를 위해 남겨둔 메서드입니다.") fun subscribeDepartment(token: String, department: String) { - subscribeRepository.findByIdAndSubscribeDepartment( - token = token, - department = department - ) + val subscribe = subscribeReader.findById(token) + + subscribe.changeDepartment(department) + subscribe.subscribeDepartment() + + subscribeWriter.write(subscribe) } + @Deprecated("구버전 사용자를 위해 남겨둔 메서드입니다.") fun unsubscribeDepartment(token: String) { - subscribeRepository.findByIdAndUpdateDepartmentUnsubscribe(token = token) + val subscribe = subscribeReader.findById(token) + + subscribe.unsubscribeDepartment() + + subscribeWriter.write(subscribe) } + @Deprecated("구버전 사용자를 위해 남겨둔 메서드입니다.") fun subscribeKeywords(token: String, keywords: List) { - subscribeRepository.findByIdAndSubscribeKeywords( - token = token, - keywords = keywords - ) + val subscribe = subscribeReader.findById(token) + + subscribe.changeKeywords(keywords) + subscribe.subscribeKeyword() + + subscribeWriter.write(subscribe) } + @Deprecated("구버전 사용자를 위해 남겨둔 메서드입니다.") fun unsubscribeKeywords(token: String) { - subscribeRepository.findByIdAndUpdateKeywordUnsubscribe(token = token) + val subscribe = subscribeReader.findById(token) + + subscribe.unsubscribeKeyword() + + subscribeWriter.write(subscribe) } } \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt index 3d80e10..1c1774a 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt @@ -1,17 +1,15 @@ package com.dmforu.storage.db.mysql.subscribe -import com.dmforu.domain.subscribe.OldSubscribeRepository import com.dmforu.domain.subscribe.Subscribe import com.dmforu.domain.subscribe.SubscribeRepository import jakarta.transaction.Transactional import org.springframework.stereotype.Repository -import java.util.* import kotlin.jvm.optionals.getOrNull @Repository internal class SubscribeEntityRepository( private val subscribeJpaRepository: SubscribeJpaRepository, -) : SubscribeRepository, OldSubscribeRepository { +) : SubscribeRepository { @Transactional override fun save(subscribe: Subscribe) { @@ -23,40 +21,6 @@ internal class SubscribeEntityRepository( return foundSubscribe.getOrNull()?.toSubscribe() } - @Transactional - @Deprecated("구버전 호환성을 위해 남겨둔 메서드입니다.") - override fun findByIdAndSubscribeDepartment(token: String, department: String) { - val subscribe = findNotNullById(token) - - subscribe.changeDepartment(department) - - subscribe.subscribeDepartment() - } - - @Transactional - override fun findByIdAndUpdateDepartmentUnsubscribe(token: String) { - val subscribe = findNotNullById(token) - - subscribe.unsubscribeDepartment() - } - - @Transactional - @Deprecated("구버전 호환성을 위해 남겨둔 메서드입니다.") - override fun findByIdAndSubscribeKeywords(token: String, keywords: List) { - val subscribe = findNotNullById(token) - - subscribe.changeKeywords(keywords) - - subscribe.subscribeKeyword() - } - - @Transactional - override fun findByIdAndUpdateKeywordUnsubscribe(token: String) { - val subscribe = findNotNullById(token) - - subscribe.unsubscribeKeyword() - } - override fun findTokensByDepartment(department: String): List { return subscribeJpaRepository.findTokensByDepartment(department) } @@ -65,8 +29,4 @@ internal class SubscribeEntityRepository( return subscribeJpaRepository.findTokensContainingKeyword(keyword) } - private fun findNotNullById(token: String): SubscribeEntity { - return subscribeJpaRepository.findById(token).orElseThrow { throw IllegalArgumentException("존재하지 않은 토큰입니다.") } - } - } \ No newline at end of file From be2021688ca8756467d4b42aaaf32a1dcca40c4b Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:51:12 +0900 Subject: [PATCH 087/223] =?UTF-8?q?refactor:=20=EB=B9=84=EC=A6=88=EB=8B=88?= =?UTF-8?q?=EC=8A=A4=20=EB=A1=9C=EC=A7=81=EC=9D=98=20=EC=B1=85=EC=9E=84?= =?UTF-8?q?=EC=9D=84=20=EB=8F=84=EB=A9=94=EC=9D=B8=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=98=AE=EA=B9=80=EC=9C=BC=EB=A1=9C=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../db/mysql/subscribe/SubscribeEntity.kt | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt index 80779ff..3f54de9 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt @@ -48,27 +48,4 @@ internal class SubscribeEntity( ) } - fun changeDepartment(department: String) { - this.department = department - } - - fun subscribeDepartment() { - this.isDepartmentSubscribed = true - } - - fun unsubscribeDepartment() { - this.isDepartmentSubscribed = false - } - - fun changeKeywords(keywords: List) { - this.keywords = keywords - } - - fun subscribeKeyword() { - this.isKeywordSubscribed = true - } - - fun unsubscribeKeyword() { - this.isKeywordSubscribed = false - } } \ No newline at end of file From c61439ffa093066b10146f64a29ef98d496d0d40 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:59:03 +0900 Subject: [PATCH 088/223] =?UTF-8?q?refactor:=20=EA=B5=AC=EB=B2=84=EC=A0=84?= =?UTF-8?q?=20=EC=82=AC=EC=9A=A9=EC=9E=90=EB=A5=BC=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?DTO=20=EA=B0=9D=EC=B2=B4=20Deprecated=20=EC=84=A0=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/api/controller/old/request/OldDepartmentRequest.kt | 1 + .../api/controller/old/request/OldKeywordsSubscribeRequest.kt | 1 + .../api/controller/old/request/OldRegisterSubscribeRequest.kt | 1 + .../com/dmforu/api/controller/old/request/OldTokenRequest.kt | 1 + 4 files changed, 4 insertions(+) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldDepartmentRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldDepartmentRequest.kt index 83e2d2e..abcd7b8 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldDepartmentRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldDepartmentRequest.kt @@ -1,5 +1,6 @@ package com.dmforu.api.controller.old.request +@Deprecated("구버전 사용자를 위해 남겨둔 DTO 입니다.") data class OldDepartmentRequest( val token: String, val department: String, diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldKeywordsSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldKeywordsSubscribeRequest.kt index d2f3216..69809ef 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldKeywordsSubscribeRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldKeywordsSubscribeRequest.kt @@ -1,5 +1,6 @@ package com.dmforu.api.controller.old.request +@Deprecated("구버전 사용자를 위해 남겨둔 DTO 입니다.") data class OldKeywordsSubscribeRequest ( val token: String, val topics: List diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt index c336ab9..831ccfd 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt @@ -2,6 +2,7 @@ package com.dmforu.api.controller.old.request import com.dmforu.domain.subscribe.Subscribe +@Deprecated("구버전 사용자를 위해 남겨둔 DTO 입니다.") data class OldRegisterSubscribeRequest( val token: String, val department: String, diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldTokenRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldTokenRequest.kt index 1a55706..a80dbfa 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldTokenRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldTokenRequest.kt @@ -1,5 +1,6 @@ package com.dmforu.api.controller.old.request +@Deprecated("구버전 사용자를 위해 남겨둔 DTO 입니다.") data class OldTokenRequest( val token: String, ) \ No newline at end of file From 4bcf9aa2436cd82a5b0c886c330ce4fad68b1074 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:59:31 +0900 Subject: [PATCH 089/223] =?UTF-8?q?refactor:=20Subscribe=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=20=EC=83=9D=EC=84=B1=EC=9E=90=20=EB=8C=80=EC=8B=A0=20?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A6=AC=20=ED=95=A8=EC=88=98=EB=A1=9C=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/OldRegisterSubscribeRequest.kt | 2 +- .../v1/request/RegisterSubscribeRequest.kt | 2 +- .../com/dmforu/domain/subscribe/Subscribe.kt | 22 +++++++++++++++++-- .../db/mysql/subscribe/SubscribeEntity.kt | 2 +- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt index 831ccfd..fd45f02 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/request/OldRegisterSubscribeRequest.kt @@ -12,7 +12,7 @@ data class OldRegisterSubscribeRequest( val isDepartmentSubscribed = department.isNotBlank() val areKeywordsSubscribed = topic.isNotEmpty() - return Subscribe( + return Subscribe.of( token = token, department = department, keywords = topic, diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt index 3f25ded..8727d3d 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt @@ -10,7 +10,7 @@ data class RegisterSubscribeRequest ( val areKeywordSubscribed: Boolean, ) { fun toSubscribe(): Subscribe { - return Subscribe( + return Subscribe.of( token = token, department = department, keywords = keywords, diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt index b394450..14edd0b 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt @@ -1,11 +1,11 @@ package com.dmforu.domain.subscribe -class Subscribe( +class Subscribe private constructor( token: String, department: String, keywords: List, isDepartmentSubscribed: Boolean, - isKeywordSubscribed: Boolean, + isKeywordSubscribed: Boolean ) { val token: String = token @@ -21,6 +21,24 @@ class Subscribe( var isKeywordSubscribed: Boolean = isKeywordSubscribed private set + companion object { + fun of( + token: String, + department: String, + keywords: List, + isDepartmentSubscribed: Boolean, + isKeywordSubscribed: Boolean, + ): Subscribe { + return Subscribe( + token = token, + department = department, + keywords = keywords, + isDepartmentSubscribed = isDepartmentSubscribed, + isKeywordSubscribed = isKeywordSubscribed + ) + } + } + fun changeDepartment(department: String) { this.department = department } diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt index 3f54de9..4d4780b 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt @@ -39,7 +39,7 @@ internal class SubscribeEntity( } fun toSubscribe(): Subscribe { - return Subscribe( + return Subscribe.of( token = token, department = department, keywords = keywords, From 4a8ea24f467631d87114e57059a379843e689ba4 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:40:11 +0900 Subject: [PATCH 090/223] =?UTF-8?q?refactor:=20equals,=20hashcode,=20toStr?= =?UTF-8?q?ing=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/subscribe/Subscribe.kt | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt index 14edd0b..9446021 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt @@ -1,14 +1,12 @@ package com.dmforu.domain.subscribe class Subscribe private constructor( - token: String, + val token: String, department: String, keywords: List, isDepartmentSubscribed: Boolean, - isKeywordSubscribed: Boolean + isKeywordSubscribed: Boolean, ) { - val token: String = token - var department: String = department private set @@ -63,4 +61,32 @@ class Subscribe private constructor( this.isKeywordSubscribed = false } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Subscribe + + if (token != other.token) return false + if (department != other.department) return false + if (keywords != other.keywords) return false + if (isDepartmentSubscribed != other.isDepartmentSubscribed) return false + if (isKeywordSubscribed != other.isKeywordSubscribed) return false + + return true + } + + override fun hashCode(): Int { + var result = token.hashCode() + result = 31 * result + department.hashCode() + result = 31 * result + keywords.hashCode() + result = 31 * result + isDepartmentSubscribed.hashCode() + result = 31 * result + isKeywordSubscribed.hashCode() + return result + } + + override fun toString(): String { + return "Subscribe(token='$token', department='$department', keywords=$keywords, isDepartmentSubscribed=$isDepartmentSubscribed, isKeywordSubscribed=$isKeywordSubscribed)" + } + } \ No newline at end of file From 7affb5b2145f5d1a90d004cc67a31fabe34e8eac Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:47:03 +0900 Subject: [PATCH 091/223] =?UTF-8?q?refactor:=20data=20class=EC=97=90?= =?UTF-8?q?=EC=84=9C=20class=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=20=EC=83=9D=EC=84=B1=EC=9E=90=20=EB=8C=80=EC=8B=A0=20?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A6=AC=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EB=8A=94=20=EB=B0=A9=ED=96=A5?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/crawling/DepartmentNoticeParser.kt | 2 +- .../dmforu/crawling/UniversityNoticeParser.kt | 2 +- .../kotlin/com/dmforu/domain/notice/Notice.kt | 64 ++++++++++++++----- .../storage/db/mysql/notice/NoticeEntity.kt | 2 +- 4 files changed, 51 insertions(+), 19 deletions(-) diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt index 1b10eff..634df56 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt @@ -45,7 +45,7 @@ class DepartmentNoticeParser : UrlGenerator(), Parser { val url = generateUrlFromSearch(row.select(".td-subject a").attr("href")) val date = LocalDate.parse(row.select(".td-date").text(), formatter) - val departmentNotice = Notice( + val departmentNotice = Notice.of( number = number, type = major.type, date = date, diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt index fc4efc2..4331e0f 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt @@ -38,7 +38,7 @@ class UniversityNoticeParser : UrlGenerator(), Parser { val url = generateUrlFromSearch(row.select(".td-subject a").attr("href")) val date = LocalDate.parse(row.select(".td-date").text(), DATE_FORMATTER) - val universityNotice = Notice( + val universityNotice = Notice.of( number = number, type = NOTICE_TYPE, date = date, diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt index 5813e05..1831ced 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt @@ -2,35 +2,67 @@ package com.dmforu.domain.notice import java.time.LocalDate -data class Notice( - // 공지사항 번호 +class Notice private constructor( val number: Int, - - // 공지사항 종류 val type: String, - - // 공지사항 날짜 val date: LocalDate, - - // 공지사항 제목 val title: String, - - // 공지사항 작성자 val author: String, - - // 공지사항 URL - val url: String + val url: String, ) { + companion object { + fun of(number: Int, type: String, date: LocalDate, title: String, author: String, url: String): Notice { + return Notice( + number = number, + type = type, + date = date, + title = title, + author = author, + url = url + ) + } + } + fun isNumberLessThanOrEqualTo(number: Int): Boolean { return this.number <= number } - fun isLastInType(): Boolean{ + fun isLastInType(): Boolean { return this.number == 1 } - fun isUniversityNotice(): Boolean{ - return "대학".equals(this.type) + fun isUniversityNotice(): Boolean { + return "대학" == this.type + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Notice + + if (number != other.number) return false + if (type != other.type) return false + if (date != other.date) return false + if (title != other.title) return false + if (author != other.author) return false + if (url != other.url) return false + + return true + } + + override fun hashCode(): Int { + var result = number + result = 31 * result + type.hashCode() + result = 31 * result + date.hashCode() + result = 31 * result + title.hashCode() + result = 31 * result + author.hashCode() + result = 31 * result + url.hashCode() + return result + } + + override fun toString(): String { + return "Notice(number=$number, type='$type', date=$date, title='$title', author='$author', url='$url')" } } \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt index 876d077..6ee9447 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt @@ -45,7 +45,7 @@ internal class NoticeEntity( } fun toNotice(): Notice { - return Notice( + return Notice.of( number = this.number, type = this.type, date = this.date, From bd8a70048764d37cea379ababfdf633df4bfbab8 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 21 Oct 2024 23:01:58 +0900 Subject: [PATCH 092/223] =?UTF-8?q?refactor:=20=EB=A7=A4=EC=A7=81=20String?= =?UTF-8?q?=EC=9D=84=20=EC=83=81=EC=88=98=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/dmforu/domain/notice/Notice.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt index 1831ced..e7cba55 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt @@ -21,6 +21,8 @@ class Notice private constructor( url = url ) } + + private const val UNIVERSITY: String = "대학" } fun isNumberLessThanOrEqualTo(number: Int): Boolean { @@ -32,7 +34,7 @@ class Notice private constructor( } fun isUniversityNotice(): Boolean { - return "대학" == this.type + return UNIVERSITY == this.type } override fun equals(other: Any?): Boolean { From 6c428753afc4ce8b7dbbdaadac6758af0cabf3ce Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 22 Oct 2024 12:09:40 +0900 Subject: [PATCH 093/223] =?UTF-8?q?feat:=20=EC=9E=84=EC=8B=9C=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EC=B6=94=ED=9B=84=EC=97=90=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=ED=95=B4=EC=95=BC=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/dmforu/domain/diet/DietReader.kt | 3 ++- .../main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt index 32c58f7..e4a025f 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt @@ -6,7 +6,8 @@ import org.springframework.stereotype.Component class DietReader( private val dietRepository: DietRepository, ) { + // TODO fun read(): List { - return dietRepository.read().orEmpty() + return dietRepository.read() ?: throw IllegalStateException("식단 정보가 존재하지 않습니다. 관리자 에러") } } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt index 5066df5..7a36b8d 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt @@ -6,7 +6,8 @@ import org.springframework.stereotype.Component class ScheduleReader( private val scheduleRepository: ScheduleRepository ) { + // TODO fun read(): List { - return scheduleRepository.read().orEmpty() + return scheduleRepository.read() ?: throw IllegalArgumentException("No schedule exists 관리자 에러") } } \ No newline at end of file From ebe989dc56ec2240a87ada2f1f002020fcfec5c3 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 22 Oct 2024 12:10:29 +0900 Subject: [PATCH 094/223] =?UTF-8?q?chore:=20crawling=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=EC=97=90=EC=84=9C=20Domain=EC=9D=84=20compileOnly=EB=A1=9C=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-crawling/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmforu-crawling/build.gradle.kts b/dmforu-crawling/build.gradle.kts index e9e82a3..8164988 100644 --- a/dmforu-crawling/build.gradle.kts +++ b/dmforu-crawling/build.gradle.kts @@ -1,7 +1,7 @@ val jsoupVersion: String by project dependencies { - implementation(project(":dmforu-domain")) + compileOnly(project(":dmforu-domain")) implementation("org.jsoup:jsoup:${jsoupVersion}") compileOnly("org.springframework:spring-context") From 8457c7825bc0c963f148360b9eca6d38fbed5271 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 22 Oct 2024 13:37:40 +0900 Subject: [PATCH 095/223] =?UTF-8?q?fix:=20if=20return=20=EB=AC=B8=EC=97=90?= =?UTF-8?q?=EC=84=9C=20return=EC=9D=B4=20=EB=B9=A0=EC=A0=B8=EC=9E=88?= =?UTF-8?q?=EB=8D=98=20=EB=B6=80=EB=B6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt index 9469dfb..732e948 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt @@ -22,6 +22,8 @@ class SubscribeUpdater( subscribe.subscribeKeyword() subscribeWriter.write(subscribe) + + return } val subscribe = subscribeReader.findById(token) From f03710ef70c51c257aabe6f6e1f298987d219dbd Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 22 Oct 2024 13:42:31 +0900 Subject: [PATCH 096/223] =?UTF-8?q?test:=20Subscribe=20=EB=8B=A8=EC=9C=84?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A1=9C=EC=A7=81=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/domain/subscribe/SubscribeTest.kt | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeTest.kt diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeTest.kt new file mode 100644 index 0000000..33811b4 --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeTest.kt @@ -0,0 +1,128 @@ +package com.dmforu.domain.subscribe + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +class SubscribeTest { + + @DisplayName("구독 정보에서 학과를 변경할 수 있다.") + @Test + fun changeDepartment() { + // given + val subscribe = Subscribe.of( + token = "0001", + department = "기계공학과", + keywords = listOf("학사", "봉사"), + isDepartmentSubscribed = true, + isKeywordSubscribed = true + ) + + val changedDepartment = "컴퓨터소프트웨어공학과" + + // when + subscribe.changeDepartment(changedDepartment) + + // then + assertThat(subscribe.department).isEqualTo(changedDepartment) + } + + @DisplayName("구독 정보에서 학과 알림을 구독할 수 있다.") + @Test + fun subscribeDepartment() { + // given + val subscribe = Subscribe.of( + token = "0001", + department = "기계공학과", + keywords = listOf("학사", "봉사"), + isDepartmentSubscribed = true, + isKeywordSubscribed = true + ) + + // when + subscribe.subscribeDepartment() + + // then + assertTrue(subscribe.isDepartmentSubscribed) + } + + @DisplayName("구독 정보에서 학과 알림을 구독 해제할 수 있다.") + @Test + fun unsubscribeDepartment() { + // given + val subscribe = Subscribe.of( + token = "0001", + department = "기계공학과", + keywords = listOf("학사", "봉사"), + isDepartmentSubscribed = true, + isKeywordSubscribed = true + ) + + // when + subscribe.unsubscribeDepartment() + + // then + assertFalse(subscribe.isDepartmentSubscribed) + } + + @DisplayName("구독 정보에서 학과를 변경할 수 있다.") + @Test + fun changeKeywords() { + // given + val subscribe = Subscribe.of( + token = "0001", + department = "기계공학과", + keywords = listOf("학사", "봉사"), + isDepartmentSubscribed = true, + isKeywordSubscribed = true + ) + + val changedKeywords = listOf("장학", "등록") + + // when + subscribe.changeKeywords(changedKeywords) + + // then + assertThat(subscribe.keywords).isEqualTo(changedKeywords) + } + + @DisplayName("구독 정보에서 학과 알림을 구독할 수 있다.") + @Test + fun subscribeKeyword() { + // given + val subscribe = Subscribe.of( + token = "0001", + department = "기계공학과", + keywords = listOf("학사", "봉사"), + isDepartmentSubscribed = true, + isKeywordSubscribed = true + ) + + // when + subscribe.subscribeKeyword() + + // then + assertTrue(subscribe.isKeywordSubscribed) + } + + @DisplayName("구독 정보에서 학과 알림을 구독 해제할 수 있다.") + @Test + fun unsubscribeKeyword() { + // given + val subscribe = Subscribe.of( + token = "0001", + department = "기계공학과", + keywords = listOf("학사", "봉사"), + isDepartmentSubscribed = true, + isKeywordSubscribed = true + ) + + // when + subscribe.unsubscribeKeyword() + + // then + assertFalse(subscribe.isKeywordSubscribed) + } + +} \ No newline at end of file From 5a6a6d121dde5fe6adfd41e69e2da89f2a582998 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:14:59 +0900 Subject: [PATCH 097/223] =?UTF-8?q?test:=20Notice=20=EB=8B=A8=EC=9C=84=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A1=9C=EC=A7=81=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/notice/NoticeTest.kt | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeTest.kt diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeTest.kt new file mode 100644 index 0000000..c6bad07 --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeTest.kt @@ -0,0 +1,75 @@ +package com.dmforu.domain.notice + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import java.time.LocalDate + +class NoticeTest { + + @DisplayName("공지의 번호가 특정 숫자보다 작거나 같은지 확인할 수 있다.") + @Test + fun isNumberLessThanOrEqualTo() { + // given + val notice = Notice.of( + number = 10, + type = "대학", + date = LocalDate.now(), + title = "공지사항입니다.", + author = "관리자", + url = "https://www.test.com" + ) + + // when // then + assertTrue(notice.isNumberLessThanOrEqualTo(10)) + assertFalse(notice.isNumberLessThanOrEqualTo(9)) + + } + + @DisplayName("특정 타입의 마지막 공지인지 확인할 수 있다.") + @Test + fun isLastInType() { + // given + val lastNotice = Notice.of( + number = 1, + type = "대학", + date = LocalDate.now(), + title = "공지사항입니다.", + author = "관리자", + url = "https://www.test.com" + ) + + val notLastNotice = Notice.of( + number = 2, + type = "대학", + date = LocalDate.now(), + title = "공지사항입니다.", + author = "관리자", + url = "https://www.test.com" + ) + + // when // then + assertTrue(lastNotice.isLastInType()) + assertFalse(notLastNotice.isLastInType()) + + } + + @DisplayName("대학 공지인지 확인할 수 있다.") + @Test + fun isUniversalNotice() { + // given + val notice = Notice.of( + number = 10, + type = "대학", + date = LocalDate.now(), + title = "공지사항입니다.", + author = "관리자", + url = "https://www.test.com" + ) + + // when // then + assertTrue(notice.isUniversityNotice()) + + } + +} \ No newline at end of file From d69d53ffa3435bba514af8e9bf70e7b0437c7279 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:23:06 +0900 Subject: [PATCH 098/223] =?UTF-8?q?test:=20Notice=20Message=20=EB=8B=A8?= =?UTF-8?q?=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/message/NoticeMessageTest.kt | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/message/NoticeMessageTest.kt diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/message/NoticeMessageTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/message/NoticeMessageTest.kt new file mode 100644 index 0000000..be0026b --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/message/NoticeMessageTest.kt @@ -0,0 +1,55 @@ +package com.dmforu.domain.message + +import com.dmforu.domain.notice.Notice +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import java.time.LocalDate + +class NoticeMessageTest { + + @DisplayName("대학 공지 메세지를 생성할 때, 제목에 키워드가 들어간다.") + @Test + fun createUniversityNoticeMessage() { + // given + val notice = Notice.of( + number = 10, + type = "대학", + date = LocalDate.now(), + title = "시험 공지사항입니다.", + author = "관리자", + url = "https://www.test.com" + ) + + val keyword = "시험" + + // when + val message = NoticeMessage.createUniversityNoticeMessage(notice = notice, keyword = keyword) + + // then + assertThat(message.title).isEqualTo("[ " + keyword + " ] 키워드 알림 도착") + + } + + @DisplayName("학과 공지 메세지를 생성할 때, 제목에 학과명이 들어간다.") + @Test + fun createDepartmentNoticeMessage() { + // given + val notice = Notice.of( + number = 10, + type = "컴퓨터소프트웨어공학과", + date = LocalDate.now(), + title = "시험 공지사항입니다.", + author = "관리자", + url = "https://www.test.com" + ) + + // when + val message = NoticeMessage.createDepartmentNoticeMessage(notice) + + // then + assertThat(message.title).isEqualTo("[ " + notice.type + " ] 키워드 알림 도착") + + } +} \ No newline at end of file From 9640af5df1176f37e451232f20bb11908bc77508 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:43:36 +0900 Subject: [PATCH 099/223] =?UTF-8?q?test:=20Subscribe=20Reader,=20Writer,?= =?UTF-8?q?=20Updater=20=EB=8B=A8=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/subscribe/SubscribeReaderTest.kt | 91 ++++++++++++ .../domain/subscribe/SubscribeUpdaterTest.kt | 137 ++++++++++++++++++ .../domain/subscribe/SubscribeWriterTest.kt | 40 +++++ 3 files changed, 268 insertions(+) create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeReaderTest.kt create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeUpdaterTest.kt create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeWriterTest.kt diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeReaderTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeReaderTest.kt new file mode 100644 index 0000000..fec1ca0 --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeReaderTest.kt @@ -0,0 +1,91 @@ +package com.dmforu.domain.subscribe + +import org.assertj.core.api.Assertions.* +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` +import org.mockito.junit.jupiter.MockitoExtension + +@ExtendWith(MockitoExtension::class) +class SubscribeReaderTest { + + @Mock + lateinit var subscribeRepository: SubscribeRepository + + @InjectMocks + lateinit var subscribeReader: SubscribeReader + + @DisplayName("토큰을 사용해서 구독 정보를 불러올 수 있다.") + @Test + fun findById() { + // given + val token = "validToken" + val expectedSubscribe = Subscribe.of( + token = token, + department = "컴퓨터소프트웨어공학과", + keywords = listOf("학사", "시험"), + isDepartmentSubscribed = true, + isKeywordSubscribed = true + ) + + `when`(subscribeRepository.findByToken(token)).thenReturn(expectedSubscribe) + + // when + val actualSubscribe = subscribeReader.findById(token) + + // then + assertEquals(expectedSubscribe, actualSubscribe) + verify(subscribeRepository).findByToken(token) + } + + @DisplayName("잘못된 토큰을 사용해서 구독 정보를 불러오는 경우 예외가 발생한다.") + @Test + fun findByIdThrowException() { + // given + val token = "invalidToken" + `when`(subscribeRepository.findByToken(token)).thenReturn(null) + + // when // then + assertThatThrownBy { subscribeReader.findById(token) } + .isInstanceOf(IllegalArgumentException::class.java) + .hasMessage("존재하지 않는 토큰입니다.") + } + + @DisplayName("학과명에 해당하는 모든 토큰을 불러올 수 있다.") + @Test + fun getTokensBySubscribedToDepartment() { + // given + val department = "컴퓨터소프트웨어공학과" + val tokens = listOf("0001", "0002") + `when`(subscribeRepository.findTokensByDepartment(department)).thenReturn(tokens) + + // when + val result = subscribeReader.getTokensBySubscribedToDepartment(department) + + // then + assertEquals(tokens, result) + verify(subscribeRepository).findTokensByDepartment(department) + } + + @DisplayName("해당하는 키워드를 가지고 있는 모든 토큰을 불러올 수 있다.") + @Test + fun getTokensBySubscribedToKeyword() { + // given + val keyword = "학사" + val tokens = listOf("0001", "0002") + `when`(subscribeRepository.findTokensContainingKeyword(keyword)).thenReturn(tokens) + + // when + val result = subscribeReader.getTokensBySubscribedToKeyword(keyword) + + // then + assertEquals(tokens, result) + verify(subscribeRepository).findTokensContainingKeyword(keyword) + } + +} \ No newline at end of file diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeUpdaterTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeUpdaterTest.kt new file mode 100644 index 0000000..d2c948d --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeUpdaterTest.kt @@ -0,0 +1,137 @@ +package com.dmforu.domain.subscribe + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.* +import org.mockito.junit.jupiter.MockitoExtension + +@ExtendWith(MockitoExtension::class) +class SubscribeUpdaterTest { + + @Mock + lateinit var subscribeReader: SubscribeReader + + @Mock + lateinit var subscribeWriter: SubscribeWriter + + @InjectMocks + lateinit var subscribeUpdater: SubscribeUpdater + + @DisplayName("토큰과 키워드로 구독 정보의 키워드를 업데이트할 수 있다.") + @Test + fun updateKeywords() { + // given + val token = "0001" + val keywords = listOf("봉사", "장학") + val subscribe = mock(Subscribe::class.java) + + `when`(subscribeReader.findById(token)).thenReturn(subscribe) + + // when + subscribeUpdater.updateKeywords(token, keywords) + + // then + verify(subscribeReader).findById(token) + verify(subscribe).changeKeywords(keywords) + verify(subscribeWriter).write(subscribe) + } + + @DisplayName("토큰 정보에 해당하는 구독 정보에서 키워드 구독 상태를 구독으로 변경할 수 있다.") + @Test + fun subscribeKeywords() { + // given + val token = "0001" + val keywordSubscribeStatus = true + val subscribe = mock(Subscribe::class.java) + + `when`(subscribeReader.findById(token)).thenReturn(subscribe) + + // when + subscribeUpdater.updateKeywordSubscribeStatus(token, keywordSubscribeStatus) + + // then + verify(subscribeReader).findById(token) + verify(subscribe).subscribeKeyword() + verify(subscribeWriter).write(subscribe) + } + + @DisplayName("토큰 정보에 해당하는 구독 정보에서 키워드 구독 상태를 구독 해제로 변경할 수 있다.") + @Test + fun unsubscribeKeywords() { + // given + val token = "0001" + val keywordSubscribeStatus = false + val subscribe = mock(Subscribe::class.java) + + `when`(subscribeReader.findById(token)).thenReturn(subscribe) + + // when + subscribeUpdater.updateKeywordSubscribeStatus(token, keywordSubscribeStatus) + + // then + verify(subscribeReader).findById(token) + verify(subscribe).unsubscribeKeyword() + verify(subscribeWriter).write(subscribe) + } + + @DisplayName("토큰과 학과명으로 구독 정보의 학과를 업데이트할 수 있다.") + @Test + fun updateDepartment() { + // given + val token = "0001" + val department = "컴퓨터소프트웨어공학과" + val subscribe = mock(Subscribe::class.java) + + `when`(subscribeReader.findById(token)).thenReturn(subscribe) + + // when + subscribeUpdater.updateDepartment(token, department) + + // then + verify(subscribeReader).findById(token) + verify(subscribe).changeDepartment(department) + verify(subscribeWriter).write(subscribe) + } + + @DisplayName("토큰 정보에 해당하는 구독 정보에서 학과 구독 상태를 구독으로 변경할 수 있다.") + @Test + fun subscribeDepartment() { + // given + val token = "0001" + val departmentSubscribeStatus = true + val subscribe = mock(Subscribe::class.java) + + `when`(subscribeReader.findById(token)).thenReturn(subscribe) + + // when + subscribeUpdater.updateDepartmentSubscribeStatus(token, departmentSubscribeStatus) + + // then + verify(subscribeReader).findById(token) + verify(subscribe).subscribeDepartment() + verify(subscribeWriter).write(subscribe) + } + + @DisplayName("토큰 정보에 해당하는 구독 정보에서 학과 구독 상태를 구독 해제로 변경할 수 있다.") + @Test + fun unsubscribeDepartment() { + // given + val token = "0001" + val departmentSubscribeStatus = false + val subscribe = mock(Subscribe::class.java) + + `when`(subscribeReader.findById(token)).thenReturn(subscribe) + + // when + subscribeUpdater.updateDepartmentSubscribeStatus(token, departmentSubscribeStatus) + + // then + verify(subscribeReader).findById(token) + verify(subscribe).unsubscribeDepartment() + verify(subscribeWriter).write(subscribe) + } +} \ No newline at end of file diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeWriterTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeWriterTest.kt new file mode 100644 index 0000000..2e2f78c --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeWriterTest.kt @@ -0,0 +1,40 @@ +package com.dmforu.domain.subscribe + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension + +@ExtendWith(MockitoExtension::class) +class SubscribeWriterTest { + + @Mock + lateinit var subscribeRepository: SubscribeRepository + + @InjectMocks + lateinit var subscribeWriter: SubscribeWriter + + @DisplayName("구독 정보를 저장할 수 있다.") + @Test + fun write() { + // given + val subscribe = Subscribe.of( + token = "0001", + department = "컴퓨터소프트웨어공학과", + keywords = listOf("학사", "시험"), + isDepartmentSubscribed = true, + isKeywordSubscribed = true + ) + + // when + subscribeWriter.write(subscribe) + + // then + verify(subscribeRepository).save(subscribe) + } + +} \ No newline at end of file From 4b2cc7245716d91f3ba61107a74f9bf537bb74fc Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 22 Oct 2024 16:24:09 +0900 Subject: [PATCH 100/223] =?UTF-8?q?test:=20Notice=20Reader,=20Writer=20?= =?UTF-8?q?=EB=8B=A8=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/domain/notice/NoticeReaderTest.kt | 197 ++++++++++++++++++ .../dmforu/domain/notice/NoticeWriterTest.kt | 42 ++++ 2 files changed, 239 insertions(+) create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeReaderTest.kt create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeWriterTest.kt diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeReaderTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeReaderTest.kt new file mode 100644 index 0000000..9752ad1 --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeReaderTest.kt @@ -0,0 +1,197 @@ +package com.dmforu.domain.notice + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` +import org.mockito.junit.jupiter.MockitoExtension +import java.time.LocalDate + +@ExtendWith(MockitoExtension::class) +class NoticeReaderTest { + + @Mock + private lateinit var noticeRepository: NoticeRepository + + @InjectMocks + private lateinit var noticeReader: NoticeReader + + @DisplayName("학과와 검색어를 사용하여, 대학 공지와 해당하는 학과 공지에서 검색어가 포함된 공지를 불러올 수 있다. ") + @Test + fun searchNotice() { + // given + val searchWord = "시험" + val department = Major.COMPUTER_SOFTWARE_ENGINEERING.type + val page = 1 + val size = 20 + + val universityNotice = createNotice( + number = 10, + type = "대학", + title = "시험 안내" + ) + + val departmentNotice = createNotice( + number = 20, + type = department, + title = "시험 시간표 공지" + ) + + `when`(noticeRepository.findNoticesBySearchWord(searchWord, department, page, size)) + .thenReturn( + listOf(universityNotice, departmentNotice) + ) + + // when + val foundNotices = noticeReader.searchNotice(searchWord, department, page, size) + + // then + assertThat(foundNotices).hasSize(2) + .extracting("type") + .containsExactlyInAnyOrder( + "대학", department + ) + + verify(noticeRepository).findNoticesBySearchWord(searchWord, department, page, size) + } + + @DisplayName("해당하는 학과의 공지를 불러올 수 있다.") + @Test + fun readDepartmentNotice() { + // given + val department = Major.COMPUTER_SOFTWARE_ENGINEERING.type + val page = 1 + val size = 20 + + val departmentNotice1 = createNotice( + number = 1, + type = department, + title = "등록금 납부 기간 안내" + ) + + val departmentNotice2 = createNotice( + number = 2, + type = department, + title = "시험 시간표 공지" + ) + + `when`(noticeRepository.findDepartmentNotices(department, page, size)) + .thenReturn( + listOf(departmentNotice1, departmentNotice2) + ) + + // when + val foundNotices = noticeReader.readDepartmentNotice(department, page, size) + + // then + assertThat(foundNotices).hasSize(2) + .extracting("type") + .containsExactlyInAnyOrder( + department, department + ) + + verify(noticeRepository).findDepartmentNotices(department, page, size) + } + + @DisplayName("대학 공지를 불러올 수 있다.") + @Test + fun readUniversityNotice() { + // given + val type = "대학" + val page = 1 + val size = 20 + + val universityNotice1 = createNotice( + number = 1, + type = type, + title = "등록금 납부 기간 안내" + ) + + val universityNotice2 = createNotice( + number = 2, + type = type, + title = "시험 시간표 공지" + ) + + `when`(noticeRepository.findUniversityNotices(page, size)) + .thenReturn( + listOf(universityNotice1, universityNotice2) + ) + + // when + val foundNotices = noticeReader.readUniversityNotice(page, size) + + // then + assertThat(foundNotices).hasSize(2) + .extracting("type") + .containsExactlyInAnyOrder( + type, type + ) + + verify(noticeRepository).findUniversityNotices(page, size) + } + + @DisplayName("타입에 해당하는 공지의 가장 최신 번호를 불러온다.") + @Test + fun findMaxNumberByType() { + // given + val department = Major.COMPUTER_SOFTWARE_ENGINEERING.type + val maxNumber = 10 + val notice = createNotice( + number = maxNumber, + type = department, + title = "신입생 설명회" + ) + + `when`(noticeRepository.findMaxNumberByType(department)) + .thenReturn(maxNumber) + + // then + val foundMaxNumber = noticeReader.findMaxNumberByType(department) + + // when + assertThat(foundMaxNumber).isEqualTo(maxNumber) + + verify(noticeRepository).findMaxNumberByType(department) + } + + @DisplayName("타입에 해당하는 공지가 없는 경우 null 을 반환한다.") + @Test + fun findMaxNumberByTypeWhenEmpty() { + // given + val department = Major.COMPUTER_SOFTWARE_ENGINEERING.type + + `when`(noticeRepository.findMaxNumberByType(department)) + .thenReturn(null) + + // when + val foundMaxNumber = noticeReader.findMaxNumberByType(department) + + // then + assertThat(foundMaxNumber).isNull() + + verify(noticeRepository).findMaxNumberByType(department) + } + + private fun createNotice( + number: Int, + type: String, + title: String, + date: LocalDate = LocalDate.now(), + author: String = "작성자", + url: String = "https://www.test.com", + ): Notice { + return Notice.of( + number = number, + type = type, + date = date, + title = title, + author = author, + url = url + ) + } +} \ No newline at end of file diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeWriterTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeWriterTest.kt new file mode 100644 index 0000000..508f282 --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeWriterTest.kt @@ -0,0 +1,42 @@ +package com.dmforu.domain.notice + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension +import java.time.LocalDate + +@ExtendWith(MockitoExtension::class) +class NoticeWriterTest { + + @Mock + private lateinit var noticeRepository: NoticeRepository + + @InjectMocks + private lateinit var noticeWriter: NoticeWriter + + @DisplayName("공지를 저장할 수 있다.") + @Test + fun write() { + // given + val notice = Notice.of( + number = 10, + type = "대학", + date = LocalDate.now(), + title = "공지사항입니다.", + author = "관리자", + url = "https://www.test.com" + ) + + // when + noticeWriter.write(notice) + + // then + verify(noticeRepository).write(notice) + + } +} \ No newline at end of file From 609c09d002a0a3708f6c9bc88efb2f2abca03eb0 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 22 Oct 2024 16:47:20 +0900 Subject: [PATCH 101/223] =?UTF-8?q?chore:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BB=A4=EB=B2=84=EB=A6=AC=EC=A7=80=20=ED=99=95=EC=9D=B8?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20jacoco=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 79c0f60..e5ab45b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,6 +3,7 @@ plugins { kotlin("plugin.spring") apply false id("org.springframework.boot") apply false id("io.spring.dependency-management") + id("jacoco") } java { @@ -28,10 +29,11 @@ subprojects { apply(plugin = "org.jetbrains.kotlin.plugin.spring") apply(plugin = "org.springframework.boot") apply(plugin = "io.spring.dependency-management") + apply(plugin = "jacoco") dependencyManagement { val springCloudDependenciesVersion: String by project - imports{ + imports { mavenBom("org.springframework.cloud:spring-cloud-dependencies:${springCloudDependenciesVersion}") } } @@ -60,5 +62,32 @@ subprojects { tasks.withType { useJUnitPlatform() + finalizedBy(tasks.jacocoTestReport) } + + tasks.jacocoTestReport { + dependsOn(tasks.test) + reports { + html.required.set(true) + xml.required.set(true) + } + classDirectories.setFrom( + files( + classDirectories.files.map { + fileTree(it) { + exclude( + "**/*Application*", + "**/*Config*", + "**/*Dto*", + "**/*Request*", + "**/*Response*", + "**/*Interceptor*", + "**/*Exception*" + ) + } + } + ) + ) + } + } From 2ed82f26f18ab3025c1747a9d7fd8ae8732594dc Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 23 Oct 2024 21:29:18 +0900 Subject: [PATCH 102/223] =?UTF-8?q?feat:=20equals,=20hashcode,=20toString?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BB=A4=EB=B2=84=EB=A6=AC?= =?UTF-8?q?=EC=A7=80=EC=97=90=EC=84=9C=20=EC=A0=9C=EC=99=B8=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=9C=84=ED=95=B4=20Generated=20=EC=95=A0=EB=84=88?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=EC=9D=84=20=EB=A7=8C=EB=93=A0=20?= =?UTF-8?q?=ED=9B=84,=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/domain/Generated.kt | 11 +++++++ .../dmforu/domain/message/NoticeMessage.kt | 30 +++++++++++++++++++ .../kotlin/com/dmforu/domain/notice/Notice.kt | 4 +++ .../com/dmforu/domain/subscribe/Subscribe.kt | 5 ++++ .../subscribe/OldSubscribeUpdaterTest.kt | 5 ++++ 5 files changed, 55 insertions(+) create mode 100644 dmforu-domain/src/main/kotlin/com/dmforu/domain/Generated.kt create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdaterTest.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/Generated.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/Generated.kt new file mode 100644 index 0000000..7d8c740 --- /dev/null +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/Generated.kt @@ -0,0 +1,11 @@ +package com.dmforu.domain + +import java.lang.annotation.Documented +import kotlin.annotation.AnnotationRetention.RUNTIME +import kotlin.annotation.AnnotationTarget.TYPE +import kotlin.annotation.AnnotationTarget.FUNCTION + +@Documented +@Retention(RUNTIME) +@Target(TYPE, FUNCTION) +annotation class Generated \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/NoticeMessage.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/NoticeMessage.kt index 1dc818c..e6af723 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/NoticeMessage.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/NoticeMessage.kt @@ -1,5 +1,6 @@ package com.dmforu.domain.message +import com.dmforu.domain.Generated import com.dmforu.domain.notice.Notice class NoticeMessage { @@ -39,5 +40,34 @@ class NoticeMessage { .append("[ ").append(keyword).append(" ] ") .append(" 키워드 알림 도착").toString() } + + @Generated + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as NoticeMessage + + if (title != other.title) return false + if (type != other.type) return false + if (body != other.body) return false + if (url != other.url) return false + + return true + } + + @Generated + override fun hashCode(): Int { + var result = title.hashCode() + result = 31 * result + type.hashCode() + result = 31 * result + body.hashCode() + result = 31 * result + url.hashCode() + return result + } + + @Generated + override fun toString(): String { + return "NoticeMessage(title='$title', type='$type', body='$body', url='$url')" + } } diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt index e7cba55..72ac58e 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Notice.kt @@ -1,5 +1,6 @@ package com.dmforu.domain.notice +import com.dmforu.domain.Generated import java.time.LocalDate class Notice private constructor( @@ -37,6 +38,7 @@ class Notice private constructor( return UNIVERSITY == this.type } + @Generated override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -53,6 +55,7 @@ class Notice private constructor( return true } + @Generated override fun hashCode(): Int { var result = number result = 31 * result + type.hashCode() @@ -63,6 +66,7 @@ class Notice private constructor( return result } + @Generated override fun toString(): String { return "Notice(number=$number, type='$type', date=$date, title='$title', author='$author', url='$url')" } diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt index 9446021..98cd6ca 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/Subscribe.kt @@ -1,5 +1,7 @@ package com.dmforu.domain.subscribe +import com.dmforu.domain.Generated + class Subscribe private constructor( val token: String, department: String, @@ -61,6 +63,7 @@ class Subscribe private constructor( this.isKeywordSubscribed = false } + @Generated override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -76,6 +79,7 @@ class Subscribe private constructor( return true } + @Generated override fun hashCode(): Int { var result = token.hashCode() result = 31 * result + department.hashCode() @@ -85,6 +89,7 @@ class Subscribe private constructor( return result } + @Generated override fun toString(): String { return "Subscribe(token='$token', department='$department', keywords=$keywords, isDepartmentSubscribed=$isDepartmentSubscribed, isKeywordSubscribed=$isKeywordSubscribed)" } diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdaterTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdaterTest.kt new file mode 100644 index 0000000..f60835e --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdaterTest.kt @@ -0,0 +1,5 @@ +package com.dmforu.domain.subscribe + +import org.junit.jupiter.api.Assertions.* + +class OldSubscribeUpdaterTest \ No newline at end of file From 54977c140983a97aa5731d733a45744cd1e7533c Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 23 Oct 2024 21:30:43 +0900 Subject: [PATCH 103/223] =?UTF-8?q?test:=20Notice=20=EC=9D=B8=EC=8A=A4?= =?UTF-8?q?=ED=84=B4=EC=8A=A4=20=EC=83=9D=EC=84=B1=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/domain/subscribe/SubscribeTest.kt | 82 +++++++++---------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeTest.kt index 33811b4..9beb1f6 100644 --- a/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeTest.kt +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeTest.kt @@ -7,17 +7,32 @@ import org.junit.jupiter.api.Test class SubscribeTest { + @DisplayName("구독 정보를 생성할 수 있다.") + @Test + fun of() { + //given + val token = "0001" + val department = "컴퓨터소프트웨어공학과" + val keywords = listOf("학사", "봉사") + val isDepartmentSubscribed = true + val isKeywordSubscribed = true + + // when + val subscribe = createSubscribe(token, department, keywords, isDepartmentSubscribed, isKeywordSubscribed) + + // then + assertThat(subscribe.token).isEqualTo(token) + assertThat(subscribe.department).isEqualTo(department) + assertThat(subscribe.keywords).isEqualTo(keywords) + assertThat(subscribe.isDepartmentSubscribed).isEqualTo(isDepartmentSubscribed) + assertThat(subscribe.isKeywordSubscribed).isEqualTo(isKeywordSubscribed) + } + @DisplayName("구독 정보에서 학과를 변경할 수 있다.") @Test fun changeDepartment() { // given - val subscribe = Subscribe.of( - token = "0001", - department = "기계공학과", - keywords = listOf("학사", "봉사"), - isDepartmentSubscribed = true, - isKeywordSubscribed = true - ) + val subscribe = createSubscribe() val changedDepartment = "컴퓨터소프트웨어공학과" @@ -32,13 +47,7 @@ class SubscribeTest { @Test fun subscribeDepartment() { // given - val subscribe = Subscribe.of( - token = "0001", - department = "기계공학과", - keywords = listOf("학사", "봉사"), - isDepartmentSubscribed = true, - isKeywordSubscribed = true - ) + val subscribe = createSubscribe() // when subscribe.subscribeDepartment() @@ -51,13 +60,7 @@ class SubscribeTest { @Test fun unsubscribeDepartment() { // given - val subscribe = Subscribe.of( - token = "0001", - department = "기계공학과", - keywords = listOf("학사", "봉사"), - isDepartmentSubscribed = true, - isKeywordSubscribed = true - ) + val subscribe = createSubscribe() // when subscribe.unsubscribeDepartment() @@ -70,13 +73,7 @@ class SubscribeTest { @Test fun changeKeywords() { // given - val subscribe = Subscribe.of( - token = "0001", - department = "기계공학과", - keywords = listOf("학사", "봉사"), - isDepartmentSubscribed = true, - isKeywordSubscribed = true - ) + val subscribe = createSubscribe() val changedKeywords = listOf("장학", "등록") @@ -91,13 +88,7 @@ class SubscribeTest { @Test fun subscribeKeyword() { // given - val subscribe = Subscribe.of( - token = "0001", - department = "기계공학과", - keywords = listOf("학사", "봉사"), - isDepartmentSubscribed = true, - isKeywordSubscribed = true - ) + val subscribe = createSubscribe() // when subscribe.subscribeKeyword() @@ -110,13 +101,7 @@ class SubscribeTest { @Test fun unsubscribeKeyword() { // given - val subscribe = Subscribe.of( - token = "0001", - department = "기계공학과", - keywords = listOf("학사", "봉사"), - isDepartmentSubscribed = true, - isKeywordSubscribed = true - ) + val subscribe = createSubscribe() // when subscribe.unsubscribeKeyword() @@ -125,4 +110,17 @@ class SubscribeTest { assertFalse(subscribe.isKeywordSubscribed) } + private fun createSubscribe( + token: String = "0001", + department: String = "컴퓨터소프트웨어공학과", + keywords: List = listOf("학사", "봉사"), + isDepartmentSubscribed: Boolean = true, + isKeywordSubscribed: Boolean = true, + ) = Subscribe.of( + token = token, + department = department, + keywords = keywords, + isDepartmentSubscribed = isDepartmentSubscribed, + isKeywordSubscribed = isKeywordSubscribed, + ) } \ No newline at end of file From ccd55567159c3b2ed134a6a652ed199433598acc Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 23 Oct 2024 21:31:46 +0900 Subject: [PATCH 104/223] =?UTF-8?q?test:=20when=EC=97=90=EC=84=9C=20BDDMoc?= =?UTF-8?q?kito=EC=9D=98=20given=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/domain/subscribe/SubscribeUpdaterTest.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeUpdaterTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeUpdaterTest.kt index d2c948d..de9b93c 100644 --- a/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeUpdaterTest.kt +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/SubscribeUpdaterTest.kt @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.BDDMockito.given import org.mockito.InjectMocks import org.mockito.Mock import org.mockito.Mockito.* @@ -29,7 +30,7 @@ class SubscribeUpdaterTest { val keywords = listOf("봉사", "장학") val subscribe = mock(Subscribe::class.java) - `when`(subscribeReader.findById(token)).thenReturn(subscribe) + given(subscribeReader.findById(token)).willReturn(subscribe) // when subscribeUpdater.updateKeywords(token, keywords) @@ -48,7 +49,7 @@ class SubscribeUpdaterTest { val keywordSubscribeStatus = true val subscribe = mock(Subscribe::class.java) - `when`(subscribeReader.findById(token)).thenReturn(subscribe) + given(subscribeReader.findById(token)).willReturn(subscribe) // when subscribeUpdater.updateKeywordSubscribeStatus(token, keywordSubscribeStatus) @@ -67,7 +68,7 @@ class SubscribeUpdaterTest { val keywordSubscribeStatus = false val subscribe = mock(Subscribe::class.java) - `when`(subscribeReader.findById(token)).thenReturn(subscribe) + given(subscribeReader.findById(token)).willReturn(subscribe) // when subscribeUpdater.updateKeywordSubscribeStatus(token, keywordSubscribeStatus) @@ -86,7 +87,7 @@ class SubscribeUpdaterTest { val department = "컴퓨터소프트웨어공학과" val subscribe = mock(Subscribe::class.java) - `when`(subscribeReader.findById(token)).thenReturn(subscribe) + given(subscribeReader.findById(token)).willReturn(subscribe) // when subscribeUpdater.updateDepartment(token, department) @@ -105,7 +106,7 @@ class SubscribeUpdaterTest { val departmentSubscribeStatus = true val subscribe = mock(Subscribe::class.java) - `when`(subscribeReader.findById(token)).thenReturn(subscribe) + given(subscribeReader.findById(token)).willReturn(subscribe) // when subscribeUpdater.updateDepartmentSubscribeStatus(token, departmentSubscribeStatus) @@ -124,7 +125,7 @@ class SubscribeUpdaterTest { val departmentSubscribeStatus = false val subscribe = mock(Subscribe::class.java) - `when`(subscribeReader.findById(token)).thenReturn(subscribe) + given(subscribeReader.findById(token)).willReturn(subscribe) // when subscribeUpdater.updateDepartmentSubscribeStatus(token, departmentSubscribeStatus) From eb7dc968939d9ae0cca250d3f53d8cdb47a1d0ed Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 23 Oct 2024 21:32:11 +0900 Subject: [PATCH 105/223] =?UTF-8?q?test:=20OldSubscribeUpdater=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../subscribe/OldSubscribeUpdaterTest.kt | 99 ++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdaterTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdaterTest.kt index f60835e..1ad8062 100644 --- a/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdaterTest.kt +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdaterTest.kt @@ -1,5 +1,102 @@ package com.dmforu.domain.subscribe import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension -class OldSubscribeUpdaterTest \ No newline at end of file +@ExtendWith(MockitoExtension::class) +class OldSubscribeUpdaterTest { + + @Mock + private lateinit var subscribeReader: SubscribeReader + + @Mock + private lateinit var subscribeWriter: SubscribeWriter + + @InjectMocks + private lateinit var oldSubscribeUpdater: OldSubscribeUpdater + + @DisplayName("토큰과 학과를 가지고, 해당 학과로 알림 구독을 할 수 있다.") + @Test + fun subscribeDepartment() { + // given + val token = "0001" + val department = "컴퓨터소프트웨어공학과" + val subscribe = mock(Subscribe::class.java) + + given(subscribeReader.findById(token)).willReturn(subscribe) + + // when + oldSubscribeUpdater.subscribeDepartment(token, department) + + // then + verify(subscribeReader).findById(token) + verify(subscribe).changeDepartment(department) + verify(subscribe).subscribeDepartment() + verify(subscribeWriter).write(subscribe) + } + + @DisplayName("토큰에 해당하는 구독 정보에서, 학과 알림 구독을 해제할 수 있다.") + @Test + fun unsubscribeDepartment() { + // given + val token = "0001" + val subscribe = mock(Subscribe::class.java) + + given(subscribeReader.findById(token)).willReturn(subscribe) + + // when + oldSubscribeUpdater.unsubscribeDepartment(token) + + // then + verify(subscribeReader).findById(token) + verify(subscribe).unsubscribeDepartment() + verify(subscribeWriter).write(subscribe) + } + + @DisplayName("토큰과 키워드를 가지고, 해당 키워드 알림 구독을 할 수 있다.") + @Test + fun subscribeKeywords() { + // given + val token = "0001" + val keywords = listOf("봉사", "장학") + val subscribe = mock(Subscribe::class.java) + + given(subscribeReader.findById(token)).willReturn(subscribe) + + // when + oldSubscribeUpdater.subscribeKeywords(token = token, keywords = keywords) + + // then + verify(subscribeReader).findById(token) + verify(subscribe).changeKeywords(keywords) + verify(subscribe).subscribeKeyword() + verify(subscribeWriter).write(subscribe) + } + + @DisplayName("토큰에 해당하는 구독 정보에서, 학과 알림 구독을 해제할 수 있다.") + @Test + fun unsubscribeKeywords() { + // given + val token = "0001" + val subscribe = mock(Subscribe::class.java) + + given(subscribeReader.findById(token)).willReturn(subscribe) + + // when + oldSubscribeUpdater.unsubscribeKeywords(token) + + // then + verify(subscribeReader).findById(token) + verify(subscribe).unsubscribeKeyword() + verify(subscribeWriter).write(subscribe) + } + +} \ No newline at end of file From de5002a208cd7659f9e333395b39e4a2da3aa558 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 23 Oct 2024 21:33:51 +0900 Subject: [PATCH 106/223] =?UTF-8?q?refactor:=20subscribe=EC=9D=84=20?= =?UTF-8?q?=ED=94=84=EB=A0=88=EC=9E=84=EC=9B=8C=ED=81=AC=EB=A5=BC=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20POJ?= =?UTF-8?q?O=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/config/ApplicationConfiguration.kt | 29 ++++++++++++ .../domain/subscribe/OldSubscribeUpdater.kt | 3 -- .../domain/subscribe/SubscribeReader.kt | 3 -- .../domain/subscribe/SubscribeUpdater.kt | 47 ++++++++++++------- .../domain/subscribe/SubscribeWriter.kt | 3 -- 5 files changed, 58 insertions(+), 27 deletions(-) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfiguration.kt diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfiguration.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfiguration.kt new file mode 100644 index 0000000..3505f4b --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfiguration.kt @@ -0,0 +1,29 @@ +package com.dmforu.api.config + +import com.dmforu.domain.subscribe.* +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class ApplicationConfiguration { + + @Bean + fun subscribeReader(subscribeRepository: SubscribeRepository): SubscribeReader { + return SubscribeReader(subscribeRepository = subscribeRepository) + } + + @Bean + fun subscribeWriter(subscribeRepository: SubscribeRepository): SubscribeWriter { + return SubscribeWriter(subscribeRepository = subscribeRepository) + } + + @Bean + fun subscribeUpdater(subscribeReader: SubscribeReader, subscribeWriter: SubscribeWriter): SubscribeUpdater { + return SubscribeUpdater(subscribeReader = subscribeReader, subscribeWriter = subscribeWriter) + } + + @Bean + fun oldSubscribeUpdater(subscribeReader: SubscribeReader, subscribeWriter: SubscribeWriter): OldSubscribeUpdater { + return OldSubscribeUpdater(subscribeReader = subscribeReader, subscribeWriter = subscribeWriter) + } +} \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt index 1c12e51..01b6c2f 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/OldSubscribeUpdater.kt @@ -1,9 +1,6 @@ package com.dmforu.domain.subscribe -import org.springframework.stereotype.Service - @Deprecated("구버전 사용자를 위해 남겨둔 Updater 입니다.") -@Service class OldSubscribeUpdater( private val subscribeReader: SubscribeReader, private val subscribeWriter: SubscribeWriter, diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeReader.kt index 95abf49..1f89ec1 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeReader.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeReader.kt @@ -1,8 +1,5 @@ package com.dmforu.domain.subscribe -import org.springframework.stereotype.Service - -@Service class SubscribeReader ( private val subscribeRepository: SubscribeRepository, ){ diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt index 732e948..3ce773c 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeUpdater.kt @@ -1,8 +1,5 @@ package com.dmforu.domain.subscribe -import org.springframework.stereotype.Service - -@Service class SubscribeUpdater( private val subscribeReader: SubscribeReader, private val subscribeWriter: SubscribeWriter, @@ -17,45 +14,59 @@ class SubscribeUpdater( fun updateKeywordSubscribeStatus(token: String, keywordSubscribeStatus: Boolean) { if (keywordSubscribeStatus) { - val subscribe = subscribeReader.findById(token) + subscribeToKeywords(token) + return + } + + unsubscribeToKeywords(token) + } + + fun updateDepartment(token: String, department: String) { + val subscribe = subscribeReader.findById(token) - subscribe.subscribeKeyword() + subscribe.changeDepartment(department) - subscribeWriter.write(subscribe) + subscribeWriter.write(subscribe) + } + fun updateDepartmentSubscribeStatus(token: String, departmentSubscribeStatus: Boolean) { + if (departmentSubscribeStatus) { + subscribeToDepartment(token) return } + unsubscribeToDepartment(token) + } + + private fun subscribeToKeywords(token: String) { val subscribe = subscribeReader.findById(token) - subscribe.unsubscribeKeyword() + subscribe.subscribeKeyword() subscribeWriter.write(subscribe) } - fun updateDepartment(token: String, department: String) { + private fun unsubscribeToKeywords(token: String) { val subscribe = subscribeReader.findById(token) - subscribe.changeDepartment(department) + subscribe.unsubscribeKeyword() subscribeWriter.write(subscribe) } - fun updateDepartmentSubscribeStatus(token: String, departmentSubscribeStatus: Boolean) { - if (departmentSubscribeStatus) { - val subscribe = subscribeReader.findById(token) - - subscribe.subscribeDepartment() + private fun subscribeToDepartment(token: String) { + val subscribe = subscribeReader.findById(token) - subscribeWriter.write(subscribe) + subscribe.subscribeDepartment() - return - } + subscribeWriter.write(subscribe) + } + private fun unsubscribeToDepartment(token: String) { val subscribe = subscribeReader.findById(token) subscribe.unsubscribeDepartment() subscribeWriter.write(subscribe) } -} \ No newline at end of file +} diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeWriter.kt index 5633797..e35d337 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeWriter.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/subscribe/SubscribeWriter.kt @@ -1,8 +1,5 @@ package com.dmforu.domain.subscribe -import org.springframework.stereotype.Service - -@Service class SubscribeWriter( private val subscribeRepository: SubscribeRepository, ) { From 24b55336d10650d00cf15cbaa6ea97bda03c1bb8 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 23 Oct 2024 21:43:25 +0900 Subject: [PATCH 107/223] =?UTF-8?q?test:=20Notice=20=EC=9D=B8=EC=8A=A4?= =?UTF-8?q?=ED=84=B4=EC=8A=A4=20=EC=83=9D=EC=84=B1=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/notice/NoticeTest.kt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeTest.kt index c6bad07..4cdcdbb 100644 --- a/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeTest.kt +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeTest.kt @@ -1,5 +1,6 @@ package com.dmforu.domain.notice +import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test @@ -7,6 +8,29 @@ import java.time.LocalDate class NoticeTest { + @DisplayName("공지를 생성할 수 있다.") + @Test + fun of() { + // given + val number = 10 + val type = "대학" + val date = LocalDate.of(2024, 10, 23) + val title = "공지사항" + val author = "관리자" + val url = "https://www.test.com" + + val notice = Notice.of(number, type, date, title, author, url) + + // when // then + assertThat(notice.number).isEqualTo(number) + assertThat(notice.type).isEqualTo(type) + assertThat(notice.date).isEqualTo(date) + assertThat(notice.title).isEqualTo(title) + assertThat(notice.author).isEqualTo(author) + assertThat(notice.url).isEqualTo(url) + + } + @DisplayName("공지의 번호가 특정 숫자보다 작거나 같은지 확인할 수 있다.") @Test fun isNumberLessThanOrEqualTo() { From 453a60875d33b4adf004099491485fbda8d26337 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 23 Oct 2024 21:49:15 +0900 Subject: [PATCH 108/223] =?UTF-8?q?test:=20Keywords,=20Major=20Enum=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BB=A4=EB=B2=84=EB=A6=AC=EC=A7=80=EC=97=90=20=ED=8F=AC?= =?UTF-8?q?=ED=95=A8=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=9E=84=EC=8B=9C=20=EC=A1=B0=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/dmforu/domain/Generated.kt | 8 +++----- .../src/main/kotlin/com/dmforu/domain/message/Keywords.kt | 3 +++ .../src/main/kotlin/com/dmforu/domain/notice/Major.kt | 3 +++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/Generated.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/Generated.kt index 7d8c740..37801db 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/Generated.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/Generated.kt @@ -1,11 +1,9 @@ package com.dmforu.domain -import java.lang.annotation.Documented import kotlin.annotation.AnnotationRetention.RUNTIME -import kotlin.annotation.AnnotationTarget.TYPE -import kotlin.annotation.AnnotationTarget.FUNCTION +import kotlin.annotation.AnnotationTarget.* -@Documented +@MustBeDocumented @Retention(RUNTIME) -@Target(TYPE, FUNCTION) +@Target(TYPE, FUNCTION, CLASS) annotation class Generated \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/Keywords.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/Keywords.kt index 5d32da2..07d38a4 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/Keywords.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/message/Keywords.kt @@ -1,5 +1,8 @@ package com.dmforu.domain.message +import com.dmforu.domain.Generated + +@Generated enum class Keywords (val korean: String){ EXAM("시험"), SIGN_UP("수강"), diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Major.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Major.kt index 1557591..2b1578e 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Major.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/Major.kt @@ -1,5 +1,8 @@ package com.dmforu.domain.notice +import com.dmforu.domain.Generated + +@Generated enum class Major(val type: String, val majorPath: String, val noticePath: String) { // 기계공학부 MECHANICAL_ENGINEERING_DEPARTMENT("기계공학과", "dmu_23205", "1707"), From d247b04addef42782e9ee681b973b449c9a71041 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 23 Oct 2024 21:49:46 +0900 Subject: [PATCH 109/223] =?UTF-8?q?test:=20Notice=20Message=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/domain/message/NoticeMessageTest.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/message/NoticeMessageTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/message/NoticeMessageTest.kt index be0026b..da427be 100644 --- a/dmforu-domain/src/test/kotlin/com/dmforu/domain/message/NoticeMessageTest.kt +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/message/NoticeMessageTest.kt @@ -13,6 +13,8 @@ class NoticeMessageTest { @Test fun createUniversityNoticeMessage() { // given + val keyword = "시험" + val notice = Notice.of( number = 10, type = "대학", @@ -22,13 +24,14 @@ class NoticeMessageTest { url = "https://www.test.com" ) - val keyword = "시험" - // when val message = NoticeMessage.createUniversityNoticeMessage(notice = notice, keyword = keyword) // then assertThat(message.title).isEqualTo("[ " + keyword + " ] 키워드 알림 도착") + assertThat(message.type).isEqualTo(notice.type) + assertThat(message.url).isEqualTo(notice.url) + assertThat(message.body).isEqualTo(notice.title) } @@ -50,6 +53,9 @@ class NoticeMessageTest { // then assertThat(message.title).isEqualTo("[ " + notice.type + " ] 키워드 알림 도착") + assertThat(message.type).isEqualTo(notice.type) + assertThat(message.url).isEqualTo(notice.url) + assertThat(message.body).isEqualTo(notice.title) } } \ No newline at end of file From 95541fa4f8d1c948e352367cf75df2fa1cb2daf1 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 23 Oct 2024 22:41:21 +0900 Subject: [PATCH 110/223] =?UTF-8?q?test:=20Schedule,=20Reader,=20Writer=20?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A1=9C=EC=A7=81=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/crawling/ScheduleParser.kt | 6 +- .../com/dmforu/domain/schedule/Schedule.kt | 48 +++++++++----- .../domain/schedule/ScheduleReaderTest.kt | 62 +++++++++++++++++++ .../dmforu/domain/schedule/ScheduleTest.kt | 34 ++++++++++ .../domain/schedule/ScheduleWriterTest.kt | 39 ++++++++++++ 5 files changed, 169 insertions(+), 20 deletions(-) create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleReaderTest.kt create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleTest.kt create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleWriterTest.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt index 5e59fca..1ab6873 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt @@ -14,7 +14,7 @@ class ScheduleParser : Parser { // 작년부터 내년의 일정을 가져온다. return (currentYear - 1..currentYear + 1).map { year -> val yearSchedule = fetchYearSchedule(year) - Schedule.Year(year, yearSchedule) + Schedule.Year.of(year, yearSchedule) } } @@ -41,7 +41,7 @@ class ScheduleParser : Parser { val scheduleTable = monthTable.select(MONTH_SCHEDULE_SELECTOR) val monthSchedule = scheduleTable.map { schedule -> parseSchedule(schedule) } - return Schedule.Month(month, monthSchedule) + return Schedule.Month.of(month, monthSchedule) } private fun extractMonth(monthText: String): Int { @@ -68,7 +68,7 @@ class ScheduleParser : Parser { val content = schedule.select(SCHEDULE_CONTENT_SELECTOR).text() - return Schedule(dates.toTypedArray(), content) + return Schedule.of(dates.toTypedArray(), content) } companion object { diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt index db2589f..4bdff2a 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt @@ -1,30 +1,44 @@ package com.dmforu.domain.schedule -data class Schedule( - val date: String, - val content: String +class Schedule private constructor( + dateArray: Array, + val content: String, ) { - private constructor() : this("", "") + val date: String = dateConverter(dateArray) - constructor(dateArray: Array, content: String) : this( - dateArray.joinToString( - prefix = "[", - separator = ", ", - postfix = "]" - ), content - ) + companion object { + fun of(dateArray: Array, content: String): Schedule { + return Schedule(dateArray, content) + } + } - data class Month( + class Month private constructor( val month: Int, - val monthSchedule: List + val monthSchedule: List, ) { - private constructor() : this(0, emptyList()) + companion object { + fun of(month: Int, monthSchedule: List): Month { + return Month(month, monthSchedule) + } + } } - data class Year( + class Year private constructor( val year: Int, - val yearSchedule: List + val yearSchedule: List, ) { - private constructor() : this(0, emptyList()) + companion object { + fun of(year: Int, yearSchedule: List): Year { + return Year(year, yearSchedule) + } + } + } + + private fun dateConverter(dateArray: Array): String { + return dateArray.joinToString( + prefix = "[", + separator = ", ", + postfix = "]" + ) } } \ No newline at end of file diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleReaderTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleReaderTest.kt new file mode 100644 index 0000000..b938cd1 --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleReaderTest.kt @@ -0,0 +1,62 @@ +package com.dmforu.domain.schedule + + +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension + +@ExtendWith(MockitoExtension::class) +class ScheduleReaderTest { + + @Mock + private lateinit var scheduleRepository: ScheduleRepository + + @InjectMocks + private lateinit var scheduleReader: ScheduleReader + + @DisplayName("학사 일정이 존재하는 경우 학사 일정을 불러온다.") + @Test + fun read() { + // given + val date = arrayOf("01.03 (수)", "01.05 (목)") + val expectedDate = "[01.03 (수), 01.05 (목)]" + val content = "정시모집 원서 접수" + val month = 1 + val year = 2024 + + val schedule = Schedule.of(date, content) + val scheduleMonth = Schedule.Month.of(month, listOf(schedule)) + val scheduleYear = Schedule.Year.of(year, listOf(scheduleMonth)) + val expectedSchedules = listOf(scheduleYear) + given(scheduleReader.read()).willReturn(expectedSchedules) + + // when + val schedules = scheduleReader.read() + + // then + verify(scheduleRepository).read() + + } + + @DisplayName("학사 일정이 존재하지 않는 경우 예외가 발생한다.") + @Test + fun readWhenReturnNull() { + // given + given(scheduleReader.read()).willReturn(null) + + // when // then + assertThatThrownBy{scheduleReader.read() } + .isInstanceOf(IllegalArgumentException::class.java) + .hasMessage("No schedule exists 관리자 에러") + + verify(scheduleRepository).read() + } +} \ No newline at end of file diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleTest.kt new file mode 100644 index 0000000..a243c74 --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleTest.kt @@ -0,0 +1,34 @@ +package com.dmforu.domain.schedule + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +class ScheduleTest { + + @DisplayName("학사 일정을 생성할 수 있다.") + @Test + fun of() { + // given + val date = arrayOf("01.03 (수)", "01.05 (목)") + val expectedDate = "[01.03 (수), 01.05 (목)]" + val content = "정시모집 원서 접수" + val month = 1 + val year = 2024 + + // when + val schedule = Schedule.of(date, content) + val scheduleMonth = Schedule.Month.of(month, listOf(schedule)) + val scheduleYear = Schedule.Year.of(year, listOf(scheduleMonth)) + val schedules = listOf(scheduleYear) + + // then + assertThat(schedules[0].year).isEqualTo(year) + assertThat(schedules[0].yearSchedule[0].month).isEqualTo(month) + assertThat(schedules[0].yearSchedule[0].monthSchedule[0].date).isEqualTo(expectedDate) + assertThat(schedules[0].yearSchedule[0].monthSchedule[0].content).isEqualTo(content) + + } + +} \ No newline at end of file diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleWriterTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleWriterTest.kt new file mode 100644 index 0000000..97e8b20 --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleWriterTest.kt @@ -0,0 +1,39 @@ +package com.dmforu.domain.schedule + +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension + +@ExtendWith(MockitoExtension::class) +class ScheduleWriterTest { + + @Mock + private lateinit var scheduleRepository: ScheduleRepository + + @InjectMocks + private lateinit var scheduleWriter: ScheduleWriter + + @DisplayName("학사 일정 정보를 저장할 수 있다.") + @Test + fun write() { + // given + val date = arrayOf("01.03 (수)", "01.05 (목)") + val content = "정시모집 원서 접수" + val schedule = Schedule.of(date, content) + val scheduleMonth = Schedule.Month.of(1, listOf(schedule)) + val scheduleYear = Schedule.Year.of(2024, listOf(scheduleMonth)) + val schedules = listOf(scheduleYear) + + // when + scheduleWriter.overwrite(schedules) + + // given + verify(scheduleRepository).write(schedules) + + } + +} \ No newline at end of file From 8e4a5fc196497887df575b0d53aa9875fb7c0e24 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 23 Oct 2024 23:19:20 +0900 Subject: [PATCH 111/223] =?UTF-8?q?test:=20Diet,=20Reader,=20Writer=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/crawling/DietParser.kt | 2 +- .../kotlin/com/dmforu/domain/diet/Diet.kt | 12 +++- .../com/dmforu/domain/diet/DietReaderTest.kt | 56 +++++++++++++++++++ .../kotlin/com/dmforu/domain/diet/DietTest.kt | 26 +++++++++ .../com/dmforu/domain/diet/DietWriterTest.kt | 38 +++++++++++++ .../domain/schedule/ScheduleReaderTest.kt | 6 +- 6 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/diet/DietReaderTest.kt create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/diet/DietTest.kt create mode 100644 dmforu-domain/src/test/kotlin/com/dmforu/domain/diet/DietWriterTest.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt index bda989f..beb0399 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt @@ -39,7 +39,7 @@ class DietParser : Parser { ?.map { it.trim() } ?: emptyList() - return Diet(parsedDate, menus) + return Diet.of(parsedDate, menus) } companion object { diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt index 36985ab..c1455bc 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt @@ -2,7 +2,13 @@ package com.dmforu.domain.diet import java.time.LocalDate -data class Diet( +class Diet private constructor( val date: LocalDate, - val menus: List -) + val menus: List, +) { + companion object { + fun of(date: LocalDate, menus: List): Diet { + return Diet(date, menus) + } + } +} diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/diet/DietReaderTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/diet/DietReaderTest.kt new file mode 100644 index 0000000..6650417 --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/diet/DietReaderTest.kt @@ -0,0 +1,56 @@ +package com.dmforu.domain.diet + +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension +import java.time.LocalDate + +@ExtendWith(MockitoExtension::class) +class DietReaderTest { + + @Mock + private lateinit var dietRepository: DietRepository + + @InjectMocks + private lateinit var dietReader: DietReader + + @DisplayName("식단을 불러온다.") + @Test + fun read() { + // given + val date = LocalDate.of(2024, 10, 23) + val menus = listOf("메뉴1", "메뉴2", "메뉴3") + val diet = Diet.of(date = date, menus = menus) + + given(dietReader.read()).willReturn(listOf(diet)) + + // when + dietReader.read() + + // then + verify(dietRepository).read() + + } + + @DisplayName("식단이 존재하지 않는 경우 예외가 발생한다.") + @Test + fun readWhenReturnNull() { + // given + given(dietReader.read()).willReturn(null) + + // when // then + assertThatThrownBy { dietReader.read() } + .isInstanceOf(IllegalArgumentException::class.java) + .hasMessage("식단 정보가 존재하지 않습니다. 관리자 에러") + + verify(dietRepository).read() + } + +} \ No newline at end of file diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/diet/DietTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/diet/DietTest.kt new file mode 100644 index 0000000..e3b87b5 --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/diet/DietTest.kt @@ -0,0 +1,26 @@ +package com.dmforu.domain.diet + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import java.time.LocalDate + +class DietTest { + + @DisplayName("식단을 생성할 수 있다.") + @Test + fun of() { + // given + val date = LocalDate.of(2024, 10, 23) + val menus = listOf("메뉴1", "메뉴2", "메뉴3") + + // when + val diet = Diet.of(date = date, menus = menus) + + // then + assertThat(diet.date).isEqualTo(date) + assertThat(diet.menus).isEqualTo(menus) + } + +} \ No newline at end of file diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/diet/DietWriterTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/diet/DietWriterTest.kt new file mode 100644 index 0000000..3ec3f20 --- /dev/null +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/diet/DietWriterTest.kt @@ -0,0 +1,38 @@ +package com.dmforu.domain.diet + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension +import java.time.LocalDate + +@ExtendWith(MockitoExtension::class) +class DietWriterTest { + + @Mock + private lateinit var dietRepository: DietRepository + + @InjectMocks + private lateinit var dietWriter: DietWriter + + @DisplayName("식단 정보를 저장할 수 있다.") + @Test + fun write() { + // given + val date = LocalDate.of(2024, 10, 23) + val menus = listOf("메뉴1", "메뉴2", "메뉴3") + val diet = Diet.of(date = date, menus = menus) + val diets = listOf(diet) + + // when + dietWriter.overwrite(diets) + + // given + verify(dietRepository).write(diets) + + } +} \ No newline at end of file diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleReaderTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleReaderTest.kt index b938cd1..c08e370 100644 --- a/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleReaderTest.kt +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleReaderTest.kt @@ -22,7 +22,7 @@ class ScheduleReaderTest { @InjectMocks private lateinit var scheduleReader: ScheduleReader - @DisplayName("학사 일정이 존재하는 경우 학사 일정을 불러온다.") + @DisplayName("학사 일정을 불러온다.") @Test fun read() { // given @@ -39,7 +39,7 @@ class ScheduleReaderTest { given(scheduleReader.read()).willReturn(expectedSchedules) // when - val schedules = scheduleReader.read() + scheduleReader.read() // then verify(scheduleRepository).read() @@ -53,7 +53,7 @@ class ScheduleReaderTest { given(scheduleReader.read()).willReturn(null) // when // then - assertThatThrownBy{scheduleReader.read() } + assertThatThrownBy { scheduleReader.read() } .isInstanceOf(IllegalArgumentException::class.java) .hasMessage("No schedule exists 관리자 에러") From 8607af5690dd75e731799c5c769d9c1be1a76850 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 23 Oct 2024 23:20:59 +0900 Subject: [PATCH 112/223] =?UTF-8?q?refactor:=20domain=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=20Spring=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 13 ++++-------- .../api/config/ApplicationConfiguration.kt | 21 +++++++++++++++++++ dmforu-domain/build.gradle.kts | 3 ++- .../com/dmforu/domain/diet/DietReader.kt | 5 +---- .../com/dmforu/domain/diet/DietWriter.kt | 3 --- .../com/dmforu/domain/notice/NoticeReader.kt | 3 --- .../com/dmforu/domain/notice/NoticeWriter.kt | 3 --- .../dmforu/domain/schedule/ScheduleReader.kt | 3 --- .../dmforu/domain/schedule/ScheduleWriter.kt | 3 --- 9 files changed, 28 insertions(+), 29 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index e5ab45b..9004fbe 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -31,17 +31,12 @@ subprojects { apply(plugin = "io.spring.dependency-management") apply(plugin = "jacoco") - dependencyManagement { - val springCloudDependenciesVersion: String by project - imports { - mavenBom("org.springframework.cloud:spring-cloud-dependencies:${springCloudDependenciesVersion}") - } - } - dependencies { - implementation("org.springframework.boot:spring-boot-starter") implementation("org.jetbrains.kotlin:kotlin-reflect") - testImplementation("org.springframework.boot:spring-boot-starter-test") + if (project.name != "dmforu-domain") { + implementation("org.springframework.boot:spring-boot-starter") + testImplementation("org.springframework.boot:spring-boot-starter-test") + } testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") testRuntimeOnly("org.junit.platform:junit-platform-launcher") } diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfiguration.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfiguration.kt index 3505f4b..ed8fe25 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfiguration.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfiguration.kt @@ -1,5 +1,11 @@ package com.dmforu.api.config +import com.dmforu.domain.diet.DietReader +import com.dmforu.domain.diet.DietRepository +import com.dmforu.domain.notice.NoticeReader +import com.dmforu.domain.notice.NoticeRepository +import com.dmforu.domain.schedule.ScheduleReader +import com.dmforu.domain.schedule.ScheduleRepository import com.dmforu.domain.subscribe.* import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -26,4 +32,19 @@ class ApplicationConfiguration { fun oldSubscribeUpdater(subscribeReader: SubscribeReader, subscribeWriter: SubscribeWriter): OldSubscribeUpdater { return OldSubscribeUpdater(subscribeReader = subscribeReader, subscribeWriter = subscribeWriter) } + + @Bean + fun noticeReader(noticeRepository: NoticeRepository): NoticeReader { + return NoticeReader(noticeRepository = noticeRepository) + } + + @Bean + fun scheduleReader(scheduleRepository: ScheduleRepository): ScheduleReader { + return ScheduleReader(scheduleRepository = scheduleRepository) + } + + @Bean + fun dietReader(dietRepository: DietRepository): DietReader { + return DietReader(dietRepository = dietRepository) + } } \ No newline at end of file diff --git a/dmforu-domain/build.gradle.kts b/dmforu-domain/build.gradle.kts index f704ab1..c7fd8f2 100644 --- a/dmforu-domain/build.gradle.kts +++ b/dmforu-domain/build.gradle.kts @@ -1,3 +1,4 @@ dependencies { - compileOnly("org.springframework:spring-context") + testImplementation("org.mockito:mockito-core") + testImplementation("org.assertj:assertj-core") } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt index e4a025f..c7a722d 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietReader.kt @@ -1,13 +1,10 @@ package com.dmforu.domain.diet -import org.springframework.stereotype.Component - -@Component class DietReader( private val dietRepository: DietRepository, ) { // TODO fun read(): List { - return dietRepository.read() ?: throw IllegalStateException("식단 정보가 존재하지 않습니다. 관리자 에러") + return dietRepository.read() ?: throw IllegalArgumentException("식단 정보가 존재하지 않습니다. 관리자 에러") } } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietWriter.kt index c720257..917eb2c 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietWriter.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/DietWriter.kt @@ -1,8 +1,5 @@ package com.dmforu.domain.diet -import org.springframework.stereotype.Component - -@Component class DietWriter( private val dietRepository: DietRepository ) { diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeReader.kt index 600a01d..433b951 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeReader.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeReader.kt @@ -1,8 +1,5 @@ package com.dmforu.domain.notice -import org.springframework.stereotype.Component - -@Component class NoticeReader( private val noticeRepository: NoticeRepository ) { diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt index a873634..9c2d687 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt @@ -1,8 +1,5 @@ package com.dmforu.domain.notice -import org.springframework.stereotype.Component - -@Component class NoticeWriter( private val noticeRepository: NoticeRepository, ) { diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt index 7a36b8d..a9cb014 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleReader.kt @@ -1,8 +1,5 @@ package com.dmforu.domain.schedule -import org.springframework.stereotype.Component - -@Component class ScheduleReader( private val scheduleRepository: ScheduleRepository ) { diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt index 356576d..8c81657 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/ScheduleWriter.kt @@ -1,8 +1,5 @@ package com.dmforu.domain.schedule -import org.springframework.stereotype.Component - -@Component class ScheduleWriter( private val scheduleRepository: ScheduleRepository ) { From 66e2b46ead212f75937724d047d4c7d430f54f82 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 01:10:20 +0900 Subject: [PATCH 113/223] =?UTF-8?q?fix:=20domain=20=EB=AA=A8=EB=93=88=20Sp?= =?UTF-8?q?ring=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EC=88=98=EB=8F=99=20=EB=B9=88?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/config/ApplicationConfiguration.kt | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt new file mode 100644 index 0000000..43492ee --- /dev/null +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt @@ -0,0 +1,41 @@ +package com.dmforu.admin.config + +import com.dmforu.domain.diet.DietRepository +import com.dmforu.domain.diet.DietWriter +import com.dmforu.domain.notice.NoticeReader +import com.dmforu.domain.notice.NoticeRepository +import com.dmforu.domain.notice.NoticeWriter +import com.dmforu.domain.schedule.ScheduleRepository +import com.dmforu.domain.schedule.ScheduleWriter +import com.dmforu.domain.subscribe.* +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class ApplicationConfiguration { + + @Bean + fun subscribeReader(subscribeRepository: SubscribeRepository): SubscribeReader { + return SubscribeReader(subscribeRepository = subscribeRepository) + } + + @Bean + fun noticeReader(noticeRepository: NoticeRepository): NoticeReader { + return NoticeReader(noticeRepository = noticeRepository) + } + + @Bean + fun noticeWriter(noticeRepository: NoticeRepository): NoticeWriter { + return NoticeWriter(noticeRepository = noticeRepository) + } + + @Bean + fun scheduleWriter(scheduleRepository: ScheduleRepository): ScheduleWriter { + return ScheduleWriter(scheduleRepository = scheduleRepository) + } + + @Bean + fun dietWriter(dietRepository: DietRepository): DietWriter { + return DietWriter(dietRepository = dietRepository) + } +} \ No newline at end of file From 59bbe85a5eb1ef43f723fc48dceadfe4ddfc0f6b Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 01:19:12 +0900 Subject: [PATCH 114/223] =?UTF-8?q?style:=20import=EB=AC=B8=EC=9D=B4=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9=EB=90=98=EC=A7=80=20=EC=95=8A=EC=95=98?= =?UTF-8?q?=EB=8D=98=20=EA=B3=B3=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt index 634df56..8fd49f4 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt @@ -6,6 +6,8 @@ import org.springframework.context.annotation.Scope import org.springframework.stereotype.Component import java.lang.NumberFormatException import java.time.LocalDate +import java.time.format.DateTimeFormatter +import java.util.regex.Pattern @Scope("prototype") @Component @@ -93,9 +95,7 @@ class DepartmentNoticeParser : UrlGenerator(), Parser { } companion object { - private val pattern: java.util.regex.Pattern = - java.util.regex.Pattern.compile("\\('([^']+)'\\,'([^']+)'\\,'([^']+)'\\,'([^']+)'") - private val formatter: java.time.format.DateTimeFormatter = - java.time.format.DateTimeFormatter.ofPattern("yyyy.MM.dd") + private val pattern: Pattern = Pattern.compile("\\('([^']+)'\\,'([^']+)'\\,'([^']+)'\\,'([^']+)'") + private val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") } } \ No newline at end of file From 32c35455f3cf64c67002630bf954e153ec564f5f Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 01:34:04 +0900 Subject: [PATCH 115/223] =?UTF-8?q?refactor:=20crawling=20=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20Spring=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20=EB=B0=8F=20=EB=B9=88=20=EB=93=B1=EB=A1=9D=20Config?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 2 +- .../com/dmforu/admin/AdminApplication.kt | 2 -- .../admin/config/ApplicationConfiguration.kt | 27 +++++++++++++++++++ .../DepartmentNoticeCrawlingService.kt | 4 +-- .../UniversityNoticeCrawlingService.kt | 2 +- dmforu-crawling/build.gradle.kts | 2 -- .../dmforu/crawling/DepartmentNoticeParser.kt | 4 --- .../kotlin/com/dmforu/crawling/DietParser.kt | 2 -- .../com/dmforu/crawling/ScheduleParser.kt | 2 -- .../dmforu/crawling/UniversityNoticeParser.kt | 4 --- 10 files changed, 31 insertions(+), 20 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9004fbe..7dfae3a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,7 +33,7 @@ subprojects { dependencies { implementation("org.jetbrains.kotlin:kotlin-reflect") - if (project.name != "dmforu-domain") { + if (project.name != "dmforu-domain" && project.name != "dmforu-crawling") { implementation("org.springframework.boot:spring-boot-starter") testImplementation("org.springframework.boot:spring-boot-starter-test") } diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt index a41f52b..86e8891 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt @@ -7,8 +7,6 @@ import org.springframework.scheduling.annotation.EnableScheduling @SpringBootApplication( scanBasePackages = [ "com.dmforu.admin", - "com.dmforu.domain", - "com.dmforu.crawling", "com.dmforu.fcm", "com.dmforu.storage.db.redis", "com.dmforu.storage.db.mysql" diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt index 43492ee..3d58122 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt @@ -1,5 +1,9 @@ package com.dmforu.admin.config +import com.dmforu.crawling.DepartmentNoticeParser +import com.dmforu.crawling.DietParser +import com.dmforu.crawling.ScheduleParser +import com.dmforu.crawling.UniversityNoticeParser import com.dmforu.domain.diet.DietRepository import com.dmforu.domain.diet.DietWriter import com.dmforu.domain.notice.NoticeReader @@ -10,6 +14,7 @@ import com.dmforu.domain.schedule.ScheduleWriter import com.dmforu.domain.subscribe.* import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Scope @Configuration class ApplicationConfiguration { @@ -38,4 +43,26 @@ class ApplicationConfiguration { fun dietWriter(dietRepository: DietRepository): DietWriter { return DietWriter(dietRepository = dietRepository) } + + @Scope("prototype") + @Bean + fun departmentNoticeParser(): DepartmentNoticeParser { + return DepartmentNoticeParser() + } + + @Scope("prototype") + @Bean + fun universityNoticeParser(): UniversityNoticeParser { + return UniversityNoticeParser() + } + + @Bean + fun dietParser(): DietParser { + return DietParser() + } + + @Bean + fun scheduleParser(): ScheduleParser { + return ScheduleParser() + } } \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index f9fc572..635ca21 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -9,9 +9,9 @@ import org.springframework.stereotype.Service @Service class DepartmentNoticeCrawlingService( private val prototypeBeanProvider: ObjectProvider, - private val noticeWriter: NoticeWriter, - private val noticeReader: NoticeReader, private val applicationEventPublisher: ApplicationEventPublisher, + private val noticeReader: NoticeReader, + private val noticeWriter: NoticeWriter, ) { /** * Major 열거형의 모든 값을 반복하여 모든 학과의 공지사항을 크롤링한다.

diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt index f9d31ac..18ddbdb 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt @@ -13,8 +13,8 @@ import org.springframework.stereotype.Service class UniversityNoticeCrawlingService( private val prototypeBeanProvider: ObjectProvider, private val applicationEventPublisher: ApplicationEventPublisher, - private val noticeWriter: NoticeWriter, private val noticeReader: NoticeReader, + private val noticeWriter: NoticeWriter, ) { /** * 모든 대학 공지사항을 크롤링한다.

diff --git a/dmforu-crawling/build.gradle.kts b/dmforu-crawling/build.gradle.kts index 8164988..96a4ff1 100644 --- a/dmforu-crawling/build.gradle.kts +++ b/dmforu-crawling/build.gradle.kts @@ -3,6 +3,4 @@ val jsoupVersion: String by project dependencies { compileOnly(project(":dmforu-domain")) implementation("org.jsoup:jsoup:${jsoupVersion}") - - compileOnly("org.springframework:spring-context") } \ No newline at end of file diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt index 8fd49f4..aee25cf 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt @@ -2,15 +2,11 @@ package com.dmforu.crawling import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.Major -import org.springframework.context.annotation.Scope -import org.springframework.stereotype.Component import java.lang.NumberFormatException import java.time.LocalDate import java.time.format.DateTimeFormatter import java.util.regex.Pattern -@Scope("prototype") -@Component class DepartmentNoticeParser : UrlGenerator(), Parser { private lateinit var major: Major diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt index beb0399..7b971c6 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt @@ -2,11 +2,9 @@ package com.dmforu.crawling import com.dmforu.domain.diet.Diet import org.jsoup.nodes.Element -import org.springframework.stereotype.Service import java.time.LocalDate import java.time.format.DateTimeFormatter -@Service class DietParser : Parser { override fun parse(): List { val document = WebPageLoader.getHTML(DMU_DIET_URL) diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt index 1ab6873..a42d44a 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt @@ -2,11 +2,9 @@ package com.dmforu.crawling import com.dmforu.domain.schedule.Schedule import org.jsoup.nodes.Element -import org.springframework.stereotype.Service import java.time.LocalDate import java.time.ZoneId -@Service class ScheduleParser : Parser { override fun parse(): List { val currentYear = LocalDate.now(ZoneId.of(TIME_ZONE)).year diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt index 4331e0f..e478ea9 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt @@ -1,14 +1,10 @@ package com.dmforu.crawling import com.dmforu.domain.notice.Notice -import org.springframework.context.annotation.Scope -import org.springframework.stereotype.Component import java.lang.NumberFormatException import java.time.LocalDate import java.time.format.DateTimeFormatter -@Scope("prototype") -@Component class UniversityNoticeParser : UrlGenerator(), Parser { private var pageNumber = 1 From 2cdfde4be34be81fe4ce6c1b592ee1b42f57cfdf Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 03:29:17 +0900 Subject: [PATCH 116/223] =?UTF-8?q?refactor:=20mockito=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20domain=20?= =?UTF-8?q?testImplementation=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-crawling/build.gradle.kts | 7 +++++++ .../crawling/{WebPageLoader.kt => JsoupWebPageLoader.kt} | 9 ++------- 2 files changed, 9 insertions(+), 7 deletions(-) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{WebPageLoader.kt => JsoupWebPageLoader.kt} (65%) diff --git a/dmforu-crawling/build.gradle.kts b/dmforu-crawling/build.gradle.kts index 96a4ff1..c50308e 100644 --- a/dmforu-crawling/build.gradle.kts +++ b/dmforu-crawling/build.gradle.kts @@ -2,5 +2,12 @@ val jsoupVersion: String by project dependencies { compileOnly(project(":dmforu-domain")) + implementation("org.jsoup:jsoup:${jsoupVersion}") + + testImplementation(project(":dmforu-domain")) + testImplementation("org.mockito:mockito-core") + testImplementation("org.mockito:mockito-junit-jupiter") + testImplementation("org.mockito:mockito-inline:5.2.0") + testImplementation("org.assertj:assertj-core") } \ No newline at end of file diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/JsoupWebPageLoader.kt similarity index 65% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/JsoupWebPageLoader.kt index 2ab1349..7545538 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/JsoupWebPageLoader.kt @@ -5,12 +5,7 @@ import org.jsoup.nodes.Document import java.io.IOException object WebPageLoader { - /** - * Jsoup을 사용하여 URL에 해당하는 웹 페이지의 HTML을 가져온다. - * - * @param url HTML을 가져오고자 하는 웹 페이지의 URL - * @return URL에 접속하면 볼 수 있는 HTML을 반환 - */ + @JvmStatic fun getHTML(url: String?): Document { if (url.isNullOrBlank()) { @@ -21,7 +16,7 @@ object WebPageLoader { Jsoup.connect(url).get() } catch (e: IOException) { // TODO: 페이지 로딩 실패나 네트워크 오류인 경우 핸들링을 해야함 - throw IllegalArgumentException() + throw IllegalArgumentException("해당하는 URL 의 HTML을 불러올 수 없습니다.") } } } \ No newline at end of file From 845aae385c49070c9fc74b83bbbf5aeced68959f Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 03:30:10 +0900 Subject: [PATCH 117/223] =?UTF-8?q?refactor:=20=EC=99=B8=EB=B6=80=20?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EB=8A=94=20Static=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=EB=A5=BC=20Interface=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/crawling/DepartmentNoticeParser.kt | 7 +++++-- .../src/main/kotlin/com/dmforu/crawling/DietParser.kt | 7 +++++-- .../kotlin/com/dmforu/crawling/JsoupWebPageLoader.kt | 10 ++-------- .../main/kotlin/com/dmforu/crawling/ScheduleParser.kt | 7 +++++-- .../com/dmforu/crawling/UniversityNoticeParser.kt | 7 +++++-- .../main/kotlin/com/dmforu/crawling/WebPageLoader.kt | 5 +++++ 6 files changed, 27 insertions(+), 16 deletions(-) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt index aee25cf..25b14e9 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt @@ -2,12 +2,15 @@ package com.dmforu.crawling import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.Major +import org.jsoup.nodes.Document import java.lang.NumberFormatException import java.time.LocalDate import java.time.format.DateTimeFormatter import java.util.regex.Pattern -class DepartmentNoticeParser : UrlGenerator(), Parser { +class DepartmentNoticeParser( + private val webPageLoader: WebPageLoader, +) : UrlGenerator(), Parser { private lateinit var major: Major private var pageNumber: Int = 1 @@ -25,7 +28,7 @@ class DepartmentNoticeParser : UrlGenerator(), Parser { val departmentNotices: MutableList = java.util.ArrayList() - val document = WebPageLoader.getHTML(generateSearchUrl()) + val document = webPageLoader.getHTML(generateSearchUrl()) val rows = document.select(".board-table tbody tr") diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt index 7b971c6..e4ccd56 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt @@ -1,13 +1,16 @@ package com.dmforu.crawling import com.dmforu.domain.diet.Diet +import org.jsoup.nodes.Document import org.jsoup.nodes.Element import java.time.LocalDate import java.time.format.DateTimeFormatter -class DietParser : Parser { +class DietParser ( + private val webPageLoader: WebPageLoader +) : Parser { override fun parse(): List { - val document = WebPageLoader.getHTML(DMU_DIET_URL) + val document = webPageLoader.getHTML(DMU_DIET_URL) val rows = document.select(TABLE_SELECTOR) return rows.mapNotNull { row -> parseDiet(row) } diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/JsoupWebPageLoader.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/JsoupWebPageLoader.kt index 7545538..58452ef 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/JsoupWebPageLoader.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/JsoupWebPageLoader.kt @@ -4,14 +4,8 @@ import org.jsoup.Jsoup import org.jsoup.nodes.Document import java.io.IOException -object WebPageLoader { - - @JvmStatic - fun getHTML(url: String?): Document { - if (url.isNullOrBlank()) { - throw IllegalArgumentException("URL이 비어있거나 잘못되었습니다.") - } - +class JsoupWebPageLoader : WebPageLoader { + override fun getHTML(url: String): Document { return try { Jsoup.connect(url).get() } catch (e: IOException) { diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt index a42d44a..0131814 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt @@ -1,11 +1,14 @@ package com.dmforu.crawling import com.dmforu.domain.schedule.Schedule +import org.jsoup.nodes.Document import org.jsoup.nodes.Element import java.time.LocalDate import java.time.ZoneId -class ScheduleParser : Parser { +class ScheduleParser( + private val webPageLoader: WebPageLoader, +) : Parser { override fun parse(): List { val currentYear = LocalDate.now(ZoneId.of(TIME_ZONE)).year @@ -17,7 +20,7 @@ class ScheduleParser : Parser { } private fun fetchYearSchedule(year: Int): List { - val document = WebPageLoader.getHTML(DMU_SCHEDULE_URL + year) + val document = webPageLoader.getHTML(DMU_SCHEDULE_URL + year) val monthTables = document.select(YEAR_SCHEDULE_SELECTOR) return monthTables.mapNotNull { monthTable -> diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt index e478ea9..11387b5 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt @@ -1,11 +1,14 @@ package com.dmforu.crawling import com.dmforu.domain.notice.Notice +import org.jsoup.nodes.Document import java.lang.NumberFormatException import java.time.LocalDate import java.time.format.DateTimeFormatter -class UniversityNoticeParser : UrlGenerator(), Parser { +class UniversityNoticeParser( + private val webPageLoader: WebPageLoader +) : UrlGenerator(), Parser { private var pageNumber = 1 /** @@ -16,7 +19,7 @@ class UniversityNoticeParser : UrlGenerator(), Parser { override fun parse(): List { val universityNotices: MutableList = java.util.ArrayList() - val document = WebPageLoader.getHTML(generateSearchUrl()) + val document = webPageLoader.getHTML(generateSearchUrl()) val rows = document.select(".board-table tbody tr") diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt new file mode 100644 index 0000000..2e9271b --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt @@ -0,0 +1,5 @@ +package com.dmforu.crawling + +interface WebPageLoader { + fun getHTML(url: String): Result +} \ No newline at end of file From d4c7f98c40ee684504f4b20db6f704360374f55c Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 03:30:50 +0900 Subject: [PATCH 118/223] =?UTF-8?q?test:=20Diet=20Parser=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawling/schedule/DietParserTest.kt | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 dmforu-crawling/src/test/kotlin/com/dmforu/crawling/schedule/DietParserTest.kt diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/schedule/DietParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/schedule/DietParserTest.kt new file mode 100644 index 0000000..9c11059 --- /dev/null +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/schedule/DietParserTest.kt @@ -0,0 +1,132 @@ +package com.dmforu.crawling.schedule + +import com.dmforu.crawling.DietParser +import com.dmforu.crawling.WebPageLoader +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.tuple +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import org.jsoup.select.Elements +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.BDDMockito.anyString +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.junit.jupiter.MockitoExtension +import java.time.LocalDate + +@ExtendWith(MockitoExtension::class) +class DietParserTest { + + @Mock + private lateinit var webPageLoader: WebPageLoader + + @InjectMocks + private lateinit var dietParser: DietParser + + @DisplayName("식단표를 크롤링 할 수 있다.") + @Test + fun parse() { + // given + val mockDocument = mock(Document::class.java) + val mockRows = Elements() + val row1 = mock(Element::class.java) + val row2 = mock(Element::class.java) + val row3 = mock(Element::class.java) + mockRows.add(row1) + mockRows.add(row2) + mockRows.add(row3) + val columns1 = Elements( + mock(Element::class.java).apply { given(text()).willReturn("2024.10.23") }, + mock(Element::class.java), + mock(Element::class.java), + mock(Element::class.java).apply { given(text()).willReturn("Menu 1, Menu 2") } + ) + val columns2 = Elements( + mock(Element::class.java).apply { given(text()).willReturn("교직원식당") } + ) + val columns3 = Elements( + mock(Element::class.java).apply { given(text()).willReturn("2024.10.24") }, + mock(Element::class.java), + mock(Element::class.java), + mock(Element::class.java).apply { given(text()).willReturn("Menu 3, Menu 4") } + ) + + given(webPageLoader.getHTML(anyString())).willReturn(mockDocument) + given(mockDocument.select(anyString())).willReturn(mockRows) + given(row1.select(anyString())).willReturn(columns1) + given(row2.select(anyString())).willReturn(columns2) + given(row3.select(anyString())).willReturn(columns3) + + // when + val result = dietParser.parse() + + // then + assertThat(result).hasSize(2) + .extracting("date", "menus") + .containsExactly( + tuple(LocalDate.of(2024, 10, 23), listOf("Menu 1", "Menu 2")), + tuple(LocalDate.of(2024, 10, 24), listOf("Menu 3", "Menu 4")), + ) + } + + @DisplayName("메뉴가 비어있다면 메뉴를 빈 리스트로 반환한다.") + @Test + fun parseWhenEmptyMenus() { + // given + val mockDocument = mock(Document::class.java) + val mockRows = Elements() + val row = mock(Element::class.java) + mockRows.add(row) + val columns = Elements( + mock(Element::class.java).apply { given(text()).willReturn("2024.10.23") }, + mock(Element::class.java), + mock(Element::class.java), + mock(Element::class.java).apply { given(text()).willReturn(" ") } + ) + + given(webPageLoader.getHTML(anyString())).willReturn(mockDocument) + given(mockDocument.select(anyString())).willReturn(mockRows) + given(row.select(anyString())).willReturn(columns) + + // when + val result = dietParser.parse() + + // then + assertThat(result).hasSize(1) + val diet = result[0] + assertThat(diet.date).isEqualTo(LocalDate.of(2024, 10, 23)) + assertThat(diet.menus).isEmpty() + } + + @DisplayName("공휴일인 경우 메뉴를 빈 리스트로 반환한다.") + @Test + fun parseWhenHolidays() { + // given + val mockDocument = mock(Document::class.java) + val mockRows = Elements() + val row = mock(Element::class.java) + mockRows.add(row) + val columns = Elements( + mock(Element::class.java).apply { given(text()).willReturn("2024.10.20") }, + mock(Element::class.java) + ) + + given(webPageLoader.getHTML(anyString())).willReturn(mockDocument) + given(mockDocument.select(anyString())).willReturn(mockRows) + given(row.select(anyString())).willReturn(columns) + + // when + val result = dietParser.parse() + + // then + assertThat(result).hasSize(1) + val diet = result[0] + assertThat(diet.date).isEqualTo(LocalDate.of(2024, 10, 20)) + assertThat(diet.menus).isEmpty() + } +} + From c3d87b735620751b75b9593effae13c6188b20a5 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 03:32:49 +0900 Subject: [PATCH 119/223] =?UTF-8?q?chore:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=9C=20mockito=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-domain/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/dmforu-domain/build.gradle.kts b/dmforu-domain/build.gradle.kts index c7fd8f2..963a398 100644 --- a/dmforu-domain/build.gradle.kts +++ b/dmforu-domain/build.gradle.kts @@ -1,4 +1,5 @@ dependencies { + testImplementation("org.mockito:mockito-junit-jupiter") testImplementation("org.mockito:mockito-core") testImplementation("org.assertj:assertj-core") } \ No newline at end of file From a21ddd5a3acd6802236b32b315a543d51c0bcf83 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 03:33:12 +0900 Subject: [PATCH 120/223] =?UTF-8?q?style:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/kotlin/com/dmforu/domain/notice/NoticeReaderTest.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeReaderTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeReaderTest.kt index 9752ad1..441fccb 100644 --- a/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeReaderTest.kt +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeReaderTest.kt @@ -141,11 +141,6 @@ class NoticeReaderTest { // given val department = Major.COMPUTER_SOFTWARE_ENGINEERING.type val maxNumber = 10 - val notice = createNotice( - number = maxNumber, - type = department, - title = "신입생 설명회" - ) `when`(noticeRepository.findMaxNumberByType(department)) .thenReturn(maxNumber) From 6153151e5f95923a93a52cb83ccc999e264f85e0 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 03:34:09 +0900 Subject: [PATCH 121/223] =?UTF-8?q?chore:=20mockito=20inline=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-crawling/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/dmforu-crawling/build.gradle.kts b/dmforu-crawling/build.gradle.kts index c50308e..85536fb 100644 --- a/dmforu-crawling/build.gradle.kts +++ b/dmforu-crawling/build.gradle.kts @@ -8,6 +8,5 @@ dependencies { testImplementation(project(":dmforu-domain")) testImplementation("org.mockito:mockito-core") testImplementation("org.mockito:mockito-junit-jupiter") - testImplementation("org.mockito:mockito-inline:5.2.0") testImplementation("org.assertj:assertj-core") } \ No newline at end of file From a782eb9e4d3d13b13d014f111fa058d3ba1cb452 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 03:39:48 +0900 Subject: [PATCH 122/223] =?UTF-8?q?refactor:=20UrlGenerator=20=EC=B6=94?= =?UTF-8?q?=EC=83=81=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt | 6 +++--- .../kotlin/com/dmforu/crawling/UniversityNoticeParser.kt | 6 +++--- .../src/main/kotlin/com/dmforu/crawling/UrlGenerator.kt | 6 ------ 3 files changed, 6 insertions(+), 12 deletions(-) delete mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UrlGenerator.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt index 25b14e9..4361bf5 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt @@ -10,7 +10,7 @@ import java.util.regex.Pattern class DepartmentNoticeParser( private val webPageLoader: WebPageLoader, -) : UrlGenerator(), Parser { +) : Parser { private lateinit var major: Major private var pageNumber: Int = 1 @@ -66,7 +66,7 @@ class DepartmentNoticeParser( * * @return URL */ - protected override fun generateSearchUrl(): String { + private fun generateSearchUrl(): String { return java.lang.String.format( "https://www.dongyang.ac.kr/%s/%s/subview.do?page=%d", major.majorPath, major.noticePath, pageNumber++ @@ -80,7 +80,7 @@ class DepartmentNoticeParser( * @return URL * @throws IllegalArgumentException Matcher를 통해 URL을 생성할 수 없는 경우 예외 발생 */ - protected override fun generateUrlFromSearch(url: String): String { + private fun generateUrlFromSearch(url: String): String { // URL에서 정보를 추출하기 위한 Matcher 생성 val matcher = pattern.matcher(url) diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt index 11387b5..a264a44 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt @@ -8,7 +8,7 @@ import java.time.format.DateTimeFormatter class UniversityNoticeParser( private val webPageLoader: WebPageLoader -) : UrlGenerator(), Parser { +) : Parser { private var pageNumber = 1 /** @@ -57,7 +57,7 @@ class UniversityNoticeParser( * * @return URL */ - protected override fun generateSearchUrl(): String { + private fun generateSearchUrl(): String { return String.format(SEARCH_URL, pageNumber++) } @@ -67,7 +67,7 @@ class UniversityNoticeParser( * @param url URL 파싱결과 * @return 공지사항 URL */ - protected override fun generateUrlFromSearch(url: String): String { + private fun generateUrlFromSearch(url: String): String { return String.format(RESULT_URL, url) } diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UrlGenerator.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UrlGenerator.kt deleted file mode 100644 index cff76ae..0000000 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UrlGenerator.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.dmforu.crawling - -abstract class UrlGenerator { - protected abstract fun generateSearchUrl(): String - protected abstract fun generateUrlFromSearch(url: String): String -} From b71283ff10e349f5cd2cfaa86bd974519eb9939e Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 22:30:50 +0900 Subject: [PATCH 123/223] =?UTF-8?q?chore:=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt | 5 +++++ .../com/dmforu/crawling/{schedule => }/DietParserTest.kt | 4 +--- .../test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt | 5 +++++ 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt rename dmforu-crawling/src/test/kotlin/com/dmforu/crawling/{schedule => }/DietParserTest.kt (97%) create mode 100644 dmforu-crawling/src/test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt new file mode 100644 index 0000000..4858db8 --- /dev/null +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt @@ -0,0 +1,5 @@ +package com.dmforu.crawling + +import org.junit.jupiter.api.Assertions.* + +class DepartmentNoticeParserTest \ No newline at end of file diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/schedule/DietParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DietParserTest.kt similarity index 97% rename from dmforu-crawling/src/test/kotlin/com/dmforu/crawling/schedule/DietParserTest.kt rename to dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DietParserTest.kt index 9c11059..ff42bee 100644 --- a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/schedule/DietParserTest.kt +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DietParserTest.kt @@ -1,7 +1,5 @@ -package com.dmforu.crawling.schedule +package com.dmforu.crawling -import com.dmforu.crawling.DietParser -import com.dmforu.crawling.WebPageLoader import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.tuple import org.jsoup.nodes.Document diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt new file mode 100644 index 0000000..e36505e --- /dev/null +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt @@ -0,0 +1,5 @@ +package com.dmforu.crawling + +import org.junit.jupiter.api.Assertions.* + +class ScheduleParserTest \ No newline at end of file From 7af33955af4e3a8d341fe8f4ade2ec7db921240c Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 22:31:54 +0900 Subject: [PATCH 124/223] =?UTF-8?q?refactor:=20DepartmentNoticeParser=20?= =?UTF-8?q?=EB=A9=94=EC=86=8C=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/crawling/DepartmentNoticeParser.kt | 50 ++++++++----------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt index 4361bf5..a0cda0a 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt @@ -3,7 +3,7 @@ package com.dmforu.crawling import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.Major import org.jsoup.nodes.Document -import java.lang.NumberFormatException +import org.jsoup.nodes.Element import java.time.LocalDate import java.time.format.DateTimeFormatter import java.util.regex.Pattern @@ -25,42 +25,34 @@ class DepartmentNoticeParser( * @return 학과 공지사항 목록 */ override fun parse(): List { - - val departmentNotices: MutableList = java.util.ArrayList() - + val departmentNotices: MutableList = mutableListOf() val document = webPageLoader.getHTML(generateSearchUrl()) val rows = document.select(".board-table tbody tr") - - for (row in rows) { - var number: Int - - try { - number = row.select(".td-num").text().toInt() - } catch (e: NumberFormatException) { - continue - } - - val title = row.select(".td-subject a").text() - val author = row.select(".td-write").text() - val url = generateUrlFromSearch(row.select(".td-subject a").attr("href")) - val date = LocalDate.parse(row.select(".td-date").text(), formatter) - - val departmentNotice = Notice.of( - number = number, - type = major.type, - date = date, - title = title, - author = author, - url = url, - ) - - departmentNotices.add(departmentNotice) + rows.forEach { row -> + departmentNotices.add(parseRow(row)) } return departmentNotices } + private fun parseRow(row: Element): Notice { + val number = row.select(".td-num").text().toInt() + val title = row.select(".td-subject a").text() + val author = row.select(".td-write").text() + val url = generateUrlFromSearch(row.select(".td-subject a").attr("href")) + val date = LocalDate.parse(row.select(".td-date").text(), formatter) + + return Notice.of( + number = number, + type = major.type, + date = date, + title = title, + author = author, + url = url, + ) + } + /** * 파싱할 페이지의 URL을 생성한다. * From 99fd9c3d02bdb67dd58f027383b170f7dc8b53d0 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 22:33:57 +0900 Subject: [PATCH 125/223] =?UTF-8?q?test:=20ScheduleParser,=20DepartmentNot?= =?UTF-8?q?iceParser=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawling/DepartmentNoticeParserTest.kt | 96 ++++++++++++++- .../com/dmforu/crawling/ScheduleParserTest.kt | 113 +++++++++++++++++- 2 files changed, 207 insertions(+), 2 deletions(-) diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt index 4858db8..f156eb7 100644 --- a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt @@ -1,5 +1,99 @@ package com.dmforu.crawling +import com.dmforu.domain.notice.Major +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import org.jsoup.select.Elements import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.ArgumentMatchers.anyString +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.junit.jupiter.MockitoExtension +import java.time.LocalDate +import java.time.format.DateTimeFormatter -class DepartmentNoticeParserTest \ No newline at end of file +@ExtendWith(MockitoExtension::class) +class DepartmentNoticeParserTest { + + @Mock + private lateinit var webPageLoader: WebPageLoader + + @InjectMocks + private lateinit var parser: DepartmentNoticeParser + + @Test + fun `should return list of Notice when HTML is valid`() { + // Arrange + + parser.initialize(Major.COMPUTER_SOFTWARE_ENGINEERING) + + val mockDocument = mock(Document::class.java) + val mockRow1 = mock(Element::class.java) + val mockRow2 = mock(Element::class.java) + + // Mocking the rows of the table + val rows = Elements(mockRow1, mockRow2) + given(webPageLoader.getHTML(anyString())).willReturn(mockDocument) + given(mockDocument.select(".board-table tbody tr")).willReturn(rows) + + // Setting up the first row mock + val mockNumElement1 = mock(Element::class.java) + given(mockNumElement1.text()).willReturn("1") + + val mockTitleElement1 = mock(Element::class.java) + given(mockTitleElement1.text()).willReturn("Notice Title 1") + + val mockTitleElement10 = mock(Element::class.java) + given(mockTitleElement10.attr("href")).willReturn("('dmu_23222','14','320','129499')") + + + val mockAuthorElement1 = mock(Element::class.java) + val testAuthorElements1 = Elements(mockAuthorElement1) + given(mockRow1.select(".td-write")).willReturn(testAuthorElements1) + given(mockAuthorElement1.text()).willReturn("Author A") + + val mockDateElement1 = mock(Element::class.java) + given(mockDateElement1.text()).willReturn("2024.10.23") + + // Mocking select results for first row + val test12 = mock(Elements(mockTitleElement10)) + given(mockRow1.select(".td-num")).willReturn(Elements(mockNumElement1)) + given(mockRow1.select(".td-subject a")) + .willReturn(Elements(mockTitleElement1)) + .willReturn(test12) + given(mockRow1.select(".td-date")).willReturn(Elements(mockDateElement1)) + + // Setting up the second row mock + val mockNumElement2 = mock(Element::class.java) + given(mockNumElement2.text()).willReturn("2") + + val mockTitleElement2 = mock(Element::class.java) + given(mockTitleElement2.text()).willReturn("Notice Title 2") + given(mockTitleElement2.attr("href")).willReturn("('dmu_23222','14','320','129499')") + + val mockAuthorElement2 = mock(Element::class.java) + val testAuthorElements2 = Elements(mockAuthorElement2) + given(mockRow2.select(".td-write")).willReturn(testAuthorElements2) + given(mockAuthorElement2.text()).willReturn("Author B") + + val mockDateElement2 = mock(Element::class.java) + given(mockDateElement2.text()).willReturn("2024.10.24") + + // Mocking select results for second row + given(mockRow2.select(".td-num")).willReturn(Elements(mockNumElement2)) + given(mockRow2.select(".td-subject a")).willReturn(Elements(mockTitleElement2)) + given(mockRow2.select(".td-date")).willReturn(Elements(mockDateElement2)) + + // Act + val notices = parser.parse() + + // Assert + assertEquals(2, notices.size) + assertTrue(notices.any { it.title == "Notice Title 1" && it.author == "Author A" && it.date == LocalDate.parse("2024.10.23", DateTimeFormatter.ofPattern("yyyy.MM.dd")) }) + assertTrue(notices.any { it.title == "Notice Title 2" && it.author == "Author B" && it.date == LocalDate.parse("2024.10.24", DateTimeFormatter.ofPattern("yyyy.MM.dd")) }) + } +} \ No newline at end of file diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt index e36505e..f809cb9 100644 --- a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt @@ -1,5 +1,116 @@ package com.dmforu.crawling +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import org.jsoup.select.Elements import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.ArgumentMatchers.anyString +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.junit.jupiter.MockitoExtension +import java.time.LocalDate +import java.time.ZoneId -class ScheduleParserTest \ No newline at end of file +@ExtendWith(MockitoExtension::class) +class ScheduleParserTest { + + @Mock + private lateinit var webPageLoader: WebPageLoader + + @InjectMocks + private lateinit var scheduleParser: ScheduleParser + + + @DisplayName("학사 일정을 크롤링 할 수 있다.") + @Test + fun parse() { + // given + // todo 외부로 옮겨야하나? + val currentYear = LocalDate.now(ZoneId.of("Asia/Seoul")).year + + val mockDocument1 = mock(Document::class.java) + val mockDocument2 = mock(Document::class.java) + val mockDocument3 = mock(Document::class.java) + + // Mocking year and month tables + val yearTable1 = mock(Element::class.java) + val monthTable1 = mock(Element::class.java) + + val yearTable2 = mock(Element::class.java) + val monthTable2 = mock(Element::class.java) + + val yearTable3 = mock(Element::class.java) + val monthTable3 = mock(Element::class.java) + + // Create elements for the first mock document + val yearElements1 = Elements(yearTable1) + val monthElements1 = Elements(monthTable1) + val yearElements2 = Elements(yearTable2) + val monthElements2 = Elements(monthTable2) + val yearElements3 = Elements(yearTable3) + val monthElements3 = Elements(monthTable3) + + // Setting up different return values for different calls + given(webPageLoader.getHTML(anyString())) + .willReturn(mockDocument1) // 첫 번째 호출 + .willReturn(mockDocument2) // 두 번째 호출 + .willReturn(mockDocument3) // 세 번째 호출 + + // Setting up the behavior for the first document + given(mockDocument1.select(anyString())).willReturn(yearElements1) + given(yearTable1.select(anyString())).willReturn(monthElements1) + val test = Elements(mock(Element::class.java)) + given(monthTable1.select(anyString())).willReturn(test) + given(test.first().text()).willReturn("2023.01") + + // Setting up the behavior for the second document + given(mockDocument2.select(anyString())).willReturn(yearElements2) + given(yearTable2.select(anyString())).willReturn(monthElements2) + given(monthTable2.select(anyString())).willReturn(test) + given(test.first().text()).willReturn("2023.02") + + // Setting up the behavior for the third document + given(mockDocument3.select(anyString())).willReturn(yearElements3) + given(yearTable3.select(anyString())).willReturn(monthElements3) + given(monthTable3.select(anyString())).willReturn(test) + given(test.first().text()).willReturn("2023.03") + + // Execute + val result = scheduleParser.parse() + + // Verify the result + assertEquals(3, result.size) + } + + + // + // val test1 = Elements(mock(Element::class.java)) + // + // // Set up month text for the first month table + // given(monthTable1.select("p")).willReturn(test1) + // + // given(test1.text()).willReturn("2024.1") + // + // // Create elements for the second mock document + + // + // val test2 = Elements(mock(Element::class.java)) + // // Set up month text for the second month table + // given(monthTable2.select("p")).willReturn(test2) + // + // given(test2.text()).willReturn("2024.2") + // + // // Create elements for the third mock document + + // + // val test3 = Elements(mock(Element::class.java)) + // // Set up month text for the third month table + // given(monthTable3.select("p")).willReturn(test3) + // + // given(test3.text()).willReturn("2024.3") // 여기도 마찬가지. +} \ No newline at end of file From 5c9e4cdabeab6dd59a82f3bf00493709200f879d Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 22:36:46 +0900 Subject: [PATCH 126/223] =?UTF-8?q?refactor:=20from=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EB=A1=9C=20=EC=83=9D=EC=84=B1=ED=95=A0=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20=EC=83=9D=EC=84=B1=EC=9E=90=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=20=EC=A0=9C=EC=96=B4=EC=9E=90=20protected=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt index 6ee9447..7f91afb 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt @@ -7,7 +7,7 @@ import java.time.LocalDate @Table(name = "notice") @Entity -internal class NoticeEntity( +internal class NoticeEntity private constructor( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long? = null, @@ -29,7 +29,7 @@ internal class NoticeEntity( // 공지사항 URL val url: String ) { - constructor() : this(null, 0, "", LocalDate.now(), "", "", "") + protected constructor() : this(null, 0, "", LocalDate.now(), "", "", "") companion object { fun from(notice: Notice): NoticeEntity { From 91aa24d38d36960c25014646c3adcda298dfaae0 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 22:37:54 +0900 Subject: [PATCH 127/223] =?UTF-8?q?refactor:=20=EC=BD=94=ED=8B=80=EB=A6=B0?= =?UTF-8?q?=20Nullable=EC=9D=84=20=ED=95=84=EC=9A=94=ED=95=9C=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=EC=97=90=EB=A7=8C=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../db/mysql/notice/NoticeEntityRepository.kt | 23 ++++++++++++------- .../db/mysql/notice/NoticeJpaRepository.kt | 6 ++--- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt index 2afa03c..d534cc6 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt @@ -2,14 +2,17 @@ package com.dmforu.storage.db.mysql.notice import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.NoticeRepository +import jakarta.transaction.Transactional import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Sort import org.springframework.stereotype.Repository @Repository internal class NoticeEntityRepository( - private val noticeJpaRepository: NoticeJpaRepository + private val noticeJpaRepository: NoticeJpaRepository, ) : NoticeRepository { + + @Transactional override fun write(notice: Notice) { noticeJpaRepository.save(NoticeEntity.from(notice)) } @@ -18,27 +21,27 @@ internal class NoticeEntityRepository( searchWord: String, department: String, page: Int, - size: Int + size: Int, ): List { val pageable = pageRequest(page, size) val noticePage = noticeJpaRepository.findBySearchWordAndDepartment(searchWord, department, pageable) - return noticePage?.mapNotNull { it?.toNotice() }?.toList().orEmpty() + return noticePage.map { it.toNotice() }.toList() } override fun findDepartmentNotices( department: String, page: Int, - size: Int + size: Int, ): List { val pageable = pageRequest(page, size) val departmentNoticePage = noticeJpaRepository.findByType(department, pageable) - return departmentNoticePage?.mapNotNull { it?.toNotice() }?.toList().orEmpty() + return departmentNoticePage.map { it.toNotice() }.toList() } override fun findUniversityNotices(page: Int, size: Int): List { val pageable = pageRequest(page, size) val universityNoticePage = noticeJpaRepository.findByType("대학", pageable) - return universityNoticePage?.mapNotNull { it?.toNotice() }?.toList().orEmpty() + return universityNoticePage.map { it.toNotice() }.toList() } override fun findMaxNumberByType(type: String): Int? { @@ -46,7 +49,11 @@ internal class NoticeEntityRepository( } private fun pageRequest(page: Int, size: Int): PageRequest { - val pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "number")) - return pageable + return PageRequest.of( + page - 1, size, Sort.by( + Sort.Order.desc("date"), + Sort.Order.desc("id") + ) + ) } } \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt index 2d9f098..aa72c93 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt @@ -13,7 +13,7 @@ internal interface NoticeJpaRepository : JpaRepository { * @Return type에 알맞는 최신 공지사항 번호, 만약 공지사항이 존재하지 않다면 Null을 반환한다. */ @Query("SELECT MAX(e.number) FROM NoticeEntity e WHERE e.type = :type") - fun findMaxNumberByType(@Param("type") type: String?): Int? + fun findMaxNumberByType(@Param("type") type: String): Int? /** * 원하는 타입의 공지사항을 페이징네이션하는 메서드 @@ -22,7 +22,7 @@ internal interface NoticeJpaRepository : JpaRepository { * @param pageable 페이지 단위 * @return 학과의 공지사항을 페이지 단위에 맞게 반환한다. */ - fun findByType(type: String, pageable: Pageable): Page? + fun findByType(type: String, pageable: Pageable): Page /** * 학과, 대학 공지사항을 검색하는 메서드

@@ -36,6 +36,6 @@ internal interface NoticeJpaRepository : JpaRepository { value = "SELECT * FROM notice WHERE REPLACE(title, ' ', '') LIKE CONCAT('%', REPLACE(?1, ' ', ''), '%') AND type IN (?2, '대학')", nativeQuery = true ) - fun findBySearchWordAndDepartment(searchWord: String?, department: String?, pageable: Pageable?): Page? + fun findBySearchWordAndDepartment(searchWord: String, department: String, pageable: Pageable): Page } \ No newline at end of file From f3daa4405af7d98e4fc71bf9f4e35efdc737ecf7 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 24 Oct 2024 22:48:00 +0900 Subject: [PATCH 128/223] =?UTF-8?q?test:=20Bean=EC=9D=84=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=B4=EC=95=BC=ED=95=98=EB=8A=94=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=9E=91=EC=84=B1=ED=95=A0=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/db-mysql/build.gradle.kts | 7 +++++-- .../com/dmfou/storage/db/mysql/MysqlApplicationTest.kt | 10 ++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/MysqlApplicationTest.kt diff --git a/dmforu-infrastructure/storage/db-mysql/build.gradle.kts b/dmforu-infrastructure/storage/db-mysql/build.gradle.kts index 4bb6941..84cea12 100644 --- a/dmforu-infrastructure/storage/db-mysql/build.gradle.kts +++ b/dmforu-infrastructure/storage/db-mysql/build.gradle.kts @@ -5,10 +5,13 @@ allOpen { } dependencies { - compileOnly(project(":dmforu-domain")) - implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.0") + compileOnly(project(":dmforu-domain")) + runtimeOnly ("com.mysql:mysql-connector-j") + + testImplementation("com.h2database:h2") + testImplementation(project(":dmforu-domain")) } \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/MysqlApplicationTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/MysqlApplicationTest.kt new file mode 100644 index 0000000..40040cc --- /dev/null +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/MysqlApplicationTest.kt @@ -0,0 +1,10 @@ +package com.dmfou.storage.db.mysql + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.context.properties.ConfigurationPropertiesScan + +@ConfigurationPropertiesScan +@SpringBootApplication( + scanBasePackages = ["com.dmforu.storage.db.mysql"] +) +class MysqlApplicationTest \ No newline at end of file From 4e1cadc0ba351fb8eefef942f92d3d718762a359 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 01:26:31 +0900 Subject: [PATCH 129/223] =?UTF-8?q?test:=20Notice=20Entity,=20JpaRepositor?= =?UTF-8?q?y,=20EntityRepository=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notice/NoticeEntityRepositoryTest.kt | 464 ++++++++++++++++++ .../db/mysql/notice/NoticeEntityTest.kt | 69 +++ .../mysql/notice/NoticeJpaRepositoryTest.kt | 326 ++++++++++++ 3 files changed, 859 insertions(+) create mode 100644 dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt create mode 100644 dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityTest.kt create mode 100644 dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt new file mode 100644 index 0000000..72a1e15 --- /dev/null +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt @@ -0,0 +1,464 @@ +package com.dmfou.storage.db.mysql.notice + +import com.dmforu.domain.notice.Notice +import com.dmforu.storage.db.mysql.config.MysqlJpaConfig +import com.dmforu.storage.db.mysql.notice.NoticeEntity +import com.dmforu.storage.db.mysql.notice.NoticeEntityRepository +import com.dmforu.storage.db.mysql.notice.NoticeJpaRepository +import com.dmfou.storage.db.mysql.MysqlApplicationTest +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.tuple +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.context.annotation.Import +import org.springframework.test.context.ActiveProfiles +import java.time.LocalDate + +@ActiveProfiles("test") +@SpringBootTest(classes = [MysqlApplicationTest::class]) +@Import(MysqlJpaConfig::class) +class NoticeEntityRepositoryTest { + + @Autowired + private lateinit var noticeRepository: NoticeJpaRepository + + @Autowired + private lateinit var noticeEntityRepository: NoticeEntityRepository + + @AfterEach + fun tearDown() { + noticeRepository.deleteAllInBatch() + } + + @DisplayName("공지를 저장할 수 있다.") + @Test + fun write() { + // given + val date = LocalDate.of(2024, 10, 23) + val notice = Notice.of( + number = 1, + type = "대학", + date = date, + title = "공지사항1", + author = "관리자", + url = "https://www.test.com/1" + ) + + // when + noticeEntityRepository.write(notice) + + // then + val notices = noticeRepository.findAll() + assertThat(notices).hasSize(1) + .extracting("number", "type", "date", "title", "author", "url") + .containsExactly( + tuple(1, "대학", date, "공지사항1", "관리자", "https://www.test.com/1") + ) + } + + @DisplayName("선택한 학과, 대학 공지에서 검색어가 포함된 공지를 최신순으로 불러온다.") + @Test + fun findNoticesBySearchWord() { + // given + val searchWord = "수강" + val department = "컴퓨터소프트웨어공학과" + val title1 = "수강신청 안내" + val title2 = "학사안내" + val title3 = "학과 수강신청 안내" + + val notice1 = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 23), + title = title1, + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = 2, + type = "대학", + date = LocalDate.of(2024, 10, 24), + title = title2, + author = "관리자", + url = "https://www.test.com/2" + ) + + val notice3 = Notice.of( + number = 1, + type = "컴퓨터소프트웨어공학과", + date = LocalDate.of(2024, 10, 25), + title = title3, + author = "관리자", + url = "https://www.test.com/3" + ) + + val notice4 = Notice.of( + number = 1, + type = "기계공학과", + date = LocalDate.of(2024, 10, 26), + title = "수강신청안내", + author = "관리자", + url = "https://www.test.com/4" + ) + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2), + NoticeEntity.from(notice3), + NoticeEntity.from(notice4), + ) + ) + + // when + val result = noticeEntityRepository.findNoticesBySearchWord( + searchWord = searchWord, + department = department, + page = 1, + size = 20 + ) + + // then + assertThat(result).hasSize(2) + .extracting("type", "title") + .containsExactly( + tuple(department, title3), + tuple("대학", title1) + ) + + assertThat(title1).contains(searchWord) + assertThat(title3).contains(searchWord) + assertThat(title2).doesNotContain(searchWord) + } + + @DisplayName("선택한 학과, 대학 공지에서 검색어가 포함된 공지가 없는 경우, 빈 리스트를 반환한다.") + @Test + fun findNoticesBySearchWordWhenEmpty() { + // given + val searchWord = "수강" + val department = "컴퓨터소프트웨어공학과" + val title1 = "학사안내" + val title2 = "학과 학사안내" + val title3 = "수강신청안내" + + val notice1 = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 23), + title = title1, + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = 1, + type = "컴퓨터소프트웨어공학과", + date = LocalDate.of(2024, 10, 25), + title = title2, + author = "관리자", + url = "https://www.test.com/3" + ) + + val notice3 = Notice.of( + number = 1, + type = "기계공학과", + date = LocalDate.of(2024, 10, 26), + title = title3, + author = "관리자", + url = "https://www.test.com/4" + ) + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2), + NoticeEntity.from(notice3), + ) + ) + + // when + val result = noticeEntityRepository.findNoticesBySearchWord( + searchWord = searchWord, + department = department, + page = 1, + size = 20 + ) + + // then + assertThat(result).isEmpty() + + assertThat(title1).doesNotContain(searchWord) + assertThat(title2).doesNotContain(searchWord) + assertThat(title3).contains(searchWord) + } + + @DisplayName("학과에 해당하는 공지를 최신순으로 불러온다.") + @Test + fun findDepartmentNotices() { + // given + val department = "컴퓨터소프트웨어공학과" + + val notice1 = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 23), + title = "공지1", + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = 1, + type = department, + date = LocalDate.of(2024, 10, 25), + title = "공지2", + author = "관리자", + url = "https://www.test.com/2" + ) + + val notice3 = Notice.of( + number = 2, + type = department, + date = LocalDate.of(2024, 10, 25), + title = "공지3", + author = "관리자", + url = "https://www.test.com/2" + ) + + val notice4 = Notice.of( + number = 1, + type = "기계공학과", + date = LocalDate.of(2024, 10, 26), + title = "공지4", + author = "관리자", + url = "https://www.test.com/4" + ) + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2), + NoticeEntity.from(notice3), + NoticeEntity.from(notice4) + ) + ) + + // when + val result = noticeEntityRepository.findDepartmentNotices(department, 1, 20) + + // then + assertThat(result).hasSize(2) + .extracting("number", "type", "date") + .containsExactly( + tuple(2, department, LocalDate.of(2024, 10, 25)), + tuple(1, department, LocalDate.of(2024, 10, 25)), + ) + } + + @DisplayName("학과에 해당하는 공지가 없는 경우, 빈 리스트를 반환한다.") + @Test + fun findDepartmentNoticesWhenEmpty() { + // given + val department = "컴퓨터소프트웨어공학과" + + val notice1 = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 23), + title = "공지1", + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = 1, + type = "기계공학과", + date = LocalDate.of(2024, 10, 25), + title = "공지2", + author = "관리자", + url = "https://www.test.com/2" + ) + + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2) + ) + ) + + // when + val result = noticeEntityRepository.findDepartmentNotices(department, 1, 20) + + // then + assertThat(result).isEmpty() + } + + @DisplayName("대학 공지를 최신순으로 불러온다.") + @Test + fun findUniversityNotices() { + // given + val notice1 = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 23), + title = "공지1", + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = 2, + type = "대학", + date = LocalDate.of(2024, 10, 23), + title = "공지2", + author = "관리자", + url = "https://www.test.com/2" + ) + + val notice3 = Notice.of( + number = 1, + type = "컴퓨터소프트웨어공학과", + date = LocalDate.of(2024, 10, 25), + title = "공지3", + author = "관리자", + url = "https://www.test.com/3" + ) + + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2), + NoticeEntity.from(notice3) + ) + ) + + // when + val result = noticeEntityRepository.findUniversityNotices(1, 20) + + // then + assertThat(result).hasSize(2) + .extracting("number", "type", "date") + .containsExactly( + tuple(2, "대학", LocalDate.of(2024, 10, 23)), + tuple(1, "대학", LocalDate.of(2024, 10, 23)), + ) + } + + @DisplayName("대학 공지가 없는 경우, 빈 리스트를 반환한다.") + @Test + fun findUniversityNoticesWhenEmpty() { + // given + val notice1 = Notice.of( + number = 1, + type = "컴퓨터소프트웨어공학과", + date = LocalDate.of(2024, 10, 23), + title = "공지1", + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = 1, + type = "기계공학과", + date = LocalDate.of(2024, 10, 25), + title = "공지2", + author = "관리자", + url = "https://www.test.com/2" + ) + + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2) + ) + ) + + // when + val result = noticeEntityRepository.findUniversityNotices(1, 20) + + // then + assertThat(result).isEmpty() + } + + @DisplayName("타입에 해당하는 공지중 가장 최신 번호를 가져온다.") + @Test + fun findMaxNumberByType() { + // given + val type = "컴퓨터소프트웨어공학과" + val maxNumber = 2 + + val notice1 = Notice.of( + number = 1, + type = type, + date = LocalDate.of(2024, 10, 23), + title = "공지1", + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = maxNumber, + type = type, + date = LocalDate.of(2024, 10, 25), + title = "공지2", + author = "관리자", + url = "https://www.test.com/2" + ) + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2), + ) + ) + // when + val result = noticeEntityRepository.findMaxNumberByType(type) + + // given + assertThat(result).isEqualTo(maxNumber) + } + + @DisplayName("타입에 해당하는 공지가 없는 경우 null을 반환한다.") + @Test + fun findMaxNumberByTypeWhenEmpty() { + // given + val type = "컴퓨터소프트웨어공학과" + + val notice1 = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 23), + title = "공지1", + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = 1, + type = "기계공학과", + date = LocalDate.of(2024, 10, 25), + title = "공지2", + author = "관리자", + url = "https://www.test.com/2" + ) + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2), + ) + ) + // when + val result = noticeEntityRepository.findMaxNumberByType(type) + + // given + assertThat(result).isNull() + } +} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityTest.kt new file mode 100644 index 0000000..520d05c --- /dev/null +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityTest.kt @@ -0,0 +1,69 @@ +package com.dmfou.storage.db.mysql.notice + +import com.dmforu.domain.notice.Notice +import com.dmforu.storage.db.mysql.notice.NoticeEntity +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import java.time.LocalDate + +class NoticeEntityTest { + + @DisplayName("Notice로 NoticeEntity를 생성할 수 있다.") + @Test + fun from() { + // given + val number = 1 + val type = "대학" + val date = LocalDate.of(2024, 10, 23) + val title = "공지사항1" + val author = "관리자" + val url = "https://www.test.com/1" + + val notice = Notice.of( + number = number, + type = type, + date = date, + title = title, + author = author, + url = url + ) + + // when + val noticeEntity = NoticeEntity.from(notice) + + // then + assertThat(noticeEntity).isInstanceOf(NoticeEntity::class.java) + + assertThat(noticeEntity.number).isEqualTo(number) + assertThat(noticeEntity.type).isEqualTo(type) + assertThat(noticeEntity.date).isEqualTo(date) + assertThat(noticeEntity.title).isEqualTo(title) + assertThat(noticeEntity.author).isEqualTo(author) + assertThat(noticeEntity.url).isEqualTo(url) + + } + + @DisplayName("NoticeEntity로 Notice를 생성할 수 있다.") + @Test + fun toNotice() { + // given + val notice = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 23), + title = "공지사항1", + author = "관리자", + url = "https://www.test.com/1" + ) + + val noticeEntity = NoticeEntity.from(notice) + + // when + val savedNotice = noticeEntity.toNotice() + + // then + assertThat(savedNotice).isEqualTo(notice) + + } +} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt new file mode 100644 index 0000000..40e242a --- /dev/null +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt @@ -0,0 +1,326 @@ +package com.dmfou.storage.db.mysql.notice + +import com.dmforu.domain.notice.Notice +import com.dmforu.storage.db.mysql.config.MysqlJpaConfig +import com.dmforu.storage.db.mysql.notice.NoticeEntity +import com.dmforu.storage.db.mysql.notice.NoticeJpaRepository +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.tuple +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.context.annotation.Import +import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Sort +import org.springframework.test.context.ActiveProfiles +import java.time.LocalDate + +@ActiveProfiles("test") +@DataJpaTest +@Import(MysqlJpaConfig::class) +class NoticeJpaRepositoryTest { + + @Autowired + private lateinit var noticeRepository: NoticeJpaRepository + + @DisplayName("타입에 해당하는 공지에서 가장 최신 번호를 가져온다.") + @Test + fun findMaxNumberByType() { + // given + val maxNumber = 2 + val type = "대학" + + val notice1 = Notice.of( + number = 1, + type = type, + date = LocalDate.of(2024, 10, 23), + title = "공지사항1", + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = maxNumber, + type = type, + date = LocalDate.of(2024, 10, 23), + title = "공지사항2", + author = "관리자", + url = "https://www.test.com/2" + ) + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2) + ) + ) + + // when + val result = noticeRepository.findMaxNumberByType(type) + + // then + assertThat(result).isEqualTo(maxNumber) + } + + @DisplayName("타입에 해당하는 공지가 존재하지 않는 경우, null을 반환한다.") + @Test + fun findMaxNumberByTypeWhenEmpty() { + // given + val type = "기계공학과" + + val notice1 = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 23), + title = "공지사항1", + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = 1, + type = "컴퓨터소프트웨어공학과", + date = LocalDate.of(2024, 10, 23), + title = "공지사항3", + author = "관리자", + url = "https://www.test.com/3" + ) + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2) + ) + ) + + // when + val result = noticeRepository.findMaxNumberByType(type) + + // then + assertThat(result).isNull() + } + + @DisplayName("원하는 타입의 공지를 최신순으로 불러온다.") + @Test + fun findByType() { + // given + val type = "대학" + + val notice1 = Notice.of( + number = 1, + type = type, + date = LocalDate.of(2024, 10, 23), + title = "공지사항1", + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = 2, + type = type, + date = LocalDate.of(2024, 10, 23), + title = "공지사항2", + author = "관리자", + url = "https://www.test.com/2" + ) + + val notice3 = Notice.of( + number = 1, + type = "컴퓨터소프트웨어공학과", + date = LocalDate.of(2024, 10, 23), + title = "공지사항3", + author = "관리자", + url = "https://www.test.com/3" + ) + + val pageable = pageRequest() + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2), + NoticeEntity.from(notice3), + ) + ) + + // when + val result = noticeRepository.findByType(type, pageable) + + // then + assertThat(result).hasSize(2) + .extracting("number", "type") + .containsExactly( + tuple(2, type), + tuple(1, type) + ) + } + + @DisplayName("원하는 타입의 공지가 존재하지 않는 경우, 빈 Page를 반환한다.") + @Test + fun findByTypeWhenEmpty() { + // given + val type = "기계공학과" + + val notice1 = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 23), + title = "공지사항1", + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = 1, + type = "컴퓨터소프트웨어공학과", + date = LocalDate.of(2024, 10, 23), + title = "공지사항3", + author = "관리자", + url = "https://www.test.com/3" + ) + + val pageable = pageRequest() + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2), + ) + ) + + // when + val result = noticeRepository.findByType(type, pageable) + + // then + assertThat(result).isEmpty() + } + + @DisplayName("선택한 학과, 대학 공지에서 검색어가 포함된 공지를 최신순으로 불러온다.") + @Test + fun findBySearchWordAndDepartment() { + // given + val type = "컴퓨터소프트웨어공학과" + val searchWord = "공지" + val title1 = "공지사항1" + val title2 = "공지사항2" + val title3 = "공지사항3" + + val notice1 = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 23), + title = title1, + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = 2, + type = "대학", + date = LocalDate.of(2024, 10, 24), + title = title2, + author = "관리자", + url = "https://www.test.com/2" + ) + + val notice3 = Notice.of( + number = 1, + type = type, + date = LocalDate.of(2024, 10, 25), + title = title3, + author = "관리자", + url = "https://www.test.com/3" + ) + + val notice4 = Notice.of( + number = 1, + type = "기계공학과", + date = LocalDate.of(2024, 10, 26), + title = "공지사항4", + author = "관리자", + url = "https://www.test.com/4" + ) + + val pageable = pageRequest() + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2), + NoticeEntity.from(notice3), + NoticeEntity.from(notice4), + ) + ) + + // when + val result = noticeRepository.findBySearchWordAndDepartment(searchWord, type, pageable) + + // then + assertThat(result).hasSize(3) + .extracting("number", "date", "type") + .containsExactly( + tuple(1, LocalDate.of(2024, 10, 25), type), + tuple(2, LocalDate.of(2024, 10, 24), "대학"), + tuple(1, LocalDate.of(2024, 10, 23), "대학"), + ) + + val pages = result.get().toList() + assertThat(pages[0].title).contains(searchWord) + assertThat(pages[1].title).contains(searchWord) + assertThat(pages[2].title).contains(searchWord) + } + + @DisplayName("선택한 학과, 대학 공지에서 검색어가 포함된 공지가 없는 경우, 빈 Page를 반환한다.") + @Test + fun findBySearchWordAndDepartmentWhenEmpty() { + // given + val type = "기계공학과" + val searchWord = "학사일정" + val title1 = "공지사항1" + + val notice1 = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 23), + title = "공지사항1", + author = "관리자", + url = "https://www.test.com/1" + ) + + val notice2 = Notice.of( + number = 1, + type = "컴퓨터소프트웨어공학과", + date = LocalDate.of(2024, 10, 23), + title = "공지사항2", + author = "관리자", + url = "https://www.test.com/2" + ) + + val pageable = pageRequest() + + noticeRepository.saveAll( + listOf( + NoticeEntity.from(notice1), + NoticeEntity.from(notice2), + ) + ) + + // when + val result = noticeRepository.findByType(type, pageable) + + // then + assertThat(result).isEmpty() + assertThat(title1).doesNotContain(searchWord) + } + + + private fun pageRequest(): PageRequest { + return PageRequest.of( + 0, 20, Sort.by( + Sort.Order.desc("date"), + Sort.Order.desc("id") + ) + ) + } +} \ No newline at end of file From cdca3d78dea3b4f69851965dd97be417b707c83d Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 01:41:55 +0900 Subject: [PATCH 130/223] =?UTF-8?q?rename:=20write=EC=97=90=EC=84=9C=20sav?= =?UTF-8?q?e=EB=A1=9C=20=EC=A0=80=EC=9E=A5=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt | 2 +- .../src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt | 2 +- .../test/kotlin/com/dmforu/domain/notice/NoticeWriterTest.kt | 2 +- .../dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt | 2 +- .../storage/db/mysql/notice/NoticeEntityRepositoryTest.kt | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt index 47f6e81..817f23f 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeRepository.kt @@ -1,7 +1,7 @@ package com.dmforu.domain.notice interface NoticeRepository { - fun write(notice: Notice) + fun save(notice: Notice) fun findNoticesBySearchWord(searchWord: String, department: String, page: Int, size: Int): List fun findDepartmentNotices(department: String, page: Int, size: Int): List fun findUniversityNotices(page: Int, size: Int): List diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt index 9c2d687..c9e6ad5 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/notice/NoticeWriter.kt @@ -4,6 +4,6 @@ class NoticeWriter( private val noticeRepository: NoticeRepository, ) { fun write(notice: Notice) { - noticeRepository.write(notice) + noticeRepository.save(notice) } } \ No newline at end of file diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeWriterTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeWriterTest.kt index 508f282..6f915ea 100644 --- a/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeWriterTest.kt +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/notice/NoticeWriterTest.kt @@ -36,7 +36,7 @@ class NoticeWriterTest { noticeWriter.write(notice) // then - verify(noticeRepository).write(notice) + verify(noticeRepository).save(notice) } } \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt index d534cc6..288b1f2 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt @@ -13,7 +13,7 @@ internal class NoticeEntityRepository( ) : NoticeRepository { @Transactional - override fun write(notice: Notice) { + override fun save(notice: Notice) { noticeJpaRepository.save(NoticeEntity.from(notice)) } diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt index 72a1e15..b5b4bda 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt @@ -35,7 +35,7 @@ class NoticeEntityRepositoryTest { @DisplayName("공지를 저장할 수 있다.") @Test - fun write() { + fun save() { // given val date = LocalDate.of(2024, 10, 23) val notice = Notice.of( @@ -48,7 +48,7 @@ class NoticeEntityRepositoryTest { ) // when - noticeEntityRepository.write(notice) + noticeEntityRepository.save(notice) // then val notices = noticeRepository.findAll() From 3442e46b82c4d4865d35e85f53a8ad466cbb68b7 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 02:08:12 +0900 Subject: [PATCH 131/223] =?UTF-8?q?test:=20SubscribeEntity,=20EntityReposi?= =?UTF-8?q?tory,=20JpaRepository=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SubscribeEntityRepositoryTest.kt | 228 ++++++++++++++++++ .../db/mysql/subscribe/SubscribeEntityTest.kt | 67 +++++ .../subscribe/SubscribeJpaRepositoryTest.kt | 155 ++++++++++++ 3 files changed, 450 insertions(+) create mode 100644 dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt create mode 100644 dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityTest.kt create mode 100644 dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt new file mode 100644 index 0000000..98bc480 --- /dev/null +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt @@ -0,0 +1,228 @@ +package com.dmfou.storage.db.mysql.subscribe + +import com.dmforu.domain.subscribe.Subscribe +import com.dmforu.storage.db.mysql.config.MysqlJpaConfig +import com.dmforu.storage.db.mysql.subscribe.SubscribeEntity +import com.dmforu.storage.db.mysql.subscribe.SubscribeEntityRepository +import com.dmforu.storage.db.mysql.subscribe.SubscribeJpaRepository +import com.dmfou.storage.db.mysql.MysqlApplicationTest +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.tuple +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.context.annotation.Import +import org.springframework.test.context.ActiveProfiles + +@ActiveProfiles("test") +@SpringBootTest(classes = [MysqlApplicationTest::class]) +@Import(MysqlJpaConfig::class) +class SubscribeEntityRepositoryTest { + + @Autowired + private lateinit var subscribeRepository: SubscribeJpaRepository + + @Autowired + private lateinit var subscribeEntityRepository: SubscribeEntityRepository + + @AfterEach + fun tearDown() { + subscribeRepository.deleteAllInBatch() + } + + @DisplayName("구독 정보를 저장할 수 있다.") + @Test + fun write() { + // given + val subscribe = Subscribe.of( + token = "0001", + department = "컴퓨터소프트웨어공학과", + keywords = listOf("시험"), + isDepartmentSubscribed = true, + isKeywordSubscribed = true + ) + + // when + subscribeEntityRepository.save(subscribe) + + // then + val result = subscribeRepository.findAll() + assertThat(result).hasSize(1) + .extracting("token", "department", "keywords", "isDepartmentSubscribed", "isKeywordSubscribed") + .containsExactly( + tuple("0001", "컴퓨터소프트웨어공학과", listOf("시험"), true, true) + ) + } + + @DisplayName("토큰으로 구독정보를 불러올 수 있다.") + @Test + fun findByToken() { + // given + val subscribe = Subscribe.of( + token = "0001", + department = "컴퓨터소프트웨어공학과", + keywords = listOf("시험"), + isDepartmentSubscribed = true, + isKeywordSubscribed = true + ) + + subscribeRepository.save(SubscribeEntity.from(subscribe)) + + // when + val savedSubscribe = subscribeEntityRepository.findByToken("0001") + + // then + assertThat(savedSubscribe).isEqualTo(subscribe) + assertThat(savedSubscribe) + .extracting("token", "department", "keywords", "isDepartmentSubscribed", "isKeywordSubscribed") + .containsExactly("0001", "컴퓨터소프트웨어공학과", listOf("시험"), true, true) + } + + @DisplayName("토큰에 해당하는 구독 정보가 없는 경우, Null을 반환한다.") + @Test + fun findByTokenWhenEmpty() { + // given + + // when + val savedSubscribe = subscribeEntityRepository.findByToken("0001") + + // then + assertThat(savedSubscribe).isNull() + } + + @DisplayName("해당 학과 알림 구독이 되어있는 토큰을 불러온다.") + @Test + fun findTokensByDepartment() { + // given + val department = "컴퓨터소프트웨어공학과" + + val subscribe1 = Subscribe.of( + "0001", department, listOf("시험"), true, true + ) + + val subscribe2 = Subscribe.of( + "0002", department, listOf("시험"), true, true + ) + + val subscribe3 = Subscribe.of( + "0003", department, listOf("시험"), false, true + ) + + val subscribe4 = Subscribe.of( + "0004", "기계공학과", listOf("시험"), true, true + ) + + subscribeRepository.saveAll( + listOf( + SubscribeEntity.from(subscribe1), + SubscribeEntity.from(subscribe2), + SubscribeEntity.from(subscribe3), + SubscribeEntity.from(subscribe4) + ) + ) + + // when + val subscribes = subscribeEntityRepository.findTokensByDepartment(department) + + // then + assertThat(subscribes).hasSize(2) + .containsExactlyInAnyOrder("0001", "0002") + } + + @DisplayName("해당 학과 알림 구독이 되어있는 토큰이 없는 경우, 빈 리스트를 반환한다.") + @Test + fun findTokensByDepartmentWhenEmpty() { + // given + val department = "컴퓨터소프트웨어공학과" + + val subscribe1 = Subscribe.of( + "0001", department, listOf("시험"), false, true + ) + + val subscribe2 = Subscribe.of( + "0002", "기계공학과", listOf("시험"), true, true + ) + + subscribeRepository.saveAll( + listOf( + SubscribeEntity.from(subscribe1), + SubscribeEntity.from(subscribe2) + ) + ) + + // when + val subscribes = subscribeEntityRepository.findTokensByDepartment(department) + + // then + assertThat(subscribes).isEmpty() + } + + @DisplayName("해당 키워드 알림 구독이 되어있는 토큰을 불러온다.") + @Test + fun findTokensContainingKeyword() { + // given + val keyword = "시험" + + val subscribe1 = Subscribe.of( + "0001", "컴퓨터소프트웨어공학과", listOf("시험", "학사"), true, true + ) + + val subscribe2 = Subscribe.of( + "0002", "기계공학과", listOf("시험"), true, false + ) + + val subscribe3 = Subscribe.of( + "0003", "컴퓨터소프트웨어공학과", listOf("봉사"), true, true + ) + + val subscribe4 = Subscribe.of( + "0004", "기계공학과", listOf("시험"), true, true + ) + + subscribeRepository.saveAll( + listOf( + SubscribeEntity.from(subscribe1), + SubscribeEntity.from(subscribe2), + SubscribeEntity.from(subscribe3), + SubscribeEntity.from(subscribe4) + ) + ) + + // when + val subscribes = subscribeEntityRepository.findTokensContainingKeyword(keyword) + + // then + assertThat(subscribes).hasSize(2) + .containsExactlyInAnyOrder("0001", "0004") + } + + @DisplayName("해당 키워드 알림 구독이 되어있는 토큰이 없는 경우, 빈 리스트를 반환한다.") + @Test + fun findTokensContainingKeywordWhenEmpty() { + // given + val keyword = "학사" + + val subscribe1 = Subscribe.of( + "0001", "컴퓨터소프트웨어공학과", listOf("학사", "봉사"), true, false + ) + + val subscribe2 = Subscribe.of( + "0002", "기계공학과", listOf("시험", "장학"), true, true + ) + + subscribeRepository.saveAll( + listOf( + SubscribeEntity.from(subscribe1), + SubscribeEntity.from(subscribe2) + ) + ) + + // when + val subscribes = subscribeEntityRepository.findTokensContainingKeyword(keyword) + + // then + assertThat(subscribes).isEmpty() + } +} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityTest.kt new file mode 100644 index 0000000..372ffae --- /dev/null +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityTest.kt @@ -0,0 +1,67 @@ +package com.dmfou.storage.db.mysql.subscribe + +import com.dmforu.domain.subscribe.Subscribe +import com.dmforu.storage.db.mysql.subscribe.SubscribeEntity +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +class SubscribeEntityTest { + + @DisplayName("Subscribe로 SubscribeEntity를 생성할 수 있다.") + @Test + fun from() { + // given + val token = "0001" + val department = "컴퓨터소프트웨어공학과" + val keywords = listOf("학사", "봉사") + val isDepartmentSubscribed = true + val isKeywordSubscribed = true + + val subscribe = Subscribe.of( + token = token, + department = department, + keywords = keywords, + isDepartmentSubscribed = isDepartmentSubscribed, + isKeywordSubscribed = isKeywordSubscribed + ) + + // when + val subscribeEntity = SubscribeEntity.from(subscribe) + + // then + assertThat(subscribeEntity.token).isEqualTo(token) + assertThat(subscribeEntity.department).isEqualTo(department) + assertThat(subscribeEntity.keywords).isEqualTo(keywords) + assertThat(subscribeEntity.isDepartmentSubscribed).isEqualTo(isDepartmentSubscribed) + assertThat(subscribeEntity.isKeywordSubscribed).isEqualTo(isKeywordSubscribed) + } + + @DisplayName("SubscribeEntity로 Subscribe를 생성할 수 있다.") + @Test + fun toSubscribe() { + // given + val token = "0001" + val department = "컴퓨터소프트웨어공학과" + val keywords = listOf("학사", "봉사") + val isDepartmentSubscribed = true + val isKeywordSubscribed = true + + val subscribe = Subscribe.of( + token = token, + department = department, + keywords = keywords, + isDepartmentSubscribed = isDepartmentSubscribed, + isKeywordSubscribed = isKeywordSubscribed + ) + + val subscribeEntity = SubscribeEntity.from(subscribe) + + // when + val savedSubscribe = subscribeEntity.toSubscribe() + + // then + assertThat(savedSubscribe).isEqualTo(subscribe) + } + +} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt new file mode 100644 index 0000000..a20b135 --- /dev/null +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt @@ -0,0 +1,155 @@ +package com.dmfou.storage.db.mysql.subscribe + +import com.dmforu.domain.subscribe.Subscribe +import com.dmforu.storage.db.mysql.config.MysqlJpaConfig +import com.dmforu.storage.db.mysql.subscribe.SubscribeEntity +import com.dmforu.storage.db.mysql.subscribe.SubscribeJpaRepository +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.context.annotation.Import + +@DataJpaTest +@Import(MysqlJpaConfig::class) +class SubscribeJpaRepositoryTest { + + @Autowired + private lateinit var subscribeRepository: SubscribeJpaRepository + + @DisplayName("해당 학과 알림 구독이 되어있는 토큰을 불러온다.") + @Test + fun findTokensByDepartment() { + // given + val department = "컴퓨터소프트웨어공학과" + + val subscribeEntity1 = SubscribeEntity.from( + Subscribe.of("0001", department, listOf("봉사"), true, true) + ) + + val subscribeEntity2 = SubscribeEntity.from( + Subscribe.of("0002", department, listOf("봉사"), true, true) + ) + + val subscribeEntity3 = SubscribeEntity.from( + Subscribe.of("0003", department, listOf("봉사"), false, true) + ) + + val subscribeEntity4 = SubscribeEntity.from( + Subscribe.of("0004", "기계공학과", listOf("봉사"), true, true) + ) + + subscribeRepository.saveAll( + listOf( + subscribeEntity1, + subscribeEntity2, + subscribeEntity3, + subscribeEntity4 + ) + ) + + // when + val tokens = subscribeRepository.findTokensByDepartment(department) + + // then + assertThat(tokens).hasSize(2) + .containsExactlyInAnyOrder("0001", "0002") + } + + @DisplayName("해당 학과 알림 구독이 되어있는 토큰이 없는 경우, 빈 리스트를 반환한다.") + @Test + fun findTokensByDepartmentWhenEmpty() { + // given + val department = "컴퓨터소프트웨어공학과" + + val subscribeEntity1 = SubscribeEntity.from( + Subscribe.of("0001", department, listOf("봉사"), false, true) + ) + + val subscribeEntity2 = SubscribeEntity.from( + Subscribe.of("0002", "기계공학과", listOf("봉사"), true, true) + ) + + subscribeRepository.saveAll( + listOf( + subscribeEntity1, + subscribeEntity2, + ) + ) + + // when + val tokens = subscribeRepository.findTokensByDepartment(department) + + // then + assertThat(tokens).isEmpty() + } + + @DisplayName("해당 키워드 알림 구독이 되어있는 토큰을 불러온다.") + @Test + fun findTokensContainingKeyword() { + // given + val keyword = "시험" + + val subscribeEntity1 = SubscribeEntity.from( + Subscribe.of("0001", "컴퓨터소프트웨어공학과", listOf(keyword), true, true) + ) + + val subscribeEntity2 = SubscribeEntity.from( + Subscribe.of("0002", "기계공학과", listOf("학사",keyword), true, true) + ) + + val subscribeEntity3 = SubscribeEntity.from( + Subscribe.of("0003", "정보통신공학과", listOf(keyword), true, false) + ) + + val subscribeEntity4 = SubscribeEntity.from( + Subscribe.of("0004", "정보통신공학과", listOf("학사"), true, true) + ) + + subscribeRepository.saveAll( + listOf( + subscribeEntity1, + subscribeEntity2, + subscribeEntity3, + subscribeEntity4 + ) + ) + + // when + val tokens = subscribeRepository.findTokensContainingKeyword(keyword) + + // then + assertThat(tokens).hasSize(2) + .containsExactlyInAnyOrder("0001", "0002") + } + + @DisplayName("해당 키워드 알림 구독이 되어있는 토큰이 없는 경우, 빈 리스트를 반환한다.") + @Test + fun findTokensContainingKeywordWhenEmpty() { + // given + val keyword = "시험" + + val subscribeEntity1 = SubscribeEntity.from( + Subscribe.of("0001", "컴퓨터소프트웨어공학과", listOf(keyword), false, false) + ) + + val subscribeEntity2 = SubscribeEntity.from( + Subscribe.of("0002", "기계공학과", listOf("봉사"), true, true) + ) + + subscribeRepository.saveAll( + listOf( + subscribeEntity1, + subscribeEntity2, + ) + ) + + // when + val tokens = subscribeRepository.findTokensContainingKeyword(keyword) + + // then + assertThat(tokens).isEmpty() + } + +} \ No newline at end of file From 2b5f587f2869f426f5e9b12b00b4e8b7a3d1f88a Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 02:08:40 +0900 Subject: [PATCH 132/223] =?UTF-8?q?refactor:=20=EC=99=B8=EB=B6=80=EC=97=90?= =?UTF-8?q?=EC=84=9C=20Entity=20=EA=B0=92=EC=9D=84=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EB=AA=BB=ED=95=98=EB=8F=84=EB=A1=9D=20var?= =?UTF-8?q?=EC=97=90=EC=84=9C=20val=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/db/mysql/subscribe/SubscribeEntity.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt index 4d4780b..8438b22 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt @@ -12,19 +12,19 @@ internal class SubscribeEntity( val token: String, @Column(nullable = true) - var department: String, + val department: String, @Convert(converter = StringListConverter::class) @Column(name = "keywords_list", nullable = true) - var keywords: List, + val keywords: List, @Column(name = "department_onoff") - var isDepartmentSubscribed: Boolean, + val isDepartmentSubscribed: Boolean, @Column(name = "keyword_onoff") - var isKeywordSubscribed: Boolean, + val isKeywordSubscribed: Boolean, ) { - constructor() : this("", "", emptyList(), false, false) + protected constructor() : this("", "", emptyList(), false, false) companion object { fun from(subscribe: Subscribe): SubscribeEntity { From fb359e3ce54eba5840f9a6611c44ccff35fbd625 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 03:18:09 +0900 Subject: [PATCH 133/223] =?UTF-8?q?refactor:=20StringListConventerExceptio?= =?UTF-8?q?n=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/storage/db/mysql/converter/StringListConverter.kt | 5 +++-- .../db/mysql/exception/StringListConverterException.kt | 3 +++ .../storage/db/mysql/converter/StringListConverterTest.kt | 5 +++++ 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/exception/StringListConverterException.kt create mode 100644 dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt index a34dea8..70c2409 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt @@ -1,5 +1,6 @@ package com.dmforu.storage.db.mysql.converter +import com.dmforu.storage.db.mysql.exception.StringListConverterException import com.fasterxml.jackson.core.JsonProcessingException import com.fasterxml.jackson.core.type.TypeReference import com.fasterxml.jackson.databind.ObjectMapper @@ -15,7 +16,7 @@ class StringListConverter : AttributeConverter, String> { try { return mapper.writeValueAsString(datas) } catch (e: JsonProcessingException) { - throw IllegalArgumentException("Error converting list to JSON: ${e.message}", e) + throw StringListConverterException("List를 String으로 변환하던 중 문제가 발생했습니다.", e) } } @@ -23,7 +24,7 @@ class StringListConverter : AttributeConverter, String> { try { return mapper.readValue(data, object : TypeReference>() {}) } catch (e: JsonProcessingException) { - throw IllegalArgumentException("Error converting JSON to list: ${e.message}", e) + throw StringListConverterException("String을 List로 변환하던 중 문제가 발생했습니다.", e) } } } \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/exception/StringListConverterException.kt b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/exception/StringListConverterException.kt new file mode 100644 index 0000000..575f5cb --- /dev/null +++ b/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/exception/StringListConverterException.kt @@ -0,0 +1,3 @@ +package com.dmforu.storage.db.mysql.exception + +class StringListConverterException(message: String, cause: Throwable? = null) : RuntimeException(message, cause) diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt new file mode 100644 index 0000000..6a0248a --- /dev/null +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt @@ -0,0 +1,5 @@ +package com.dmforu.storage.db.mysql.converter + +import org.junit.jupiter.api.Assertions.* + +class StringListConverterTest \ No newline at end of file From aaa89aeb20daaa1b068e01b780caede235925213 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 03:18:33 +0900 Subject: [PATCH 134/223] =?UTF-8?q?test:=20StringListConverter=20Test=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../converter/StringListConverterTest.kt | 88 ++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt index 6a0248a..ffb4c47 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt @@ -1,5 +1,91 @@ package com.dmforu.storage.db.mysql.converter +import com.dmforu.storage.db.mysql.exception.StringListConverterException +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.mockito.ArgumentMatchers.* +import org.mockito.BDDMockito.given +import org.mockito.Mockito.mock + +class StringListConverterTest { + + private val converter: StringListConverter = StringListConverter() + + @DisplayName("List에서 String으로 직렬화 할 수 있다.") + @Test + fun convertToDatabaseColumn() { + // given + val list = listOf("테스트1", "테스트2") + + // when + val data = converter.convertToDatabaseColumn(list) + + // then + assertThat(data).isEqualTo("[\"테스트1\",\"테스트2\"]") + } + + @DisplayName("List에서 String으로 직렬화 하던 중, 문제가 발생하면 StringListConverterException 예외를 발생시킨다.") + @Test + fun convertToDatabaseColumnThrowException() { + // given + val mockMapper = mock(ObjectMapper::class.java) + val converter = StringListConverter() + val testList = listOf("invalid") + + given(mockMapper.writeValueAsString(testList)).willThrow(JsonProcessingException::class.java) + + setObjectMapper(converter, mockMapper) + + // when // then + assertThatThrownBy { converter.convertToDatabaseColumn(testList) } + .isInstanceOf(StringListConverterException::class.java) + .hasMessage("List를 String으로 변환하던 중 문제가 발생했습니다.") + } + + @DisplayName("String에서 List로 역 직렬화 할 수 있다.") + @Test + fun convertToEntityAttribute() { + // given + val data = "[\"테스트1\",\"테스트2\"]" + + // when + val list = converter.convertToEntityAttribute(data) + + // then + assertThat(list).isEqualTo(listOf("테스트1", "테스트2")) + } + + @DisplayName("String에서 List로 역 직렬화 하던 중, 문제가 발생하면 StringListConverterException 예외를 발생시킨다.") + @Test + fun convertToEntityAttributeThrowException() { + // given + val mockMapper = mock(ObjectMapper::class.java) + val converter = StringListConverter() + val test = "invalid" + + given( + mockMapper.readValue(eq(test), any>>()) + ).willThrow(JsonProcessingException::class.java) + + setObjectMapper(converter, mockMapper) + + // when // then + assertThatThrownBy { converter.convertToEntityAttribute(test) } + .isInstanceOf(StringListConverterException::class.java) + .hasMessage("String을 List로 변환하던 중 문제가 발생했습니다.") + } + + private fun setObjectMapper(converter: StringListConverter, objectMapper: ObjectMapper) { + val mapperField = StringListConverter::class.java.getDeclaredField("mapper") + mapperField.isAccessible = true + mapperField.set(converter, objectMapper) + } +} + -class StringListConverterTest \ No newline at end of file From 97dcf13ef8c6bb738af2193b613bcc9128db2ba9 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 03:20:33 +0900 Subject: [PATCH 135/223] =?UTF-8?q?chore:=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=EA=B0=80=20=EC=9E=98=EB=AA=BB=20=EB=90=98?= =?UTF-8?q?=EC=96=B4=EC=9E=88=EB=8D=98=20=EB=B6=80=EB=B6=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/db/mysql/MysqlApplicationTest.kt | 6 ++---- .../storage/db/mysql/notice/NoticeEntityRepositoryTest.kt | 7 ++----- .../storage/db/mysql/notice/NoticeEntityTest.kt | 3 +-- .../storage/db/mysql/notice/NoticeJpaRepositoryTest.kt | 4 +--- .../db/mysql/subscribe/SubscribeEntityRepositoryTest.kt | 7 ++----- .../storage/db/mysql/subscribe/SubscribeEntityTest.kt | 2 +- .../db/mysql/subscribe/SubscribeJpaRepositoryTest.kt | 2 +- 7 files changed, 10 insertions(+), 21 deletions(-) rename dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/{dmfou => dmforu}/storage/db/mysql/MysqlApplicationTest.kt (63%) rename dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/{dmfou => dmforu}/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt (97%) rename dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/{dmfou => dmforu}/storage/db/mysql/notice/NoticeEntityTest.kt (94%) rename dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/{dmfou => dmforu}/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt (98%) rename dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/{dmfou => dmforu}/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt (95%) rename dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/{dmfou => dmforu}/storage/db/mysql/subscribe/SubscribeEntityTest.kt (97%) rename dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/{dmfou => dmforu}/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt (99%) diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/MysqlApplicationTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/MysqlApplicationTest.kt similarity index 63% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/MysqlApplicationTest.kt rename to dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/MysqlApplicationTest.kt index 40040cc..dd737d3 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/MysqlApplicationTest.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/MysqlApplicationTest.kt @@ -1,10 +1,8 @@ -package com.dmfou.storage.db.mysql +package com.dmforu.storage.db.mysql import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.context.properties.ConfigurationPropertiesScan @ConfigurationPropertiesScan -@SpringBootApplication( - scanBasePackages = ["com.dmforu.storage.db.mysql"] -) +@SpringBootApplication class MysqlApplicationTest \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt similarity index 97% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt rename to dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt index b5b4bda..8001994 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt @@ -1,11 +1,8 @@ -package com.dmfou.storage.db.mysql.notice +package com.dmforu.storage.db.mysql.notice import com.dmforu.domain.notice.Notice +import com.dmforu.storage.db.mysql.MysqlApplicationTest import com.dmforu.storage.db.mysql.config.MysqlJpaConfig -import com.dmforu.storage.db.mysql.notice.NoticeEntity -import com.dmforu.storage.db.mysql.notice.NoticeEntityRepository -import com.dmforu.storage.db.mysql.notice.NoticeJpaRepository -import com.dmfou.storage.db.mysql.MysqlApplicationTest import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.tuple import org.junit.jupiter.api.AfterEach diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityTest.kt similarity index 94% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityTest.kt rename to dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityTest.kt index 520d05c..37765b1 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeEntityTest.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityTest.kt @@ -1,7 +1,6 @@ -package com.dmfou.storage.db.mysql.notice +package com.dmforu.storage.db.mysql.notice import com.dmforu.domain.notice.Notice -import com.dmforu.storage.db.mysql.notice.NoticeEntity import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt similarity index 98% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt rename to dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt index 40e242a..2f2e4c5 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt @@ -1,9 +1,7 @@ -package com.dmfou.storage.db.mysql.notice +package com.dmforu.storage.db.mysql.notice import com.dmforu.domain.notice.Notice import com.dmforu.storage.db.mysql.config.MysqlJpaConfig -import com.dmforu.storage.db.mysql.notice.NoticeEntity -import com.dmforu.storage.db.mysql.notice.NoticeJpaRepository import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.tuple import org.junit.jupiter.api.DisplayName diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt similarity index 95% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt rename to dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt index 98bc480..6c05a9a 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt @@ -1,11 +1,8 @@ -package com.dmfou.storage.db.mysql.subscribe +package com.dmforu.storage.db.mysql.subscribe import com.dmforu.domain.subscribe.Subscribe import com.dmforu.storage.db.mysql.config.MysqlJpaConfig -import com.dmforu.storage.db.mysql.subscribe.SubscribeEntity -import com.dmforu.storage.db.mysql.subscribe.SubscribeEntityRepository -import com.dmforu.storage.db.mysql.subscribe.SubscribeJpaRepository -import com.dmfou.storage.db.mysql.MysqlApplicationTest +import com.dmforu.storage.db.mysql.MysqlApplicationTest import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.tuple import org.junit.jupiter.api.AfterEach diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityTest.kt similarity index 97% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityTest.kt rename to dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityTest.kt index 372ffae..a2f1f28 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeEntityTest.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityTest.kt @@ -1,4 +1,4 @@ -package com.dmfou.storage.db.mysql.subscribe +package com.dmforu.storage.db.mysql.subscribe import com.dmforu.domain.subscribe.Subscribe import com.dmforu.storage.db.mysql.subscribe.SubscribeEntity diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt similarity index 99% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt rename to dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt index a20b135..1da9b9f 100644 --- a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmfou/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt +++ b/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt @@ -1,4 +1,4 @@ -package com.dmfou.storage.db.mysql.subscribe +package com.dmforu.storage.db.mysql.subscribe import com.dmforu.domain.subscribe.Subscribe import com.dmforu.storage.db.mysql.config.MysqlJpaConfig From 2232cd26836d70a399c006261082b1b4517d41dd Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 17:17:33 +0900 Subject: [PATCH 136/223] =?UTF-8?q?chore:=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawling/{WebPageLoader.kt => loader/HtmlLoader.kt} | 2 +- .../{JsoupWebPageLoader.kt => loader/JsoupHtmlLoader.kt} | 2 +- .../dmforu/crawling/{ => parser}/DepartmentNoticeParser.kt | 4 ++-- .../kotlin/com/dmforu/crawling/{ => parser}/DietParser.kt | 4 ++-- .../main/kotlin/com/dmforu/crawling/{ => parser}/Parser.kt | 0 .../com/dmforu/crawling/{ => parser}/ScheduleParser.kt | 4 ++-- .../dmforu/crawling/{ => parser}/UniversityNoticeParser.kt | 4 ++-- .../kotlin/com/dmforu/crawling/loader/JsoupHtmlLoaderTest.kt | 5 +++++ 8 files changed, 15 insertions(+), 10 deletions(-) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{WebPageLoader.kt => loader/HtmlLoader.kt} (66%) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{JsoupWebPageLoader.kt => loader/JsoupHtmlLoader.kt} (89%) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{ => parser}/DepartmentNoticeParser.kt (95%) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{ => parser}/DietParser.kt (94%) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{ => parser}/Parser.kt (100%) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{ => parser}/ScheduleParser.kt (96%) rename dmforu-crawling/src/main/kotlin/com/dmforu/crawling/{ => parser}/UniversityNoticeParser.kt (95%) create mode 100644 dmforu-crawling/src/test/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoaderTest.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/HtmlLoader.kt similarity index 66% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/HtmlLoader.kt index 2e9271b..91de14d 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/WebPageLoader.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/HtmlLoader.kt @@ -1,5 +1,5 @@ package com.dmforu.crawling -interface WebPageLoader { +interface HtmlLoader { fun getHTML(url: String): Result } \ No newline at end of file diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/JsoupWebPageLoader.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoader.kt similarity index 89% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/JsoupWebPageLoader.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoader.kt index 58452ef..f60e4bf 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/JsoupWebPageLoader.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoader.kt @@ -4,7 +4,7 @@ import org.jsoup.Jsoup import org.jsoup.nodes.Document import java.io.IOException -class JsoupWebPageLoader : WebPageLoader { +class JsoupHtmlLoader : HtmlLoader { override fun getHTML(url: String): Document { return try { Jsoup.connect(url).get() diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt similarity index 95% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt index a0cda0a..cc6584b 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DepartmentNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt @@ -9,7 +9,7 @@ import java.time.format.DateTimeFormatter import java.util.regex.Pattern class DepartmentNoticeParser( - private val webPageLoader: WebPageLoader, + private val htmlLoader: HtmlLoader, ) : Parser { private lateinit var major: Major @@ -26,7 +26,7 @@ class DepartmentNoticeParser( */ override fun parse(): List { val departmentNotices: MutableList = mutableListOf() - val document = webPageLoader.getHTML(generateSearchUrl()) + val document = htmlLoader.getHTML(generateSearchUrl()) val rows = document.select(".board-table tbody tr") rows.forEach { row -> diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DietParser.kt similarity index 94% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DietParser.kt index e4ccd56..c68de51 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/DietParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DietParser.kt @@ -7,10 +7,10 @@ import java.time.LocalDate import java.time.format.DateTimeFormatter class DietParser ( - private val webPageLoader: WebPageLoader + private val htmlLoader: HtmlLoader ) : Parser { override fun parse(): List { - val document = webPageLoader.getHTML(DMU_DIET_URL) + val document = htmlLoader.getHTML(DMU_DIET_URL) val rows = document.select(TABLE_SELECTOR) return rows.mapNotNull { row -> parseDiet(row) } diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/Parser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/Parser.kt similarity index 100% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/Parser.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/Parser.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/ScheduleParser.kt similarity index 96% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/ScheduleParser.kt index 0131814..f9fded4 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/ScheduleParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/ScheduleParser.kt @@ -7,7 +7,7 @@ import java.time.LocalDate import java.time.ZoneId class ScheduleParser( - private val webPageLoader: WebPageLoader, + private val htmlLoader: HtmlLoader, ) : Parser { override fun parse(): List { val currentYear = LocalDate.now(ZoneId.of(TIME_ZONE)).year @@ -20,7 +20,7 @@ class ScheduleParser( } private fun fetchYearSchedule(year: Int): List { - val document = webPageLoader.getHTML(DMU_SCHEDULE_URL + year) + val document = htmlLoader.getHTML(DMU_SCHEDULE_URL + year) val monthTables = document.select(YEAR_SCHEDULE_SELECTOR) return monthTables.mapNotNull { monthTable -> diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/UniversityNoticeParser.kt similarity index 95% rename from dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt rename to dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/UniversityNoticeParser.kt index a264a44..9de7488 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/UniversityNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/UniversityNoticeParser.kt @@ -7,7 +7,7 @@ import java.time.LocalDate import java.time.format.DateTimeFormatter class UniversityNoticeParser( - private val webPageLoader: WebPageLoader + private val htmlLoader: HtmlLoader ) : Parser { private var pageNumber = 1 @@ -19,7 +19,7 @@ class UniversityNoticeParser( override fun parse(): List { val universityNotices: MutableList = java.util.ArrayList() - val document = webPageLoader.getHTML(generateSearchUrl()) + val document = htmlLoader.getHTML(generateSearchUrl()) val rows = document.select(".board-table tbody tr") diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoaderTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoaderTest.kt new file mode 100644 index 0000000..93285a7 --- /dev/null +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoaderTest.kt @@ -0,0 +1,5 @@ +package com.dmforu.crawling.loader + +import org.junit.jupiter.api.Assertions.* + +class JsoupHtmlLoaderTest \ No newline at end of file From dfa96abdde55f08dd6b275311cb727fb9d64bd6f Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 17:18:26 +0900 Subject: [PATCH 137/223] =?UTF-8?q?test:=20JsoupHtmlLoader=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawling/exception/HtmlLoadException.kt | 3 ++ .../com/dmforu/crawling/loader/HtmlLoader.kt | 4 +- .../dmforu/crawling/loader/JsoupHtmlLoader.kt | 14 ++--- .../crawling/loader/JsoupHtmlLoaderTest.kt | 54 ++++++++++++++++++- 4 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/HtmlLoadException.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/HtmlLoadException.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/HtmlLoadException.kt new file mode 100644 index 0000000..ab92d67 --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/HtmlLoadException.kt @@ -0,0 +1,3 @@ +package com.dmforu.crawling.exception + +class HtmlLoadException(message: String, cause: Throwable? = null) : RuntimeException(message, cause) diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/HtmlLoader.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/HtmlLoader.kt index 91de14d..0d50350 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/HtmlLoader.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/HtmlLoader.kt @@ -1,5 +1,5 @@ -package com.dmforu.crawling +package com.dmforu.crawling.loader interface HtmlLoader { - fun getHTML(url: String): Result + fun get(url: String): Result } \ No newline at end of file diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoader.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoader.kt index f60e4bf..f44847c 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoader.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoader.kt @@ -1,16 +1,18 @@ -package com.dmforu.crawling +package com.dmforu.crawling.loader +import com.dmforu.crawling.exception.HtmlLoadException import org.jsoup.Jsoup import org.jsoup.nodes.Document import java.io.IOException -class JsoupHtmlLoader : HtmlLoader { - override fun getHTML(url: String): Document { +class JsoupHtmlLoader( + private val connectionProvider : (String) -> Document = { Jsoup.connect(it).get() } +) : HtmlLoader { + override fun get(url: String): Document { return try { - Jsoup.connect(url).get() + connectionProvider(url) } catch (e: IOException) { - // TODO: 페이지 로딩 실패나 네트워크 오류인 경우 핸들링을 해야함 - throw IllegalArgumentException("해당하는 URL 의 HTML을 불러올 수 없습니다.") + throw HtmlLoadException("해당하는 URL의 HTML을 불러올 수 없습니다.", e) } } } \ No newline at end of file diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoaderTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoaderTest.kt index 93285a7..c280eba 100644 --- a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoaderTest.kt +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/loader/JsoupHtmlLoaderTest.kt @@ -1,5 +1,55 @@ package com.dmforu.crawling.loader -import org.junit.jupiter.api.Assertions.* +import com.dmforu.crawling.exception.HtmlLoadException +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.jsoup.nodes.Document +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.mockito.BDDMockito.given +import org.mockito.Mockito.mock +import java.io.IOException -class JsoupHtmlLoaderTest \ No newline at end of file + +class JsoupHtmlLoaderTest { + + private lateinit var connectionProvider: (String) -> Document + private lateinit var htmlLoader: JsoupHtmlLoader + + @BeforeEach + fun setUp() { + connectionProvider = mock() + htmlLoader = JsoupHtmlLoader(connectionProvider) + } + + @DisplayName("URL의 HTML을 불러올 수 있다.") + @Test + fun get() { + // given + val url = "https://www.example.com" + val expectedDocument: Document = mock() + + given(connectionProvider.invoke(url)).willReturn(expectedDocument) + + // when + val result = htmlLoader.get(url) + + // then + assertThat(result).isSameAs(expectedDocument) + } + + @DisplayName("URL의 HTML을 불러올 수 없을 경우, HtmlLoadException 예외가 발생한다.") + @Test + fun getWhenConnectionFails() { + // given + val url = "https://www.example.com" + + given(connectionProvider.invoke(url)).willAnswer { throw IOException() } + + // when // then + assertThatThrownBy { htmlLoader.get(url) } + .isInstanceOf(HtmlLoadException::class.java) + .hasMessage("해당하는 URL의 HTML을 불러올 수 없습니다.") + } +} \ No newline at end of file From 9505bec7287abf7f4f01e06674cc1bdcec4f099d Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 17:49:06 +0900 Subject: [PATCH 138/223] =?UTF-8?q?test:=20Department=20Notice=20Parser=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/config/ApplicationConfiguration.kt | 17 +- .../DepartmentNoticeCrawlingService.kt | 6 +- .../scheduler/crawling/DietCrawlingService.kt | 2 +- .../crawling/ScheduleCrawlingService.kt | 2 +- .../UniversityNoticeCrawlingService.kt | 2 +- .../exception/GenerateUrlException.kt | 4 + .../crawling/parser/DepartmentNoticeParser.kt | 74 ++++---- .../com/dmforu/crawling/parser/DietParser.kt | 5 +- .../com/dmforu/crawling/parser/Parser.kt | 2 +- .../dmforu/crawling/parser/ScheduleParser.kt | 5 +- .../crawling/parser/UniversityNoticeParser.kt | 7 +- .../crawling/DepartmentNoticeParserTest.kt | 160 ++++++++++-------- 12 files changed, 147 insertions(+), 139 deletions(-) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/GenerateUrlException.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt index 3d58122..5fb5058 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt @@ -1,9 +1,10 @@ package com.dmforu.admin.config -import com.dmforu.crawling.DepartmentNoticeParser -import com.dmforu.crawling.DietParser -import com.dmforu.crawling.ScheduleParser -import com.dmforu.crawling.UniversityNoticeParser +import com.dmforu.crawling.loader.JsoupHtmlLoader +import com.dmforu.crawling.parser.DepartmentNoticeParser +import com.dmforu.crawling.parser.DietParser +import com.dmforu.crawling.parser.ScheduleParser +import com.dmforu.crawling.parser.UniversityNoticeParser import com.dmforu.domain.diet.DietRepository import com.dmforu.domain.diet.DietWriter import com.dmforu.domain.notice.NoticeReader @@ -47,22 +48,22 @@ class ApplicationConfiguration { @Scope("prototype") @Bean fun departmentNoticeParser(): DepartmentNoticeParser { - return DepartmentNoticeParser() + return DepartmentNoticeParser(htmlLoader = JsoupHtmlLoader()) } @Scope("prototype") @Bean fun universityNoticeParser(): UniversityNoticeParser { - return UniversityNoticeParser() + return UniversityNoticeParser(htmlLoader = JsoupHtmlLoader()) } @Bean fun dietParser(): DietParser { - return DietParser() + return DietParser(htmlLoader = JsoupHtmlLoader()) } @Bean fun scheduleParser(): ScheduleParser { - return ScheduleParser() + return ScheduleParser(htmlLoader = JsoupHtmlLoader()) } } \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index 635ca21..540ea3c 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -1,6 +1,6 @@ package com.dmforu.admin.scheduler.crawling -import com.dmforu.crawling.DepartmentNoticeParser +import com.dmforu.crawling.parser.DepartmentNoticeParser import com.dmforu.domain.notice.* import org.springframework.beans.factory.ObjectProvider import org.springframework.context.ApplicationEventPublisher @@ -35,13 +35,11 @@ class DepartmentNoticeCrawlingService( private fun crawlMajorDepartment(major: Major) { val parser = prototypeBeanProvider.getObject() - parser.initialize(major) - val maxNumber: Int? = noticeReader.findMaxNumberByType(major.type) val currentMaxNumber = maxNumber ?: 0 while (true) { - val notices: List = parser.parse() + val notices: List = parser.parse(major) val isNewNoticeFound = saveNewNotices(notices, currentMaxNumber) if (!isNewNoticeFound) { diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt index 0425da4..5239e0f 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt @@ -1,6 +1,6 @@ package com.dmforu.admin.scheduler.crawling -import com.dmforu.crawling.DietParser +import com.dmforu.crawling.parser.DietParser import com.dmforu.domain.diet.DietWriter import org.springframework.stereotype.Service diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt index 768dc8e..ace78cc 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt @@ -1,6 +1,6 @@ package com.dmforu.admin.scheduler.crawling -import com.dmforu.crawling.ScheduleParser +import com.dmforu.crawling.parser.ScheduleParser import com.dmforu.domain.schedule.ScheduleWriter import org.springframework.stereotype.Service diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt index 18ddbdb..5b9f049 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt @@ -1,6 +1,6 @@ package com.dmforu.admin.scheduler.crawling -import com.dmforu.crawling.UniversityNoticeParser +import com.dmforu.crawling.parser.UniversityNoticeParser import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.NoticeReader import com.dmforu.domain.notice.NoticeWriter diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/GenerateUrlException.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/GenerateUrlException.kt new file mode 100644 index 0000000..3c49f23 --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/GenerateUrlException.kt @@ -0,0 +1,4 @@ +package com.dmforu.crawling.exception + +class GenerateUrlException(message: String = "URL 생성에 실패했습니다.", cause: Throwable? = null) : + RuntimeException(message, cause) \ No newline at end of file diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt index cc6584b..8e3af1d 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt @@ -1,39 +1,36 @@ -package com.dmforu.crawling +package com.dmforu.crawling.parser +import com.dmforu.crawling.exception.GenerateUrlException +import com.dmforu.crawling.loader.HtmlLoader import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.Major import org.jsoup.nodes.Document import org.jsoup.nodes.Element import java.time.LocalDate import java.time.format.DateTimeFormatter +import java.util.regex.Matcher import java.util.regex.Pattern class DepartmentNoticeParser( private val htmlLoader: HtmlLoader, -) : Parser { +) { private lateinit var major: Major private var pageNumber: Int = 1 - fun initialize(major: Major) { - this.major = major - } + fun parse(major: Major): List { + initialize(major) - /** - * HTML을 파싱하여 학과 공지사항 목록을 반환한다. - * - * @return 학과 공지사항 목록 - */ - override fun parse(): List { - val departmentNotices: MutableList = mutableListOf() - val document = htmlLoader.getHTML(generateSearchUrl()) - - val rows = document.select(".board-table tbody tr") - rows.forEach { row -> - departmentNotices.add(parseRow(row)) - } + val document = htmlLoader.get(generateSearchUrl()) + + return document.select(".board-table tbody tr") + .map { row -> parseRow(row) } + .toList() - return departmentNotices + } + + private fun initialize(major: Major) { + this.major = major } private fun parseRow(row: Element): Notice { @@ -53,38 +50,31 @@ class DepartmentNoticeParser( ) } - /** - * 파싱할 페이지의 URL을 생성한다. - * - * @return URL - */ private fun generateSearchUrl(): String { - return java.lang.String.format( - "https://www.dongyang.ac.kr/%s/%s/subview.do?page=%d", - major.majorPath, major.noticePath, pageNumber++ - ) + return StringBuilder() + .append("https://www.dongyang.ac.kr/").append(major.majorPath).append("/").append(major.noticePath) + .append("/subview.do?page=").append(pageNumber++).toString() + } - /** - * 파싱 결과를 통해 공지사항의 URL을 생성한다. - * - * @param url 파싱 결과 - * @return URL - * @throws IllegalArgumentException Matcher를 통해 URL을 생성할 수 없는 경우 예외 발생 - */ private fun generateUrlFromSearch(url: String): String { - // URL에서 정보를 추출하기 위한 Matcher 생성 + val matcher: Matcher = pattern.matcher(url) - val matcher = pattern.matcher(url) + verifyValidMatcher(matcher) - require(matcher.find()) { "Matcher did not find any match" } + return StringBuilder() + .append("https://www.dongyang.ac.kr/combBbs/").append(matcher.group(1)) + .append("/").append(matcher.group(2)).append("/").append(matcher.group(4)) + .append("/view.do?layout=unknown").toString() + } - return String.format( - "https://www.dongyang.ac.kr/combBbs/%s/%s/%s/view.do?layout=unknown", - matcher.group(1), matcher.group(2), matcher.group(4) - ) + private fun verifyValidMatcher(matcher: Matcher) { + if (!matcher.find()) { + throw GenerateUrlException() + } } + companion object { private val pattern: Pattern = Pattern.compile("\\('([^']+)'\\,'([^']+)'\\,'([^']+)'\\,'([^']+)'") private val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DietParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DietParser.kt index c68de51..96cc568 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DietParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DietParser.kt @@ -1,5 +1,6 @@ -package com.dmforu.crawling +package com.dmforu.crawling.parser +import com.dmforu.crawling.loader.HtmlLoader import com.dmforu.domain.diet.Diet import org.jsoup.nodes.Document import org.jsoup.nodes.Element @@ -10,7 +11,7 @@ class DietParser ( private val htmlLoader: HtmlLoader ) : Parser { override fun parse(): List { - val document = htmlLoader.getHTML(DMU_DIET_URL) + val document = htmlLoader.get(DMU_DIET_URL) val rows = document.select(TABLE_SELECTOR) return rows.mapNotNull { row -> parseDiet(row) } diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/Parser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/Parser.kt index 5b24f7c..2c4a17c 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/Parser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/Parser.kt @@ -1,4 +1,4 @@ -package com.dmforu.crawling +package com.dmforu.crawling.parser interface Parser { fun parse(): List diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/ScheduleParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/ScheduleParser.kt index f9fded4..b1fb69a 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/ScheduleParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/ScheduleParser.kt @@ -1,5 +1,6 @@ -package com.dmforu.crawling +package com.dmforu.crawling.parser +import com.dmforu.crawling.loader.HtmlLoader import com.dmforu.domain.schedule.Schedule import org.jsoup.nodes.Document import org.jsoup.nodes.Element @@ -20,7 +21,7 @@ class ScheduleParser( } private fun fetchYearSchedule(year: Int): List { - val document = htmlLoader.getHTML(DMU_SCHEDULE_URL + year) + val document = htmlLoader.get(DMU_SCHEDULE_URL + year) val monthTables = document.select(YEAR_SCHEDULE_SELECTOR) return monthTables.mapNotNull { monthTable -> diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/UniversityNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/UniversityNoticeParser.kt index 9de7488..b62dea1 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/UniversityNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/UniversityNoticeParser.kt @@ -1,5 +1,6 @@ -package com.dmforu.crawling +package com.dmforu.crawling.parser +import com.dmforu.crawling.loader.HtmlLoader import com.dmforu.domain.notice.Notice import org.jsoup.nodes.Document import java.lang.NumberFormatException @@ -8,7 +9,7 @@ import java.time.format.DateTimeFormatter class UniversityNoticeParser( private val htmlLoader: HtmlLoader -) : Parser { +) : Parser { private var pageNumber = 1 /** @@ -19,7 +20,7 @@ class UniversityNoticeParser( override fun parse(): List { val universityNotices: MutableList = java.util.ArrayList() - val document = htmlLoader.getHTML(generateSearchUrl()) + val document = htmlLoader.get(generateSearchUrl()) val rows = document.select(".board-table tbody tr") diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt index f156eb7..3018a18 100644 --- a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt @@ -1,99 +1,111 @@ package com.dmforu.crawling +import com.dmforu.crawling.exception.GenerateUrlException +import com.dmforu.crawling.loader.HtmlLoader +import com.dmforu.crawling.parser.DepartmentNoticeParser import com.dmforu.domain.notice.Major +import org.assertj.core.api.Assertions.* +import org.jsoup.Jsoup import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import org.jsoup.select.Elements -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.ArgumentMatchers.anyString +import org.mockito.ArgumentMatchers.* import org.mockito.BDDMockito.given import org.mockito.InjectMocks import org.mockito.Mock -import org.mockito.Mockito.mock import org.mockito.junit.jupiter.MockitoExtension import java.time.LocalDate -import java.time.format.DateTimeFormatter @ExtendWith(MockitoExtension::class) class DepartmentNoticeParserTest { @Mock - private lateinit var webPageLoader: WebPageLoader + private lateinit var htmlLoader: HtmlLoader @InjectMocks private lateinit var parser: DepartmentNoticeParser + @DisplayName("") @Test - fun `should return list of Notice when HTML is valid`() { - // Arrange + fun parse() { + // given + val html = """ + + + + + + + + + + + + + + + +
2공지 제목 2작성자 22024.10.02
1공지 제목 1작성자 12024.10.01
+ """.trimIndent() + val document: Document = Jsoup.parse(html) + + given(htmlLoader.get(anyString())).willReturn(document) + + // when + val notices = parser.parse(Major.COMPUTER_SOFTWARE_ENGINEERING) + + // then + assertThat(notices).hasSize(2) + .extracting("number", "title", "author", "date", "url") + .containsExactlyInAnyOrder( + tuple( + 2, + "공지 제목 2", + "작성자 2", + LocalDate.of(2024, 10, 2), + "https://www.dongyang.ac.kr/combBbs/2/url/2/view.do?layout=unknown" + ), + tuple( + 1, + "공지 제목 1", + "작성자 1", + LocalDate.of(2024, 10, 1), + "https://www.dongyang.ac.kr/combBbs/1/url/1/view.do?layout=unknown" + ), + + ) - parser.initialize(Major.COMPUTER_SOFTWARE_ENGINEERING) - - val mockDocument = mock(Document::class.java) - val mockRow1 = mock(Element::class.java) - val mockRow2 = mock(Element::class.java) - - // Mocking the rows of the table - val rows = Elements(mockRow1, mockRow2) - given(webPageLoader.getHTML(anyString())).willReturn(mockDocument) - given(mockDocument.select(".board-table tbody tr")).willReturn(rows) - - // Setting up the first row mock - val mockNumElement1 = mock(Element::class.java) - given(mockNumElement1.text()).willReturn("1") - - val mockTitleElement1 = mock(Element::class.java) - given(mockTitleElement1.text()).willReturn("Notice Title 1") - - val mockTitleElement10 = mock(Element::class.java) - given(mockTitleElement10.attr("href")).willReturn("('dmu_23222','14','320','129499')") - - - val mockAuthorElement1 = mock(Element::class.java) - val testAuthorElements1 = Elements(mockAuthorElement1) - given(mockRow1.select(".td-write")).willReturn(testAuthorElements1) - given(mockAuthorElement1.text()).willReturn("Author A") - - val mockDateElement1 = mock(Element::class.java) - given(mockDateElement1.text()).willReturn("2024.10.23") - - // Mocking select results for first row - val test12 = mock(Elements(mockTitleElement10)) - given(mockRow1.select(".td-num")).willReturn(Elements(mockNumElement1)) - given(mockRow1.select(".td-subject a")) - .willReturn(Elements(mockTitleElement1)) - .willReturn(test12) - given(mockRow1.select(".td-date")).willReturn(Elements(mockDateElement1)) - - // Setting up the second row mock - val mockNumElement2 = mock(Element::class.java) - given(mockNumElement2.text()).willReturn("2") - - val mockTitleElement2 = mock(Element::class.java) - given(mockTitleElement2.text()).willReturn("Notice Title 2") - given(mockTitleElement2.attr("href")).willReturn("('dmu_23222','14','320','129499')") - - val mockAuthorElement2 = mock(Element::class.java) - val testAuthorElements2 = Elements(mockAuthorElement2) - given(mockRow2.select(".td-write")).willReturn(testAuthorElements2) - given(mockAuthorElement2.text()).willReturn("Author B") - - val mockDateElement2 = mock(Element::class.java) - given(mockDateElement2.text()).willReturn("2024.10.24") - - // Mocking select results for second row - given(mockRow2.select(".td-num")).willReturn(Elements(mockNumElement2)) - given(mockRow2.select(".td-subject a")).willReturn(Elements(mockTitleElement2)) - given(mockRow2.select(".td-date")).willReturn(Elements(mockDateElement2)) - - // Act - val notices = parser.parse() + } - // Assert - assertEquals(2, notices.size) - assertTrue(notices.any { it.title == "Notice Title 1" && it.author == "Author A" && it.date == LocalDate.parse("2024.10.23", DateTimeFormatter.ofPattern("yyyy.MM.dd")) }) - assertTrue(notices.any { it.title == "Notice Title 2" && it.author == "Author B" && it.date == LocalDate.parse("2024.10.24", DateTimeFormatter.ofPattern("yyyy.MM.dd")) }) + @Test + fun parseWhenUrlInvalid() { + // given + val html = """ + + + + + + + + + + + + + + + +
2공지 제목 2작성자 22024.10.02
1공지 제목 1작성자 12024.10.01
+ """.trimIndent() + val document: Document = Jsoup.parse(html) + + given(htmlLoader.get(anyString())).willReturn(document) + + // when // then + assertThatThrownBy { parser.parse(Major.COMPUTER_SOFTWARE_ENGINEERING) } + .isInstanceOf(GenerateUrlException::class.java) + .hasMessage("URL 생성에 실패했습니다.") } } \ No newline at end of file From bfdc6b3e9e7ac6b3887328b9889d1116ad3f20f5 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 19:29:23 +0900 Subject: [PATCH 139/223] =?UTF-8?q?test:=20University=20Notice=20Parser=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawling/parser/UniversityNoticeParser.kt | 37 +--- .../parser/UniversityNoticeParserTest.kt | 158 ++++++++++++++++++ 2 files changed, 166 insertions(+), 29 deletions(-) create mode 100644 dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/UniversityNoticeParserTest.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/UniversityNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/UniversityNoticeParser.kt index b62dea1..3464a78 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/UniversityNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/UniversityNoticeParser.kt @@ -8,15 +8,10 @@ import java.time.LocalDate import java.time.format.DateTimeFormatter class UniversityNoticeParser( - private val htmlLoader: HtmlLoader + private val htmlLoader: HtmlLoader, ) : Parser { private var pageNumber = 1 - /** - * HTML을 파싱하여 대학 공지사항 목록을 반환한다. - * - * @return 대학 공지사항 목록 - */ override fun parse(): List { val universityNotices: MutableList = java.util.ArrayList() @@ -49,36 +44,22 @@ class UniversityNoticeParser( universityNotices.add(universityNotice) } - + String return universityNotices } - /** - * 파싱할 페이지의 URL을 생성한다. - * - * @return URL - */ private fun generateSearchUrl(): String { - return String.format(SEARCH_URL, pageNumber++) + return StringBuilder() + .append("https://www.dongyang.ac.kr/dongyang/129/subview.do?page=").append(pageNumber++) + .toString() } - /** - * 파싱 결과를 통해 공지사항의 URL를 생성한다. - * - * @param url URL 파싱결과 - * @return 공지사항 URL - */ private fun generateUrlFromSearch(url: String): String { - return String.format(RESULT_URL, url) + return StringBuilder() + .append("https://www.dongyang.ac.kr").append(url).append("?layout=unknown") + .toString() } - /** - * 접미사를 제거한다. - * - * @param title 원본 문자열 - * @param suffix 제거하고 싶은 접미사 - * @return 원본에서 접미사를 제거한 문자열 - */ private fun removeSuffix(title: String, suffix: String): String { if (title.endsWith(suffix)) { return title.substring(0, title.length - suffix.length).trim { it <= ' ' } @@ -89,8 +70,6 @@ class UniversityNoticeParser( companion object { private val DATE_FORMATTER: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") - private const val SEARCH_URL = "https://www.dongyang.ac.kr/dongyang/129/subview.do?page=%d" - private const val RESULT_URL = "https://www.dongyang.ac.kr%s?layout=unknown" private const val SUFFIX_NEW_POST = "새글" private const val NOTICE_TYPE = "대학" } diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/UniversityNoticeParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/UniversityNoticeParserTest.kt new file mode 100644 index 0000000..99d7045 --- /dev/null +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/UniversityNoticeParserTest.kt @@ -0,0 +1,158 @@ +package com.dmforu.crawling.parser + +import com.dmforu.crawling.loader.HtmlLoader +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.tuple +import org.jsoup.Jsoup +import org.jsoup.nodes.Document +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.ArgumentMatchers.anyString +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import java.time.LocalDate + +@ExtendWith(MockitoExtension::class) +class UniversityNoticeParserTest { + + @Mock + private lateinit var htmlLoader: HtmlLoader + + @InjectMocks + private lateinit var universityNoticeParser: UniversityNoticeParser + + @DisplayName("대학 공지사항 목록을 파싱할 수 있다.") + @Test + fun parse() { + // given + val html = """ + + + + + + + + + + + + + + + +
2 + + 공지 제목 2 + + 작성자 22024.10.02
1 + + 공지 제목 1 + + 작성자 12024.10.01
+ """.trimIndent() + + val mockDocument = Jsoup.parse(html) + given(htmlLoader.get(anyString())).willReturn(mockDocument) + + // when + val notices = universityNoticeParser.parse() + + // then + assertThat(notices).hasSize(2) + .extracting("number", "title", "author", "date", "url") + .containsExactlyInAnyOrder( + tuple( + 2, + "공지 제목 2", + "작성자 2", + LocalDate.of(2024, 10, 2), + "https://www.dongyang.ac.kr/url?layout=unknown" + ), + tuple( + 1, + "공지 제목 1", + "작성자 1", + LocalDate.of(2024, 10, 1), + "https://www.dongyang.ac.kr/url?layout=unknown" + ) + ) + } + + @DisplayName("공지사항 번호가 유효하지 않은 경우 해당 행을 건너뛴다.") + @Test + fun parseWhenNumberIsInvalid() { + // given + val html = """ + + + + + + + + + +
일반공지 + + 공지 제목 + + 작성자2024.10.01
+ """.trimIndent() + + val mockDocument = Jsoup.parse(html) + given(htmlLoader.get(anyString())).willReturn(mockDocument) + + // when + val notices = universityNoticeParser.parse() + + // then + assertThat(notices).isEmpty() + } + + @DisplayName("제목에 접미사가 포함된 경우, 접미사를 제거한다.") + @Test + fun removeSuffix() { + // given + val html = """ + + + + + + + + + +
1 + + 공지 제목 + 새글 + + 작성자 12024.10.02
+ """.trimIndent() + + val mockDocument = Jsoup.parse(html) + given(htmlLoader.get(anyString())).willReturn(mockDocument) + + // when + val notices = universityNoticeParser.parse() + + // then + assertThat(notices).hasSize(1) + .extracting("number", "title", "author", "date", "url") + .containsExactlyInAnyOrder( + tuple( + 1, + "공지 제목", + "작성자 1", + LocalDate.of(2024, 10, 2), + "https://www.dongyang.ac.kr/url?layout=unknown" + ), + ) + } +} \ No newline at end of file From 7544c5f2053cba9d08900d99b7b2ddf9bf7b60cc Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 19:30:47 +0900 Subject: [PATCH 140/223] =?UTF-8?q?chore:=20parser=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/crawling/ScheduleParserTest.kt | 116 ------------------ .../DepartmentNoticeParserTest.kt | 3 +- .../crawling/{ => parser}/DietParserTest.kt | 11 +- .../crawling/parser/ScheduleParserTest.kt | 107 ++++++++++++++++ 4 files changed, 114 insertions(+), 123 deletions(-) delete mode 100644 dmforu-crawling/src/test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt rename dmforu-crawling/src/test/kotlin/com/dmforu/crawling/{ => parser}/DepartmentNoticeParserTest.kt (97%) rename dmforu-crawling/src/test/kotlin/com/dmforu/crawling/{ => parser}/DietParserTest.kt (92%) create mode 100644 dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/ScheduleParserTest.kt diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt deleted file mode 100644 index f809cb9..0000000 --- a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/ScheduleParserTest.kt +++ /dev/null @@ -1,116 +0,0 @@ -package com.dmforu.crawling - -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import org.jsoup.select.Elements -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.DisplayName -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.ArgumentMatchers.anyString -import org.mockito.BDDMockito.given -import org.mockito.InjectMocks -import org.mockito.Mock -import org.mockito.Mockito.mock -import org.mockito.junit.jupiter.MockitoExtension -import java.time.LocalDate -import java.time.ZoneId - -@ExtendWith(MockitoExtension::class) -class ScheduleParserTest { - - @Mock - private lateinit var webPageLoader: WebPageLoader - - @InjectMocks - private lateinit var scheduleParser: ScheduleParser - - - @DisplayName("학사 일정을 크롤링 할 수 있다.") - @Test - fun parse() { - // given - // todo 외부로 옮겨야하나? - val currentYear = LocalDate.now(ZoneId.of("Asia/Seoul")).year - - val mockDocument1 = mock(Document::class.java) - val mockDocument2 = mock(Document::class.java) - val mockDocument3 = mock(Document::class.java) - - // Mocking year and month tables - val yearTable1 = mock(Element::class.java) - val monthTable1 = mock(Element::class.java) - - val yearTable2 = mock(Element::class.java) - val monthTable2 = mock(Element::class.java) - - val yearTable3 = mock(Element::class.java) - val monthTable3 = mock(Element::class.java) - - // Create elements for the first mock document - val yearElements1 = Elements(yearTable1) - val monthElements1 = Elements(monthTable1) - val yearElements2 = Elements(yearTable2) - val monthElements2 = Elements(monthTable2) - val yearElements3 = Elements(yearTable3) - val monthElements3 = Elements(monthTable3) - - // Setting up different return values for different calls - given(webPageLoader.getHTML(anyString())) - .willReturn(mockDocument1) // 첫 번째 호출 - .willReturn(mockDocument2) // 두 번째 호출 - .willReturn(mockDocument3) // 세 번째 호출 - - // Setting up the behavior for the first document - given(mockDocument1.select(anyString())).willReturn(yearElements1) - given(yearTable1.select(anyString())).willReturn(monthElements1) - val test = Elements(mock(Element::class.java)) - given(monthTable1.select(anyString())).willReturn(test) - given(test.first().text()).willReturn("2023.01") - - // Setting up the behavior for the second document - given(mockDocument2.select(anyString())).willReturn(yearElements2) - given(yearTable2.select(anyString())).willReturn(monthElements2) - given(monthTable2.select(anyString())).willReturn(test) - given(test.first().text()).willReturn("2023.02") - - // Setting up the behavior for the third document - given(mockDocument3.select(anyString())).willReturn(yearElements3) - given(yearTable3.select(anyString())).willReturn(monthElements3) - given(monthTable3.select(anyString())).willReturn(test) - given(test.first().text()).willReturn("2023.03") - - // Execute - val result = scheduleParser.parse() - - // Verify the result - assertEquals(3, result.size) - } - - - // - // val test1 = Elements(mock(Element::class.java)) - // - // // Set up month text for the first month table - // given(monthTable1.select("p")).willReturn(test1) - // - // given(test1.text()).willReturn("2024.1") - // - // // Create elements for the second mock document - - // - // val test2 = Elements(mock(Element::class.java)) - // // Set up month text for the second month table - // given(monthTable2.select("p")).willReturn(test2) - // - // given(test2.text()).willReturn("2024.2") - // - // // Create elements for the third mock document - - // - // val test3 = Elements(mock(Element::class.java)) - // // Set up month text for the third month table - // given(monthTable3.select("p")).willReturn(test3) - // - // given(test3.text()).willReturn("2024.3") // 여기도 마찬가지. -} \ No newline at end of file diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParserTest.kt similarity index 97% rename from dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt rename to dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParserTest.kt index 3018a18..0e929a3 100644 --- a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DepartmentNoticeParserTest.kt +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParserTest.kt @@ -1,8 +1,7 @@ -package com.dmforu.crawling +package com.dmforu.crawling.parser import com.dmforu.crawling.exception.GenerateUrlException import com.dmforu.crawling.loader.HtmlLoader -import com.dmforu.crawling.parser.DepartmentNoticeParser import com.dmforu.domain.notice.Major import org.assertj.core.api.Assertions.* import org.jsoup.Jsoup diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DietParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DietParserTest.kt similarity index 92% rename from dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DietParserTest.kt rename to dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DietParserTest.kt index ff42bee..d3fb74a 100644 --- a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/DietParserTest.kt +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DietParserTest.kt @@ -1,5 +1,6 @@ -package com.dmforu.crawling +package com.dmforu.crawling.parser +import com.dmforu.crawling.loader.HtmlLoader import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.tuple import org.jsoup.nodes.Document @@ -20,7 +21,7 @@ import java.time.LocalDate class DietParserTest { @Mock - private lateinit var webPageLoader: WebPageLoader + private lateinit var htmlLoader: HtmlLoader @InjectMocks private lateinit var dietParser: DietParser @@ -53,7 +54,7 @@ class DietParserTest { mock(Element::class.java).apply { given(text()).willReturn("Menu 3, Menu 4") } ) - given(webPageLoader.getHTML(anyString())).willReturn(mockDocument) + given(htmlLoader.get(anyString())).willReturn(mockDocument) given(mockDocument.select(anyString())).willReturn(mockRows) given(row1.select(anyString())).willReturn(columns1) given(row2.select(anyString())).willReturn(columns2) @@ -86,7 +87,7 @@ class DietParserTest { mock(Element::class.java).apply { given(text()).willReturn(" ") } ) - given(webPageLoader.getHTML(anyString())).willReturn(mockDocument) + given(htmlLoader.get(anyString())).willReturn(mockDocument) given(mockDocument.select(anyString())).willReturn(mockRows) given(row.select(anyString())).willReturn(columns) @@ -113,7 +114,7 @@ class DietParserTest { mock(Element::class.java) ) - given(webPageLoader.getHTML(anyString())).willReturn(mockDocument) + given(htmlLoader.get(anyString())).willReturn(mockDocument) given(mockDocument.select(anyString())).willReturn(mockRows) given(row.select(anyString())).willReturn(columns) diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/ScheduleParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/ScheduleParserTest.kt new file mode 100644 index 0000000..0059004 --- /dev/null +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/ScheduleParserTest.kt @@ -0,0 +1,107 @@ +package com.dmforu.crawling.parser + +import com.dmforu.crawling.loader.HtmlLoader +import org.jsoup.nodes.Document +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension + +@ExtendWith(MockitoExtension::class) +class ScheduleParserTest { + + @Mock + private lateinit var htmlLoader: HtmlLoader + + @InjectMocks + private lateinit var scheduleParser: ScheduleParser + + +// @DisplayName("학사 일정을 크롤링 할 수 있다.") +// @Test +// fun parse() { +// // given +// // todo 외부로 옮겨야하나? +// val currentYear = LocalDate.now(ZoneId.of("Asia/Seoul")).year +// +// val mockDocument1 = mock(Document::class.java) +// val mockDocument2 = mock(Document::class.java) +// val mockDocument3 = mock(Document::class.java) +// +// // Mocking year and month tables +// val yearTable1 = mock(Element::class.java) +// val monthTable1 = mock(Element::class.java) +// +// val yearTable2 = mock(Element::class.java) +// val monthTable2 = mock(Element::class.java) +// +// val yearTable3 = mock(Element::class.java) +// val monthTable3 = mock(Element::class.java) +// +// // Create elements for the first mock document +// val yearElements1 = Elements(yearTable1) +// val monthElements1 = Elements(monthTable1) +// val yearElements2 = Elements(yearTable2) +// val monthElements2 = Elements(monthTable2) +// val yearElements3 = Elements(yearTable3) +// val monthElements3 = Elements(monthTable3) +// +// // Setting up different return values for different calls +// given(webPageLoader.getHTML(anyString())) +// .willReturn(mockDocument1) // 첫 번째 호출 +// .willReturn(mockDocument2) // 두 번째 호출 +// .willReturn(mockDocument3) // 세 번째 호출 +// +// // Setting up the behavior for the first document +// given(mockDocument1.select(anyString())).willReturn(yearElements1) +// given(yearTable1.select(anyString())).willReturn(monthElements1) +// val test = Elements(mock(Element::class.java)) +// given(monthTable1.select(anyString())).willReturn(test) +// given(test.first().text()).willReturn("2023.01") +// +// // Setting up the behavior for the second document +// given(mockDocument2.select(anyString())).willReturn(yearElements2) +// given(yearTable2.select(anyString())).willReturn(monthElements2) +// given(monthTable2.select(anyString())).willReturn(test) +// given(test.first().text()).willReturn("2023.02") +// +// // Setting up the behavior for the third document +// given(mockDocument3.select(anyString())).willReturn(yearElements3) +// given(yearTable3.select(anyString())).willReturn(monthElements3) +// given(monthTable3.select(anyString())).willReturn(test) +// given(test.first().text()).willReturn("2023.03") +// +// // Execute +// val result = scheduleParser.parse() +// +// // Verify the result +// assertEquals(3, result.size) +// } + + + // + // val test1 = Elements(mock(Element::class.java)) + // + // // Set up month text for the first month table + // given(monthTable1.select("p")).willReturn(test1) + // + // given(test1.text()).willReturn("2024.1") + // + // // Create elements for the second mock document + + // + // val test2 = Elements(mock(Element::class.java)) + // // Set up month text for the second month table + // given(monthTable2.select("p")).willReturn(test2) + // + // given(test2.text()).willReturn("2024.2") + // + // // Create elements for the third mock document + + // + // val test3 = Elements(mock(Element::class.java)) + // // Set up month text for the third month table + // given(monthTable3.select("p")).willReturn(test3) + // + // given(test3.text()).willReturn("2024.3") // 여기도 마찬가지. +} \ No newline at end of file From f8fec31ac3c0269a6000db3b3b437cc83912dd23 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 21:49:54 +0900 Subject: [PATCH 141/223] =?UTF-8?q?refactor:=20=EA=B3=B5=EC=A7=80=20URL=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=8B=A4=ED=8C=A8=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/crawling/exception/GenerateNoticeUrlException.kt | 4 ++++ .../com/dmforu/crawling/exception/GenerateUrlException.kt | 4 ---- .../com/dmforu/crawling/parser/DepartmentNoticeParser.kt | 4 ++-- .../dmforu/crawling/parser/DepartmentNoticeParserTest.kt | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/GenerateNoticeUrlException.kt delete mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/GenerateUrlException.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/GenerateNoticeUrlException.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/GenerateNoticeUrlException.kt new file mode 100644 index 0000000..d64668c --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/GenerateNoticeUrlException.kt @@ -0,0 +1,4 @@ +package com.dmforu.crawling.exception + +class GenerateNoticeUrlException(message: String = "공지 URL 생성에 실패했습니다.", cause: Throwable? = null) : + RuntimeException(message, cause) \ No newline at end of file diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/GenerateUrlException.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/GenerateUrlException.kt deleted file mode 100644 index 3c49f23..0000000 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/GenerateUrlException.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.dmforu.crawling.exception - -class GenerateUrlException(message: String = "URL 생성에 실패했습니다.", cause: Throwable? = null) : - RuntimeException(message, cause) \ No newline at end of file diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt index 8e3af1d..68f25cb 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt @@ -1,6 +1,6 @@ package com.dmforu.crawling.parser -import com.dmforu.crawling.exception.GenerateUrlException +import com.dmforu.crawling.exception.GenerateNoticeUrlException import com.dmforu.crawling.loader.HtmlLoader import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.Major @@ -70,7 +70,7 @@ class DepartmentNoticeParser( private fun verifyValidMatcher(matcher: Matcher) { if (!matcher.find()) { - throw GenerateUrlException() + throw GenerateNoticeUrlException() } } diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParserTest.kt index 0e929a3..b326796 100644 --- a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParserTest.kt +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParserTest.kt @@ -1,6 +1,6 @@ package com.dmforu.crawling.parser -import com.dmforu.crawling.exception.GenerateUrlException +import com.dmforu.crawling.exception.GenerateNoticeUrlException import com.dmforu.crawling.loader.HtmlLoader import com.dmforu.domain.notice.Major import org.assertj.core.api.Assertions.* @@ -104,7 +104,7 @@ class DepartmentNoticeParserTest { // when // then assertThatThrownBy { parser.parse(Major.COMPUTER_SOFTWARE_ENGINEERING) } - .isInstanceOf(GenerateUrlException::class.java) - .hasMessage("URL 생성에 실패했습니다.") + .isInstanceOf(GenerateNoticeUrlException::class.java) + .hasMessage("공지 URL 생성에 실패했습니다.") } } \ No newline at end of file From ede642a92a476cb4d903d1e6fdae6135a830a2ed Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 21:50:19 +0900 Subject: [PATCH 142/223] =?UTF-8?q?test:=20ScheduleParser=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/ScheduleParseException.kt | 3 + .../dmforu/crawling/parser/ScheduleParser.kt | 33 +- .../crawling/parser/ScheduleParserTest.kt | 283 ++++++++++++------ 3 files changed, 215 insertions(+), 104 deletions(-) create mode 100644 dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/ScheduleParseException.kt diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/ScheduleParseException.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/ScheduleParseException.kt new file mode 100644 index 0000000..6a68a34 --- /dev/null +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/exception/ScheduleParseException.kt @@ -0,0 +1,3 @@ +package com.dmforu.crawling.exception + +class ScheduleParseException(message: String, cause: Throwable? = null) : RuntimeException(message, cause) diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/ScheduleParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/ScheduleParser.kt index b1fb69a..b0c9149 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/ScheduleParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/ScheduleParser.kt @@ -1,23 +1,20 @@ package com.dmforu.crawling.parser +import com.dmforu.crawling.exception.ScheduleParseException import com.dmforu.crawling.loader.HtmlLoader import com.dmforu.domain.schedule.Schedule import org.jsoup.nodes.Document import org.jsoup.nodes.Element -import java.time.LocalDate -import java.time.ZoneId class ScheduleParser( private val htmlLoader: HtmlLoader, -) : Parser { - override fun parse(): List { - val currentYear = LocalDate.now(ZoneId.of(TIME_ZONE)).year - - // 작년부터 내년의 일정을 가져온다. - return (currentYear - 1..currentYear + 1).map { year -> - val yearSchedule = fetchYearSchedule(year) - Schedule.Year.of(year, yearSchedule) - } +) { + fun parse(currentYear: Int): List { + return (currentYear - 1..currentYear + 1) + .map { year -> + val yearSchedule = fetchYearSchedule(year) + Schedule.Year.of(year, yearSchedule) + } } private fun fetchYearSchedule(year: Int): List { @@ -36,7 +33,7 @@ class ScheduleParser( //

2024.1

p태그에서 "2024.1"을 문자열로 가져온다. // 이때, 월 정보만 필요하기 때문에 문자열 인덱스 5부터의 정보만을 가져온다. val monthText = monthTable.select(MONTH_DATE_SELECTOR).first()?.text() - ?: throw IllegalArgumentException("Month text not found in the provided element.") + ?: throw ScheduleParseException("학사 일정 월 정보를 찾을 수 없습니다.") val month = extractMonth(monthText) @@ -48,7 +45,7 @@ class ScheduleParser( private fun extractMonth(monthText: String): Int { return monthText.split(MONTH_SEPARATOR).last().toIntOrNull() - ?: throw IllegalArgumentException("Invalid month format: $monthText") + ?: throw ScheduleParseException("학사 일정 월 정보를 숫자로 변경할 수 없습니다.") } /** @@ -61,20 +58,21 @@ class ScheduleParser( * -> ["01.03 (수)", "01.15 (월)"], "정시모집 원서 접수" */ private fun parseSchedule(schedule: Element): Schedule { - val dateText = schedule.select(SCHEDULE_DATE_SELECTOR).text().replace(SPACE_CHAR, EMPTY_CHAR) + val dateText = schedule.select(SCHEDULE_DATE_SELECTOR).text() + .replace(SPACE_CHAR, EMPTY_CHAR) + .replace(DOUBLE_QUQATATION_CHAR, EMPTY_CHAR) val dates = if (dateText.contains(DATE_SEPARATOR)) { - dateText.split(DATE_SEPARATOR).map { it.trim() } + dateText.split(DATE_SEPARATOR) } else { listOf(dateText, dateText) } val content = schedule.select(SCHEDULE_CONTENT_SELECTOR).text() - return Schedule.of(dates.toTypedArray(), content) + return Schedule.of(dates, content) } companion object { - private const val TIME_ZONE = "Asia/Seoul" private const val DMU_SCHEDULE_URL = "https://www.dongyang.ac.kr/dongyang/71/subview.do?year=" private const val YEAR_SCHEDULE_SELECTOR = ".yearSchdulWrap" private const val MONTH_DATE_SELECTOR = "p" @@ -83,6 +81,7 @@ class ScheduleParser( private const val SCHEDULE_DATE_SELECTOR = "dt span" private const val SCHEDULE_CONTENT_SELECTOR = "dd span" private const val DATE_SEPARATOR = "~" + private const val DOUBLE_QUQATATION_CHAR = "\"" private const val EMPTY_CHAR = "" private const val SPACE_CHAR = " " } diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/ScheduleParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/ScheduleParserTest.kt index 0059004..4847853 100644 --- a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/ScheduleParserTest.kt +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/ScheduleParserTest.kt @@ -1,8 +1,16 @@ package com.dmforu.crawling.parser +import com.dmforu.crawling.exception.ScheduleParseException import com.dmforu.crawling.loader.HtmlLoader +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.jsoup.Jsoup import org.jsoup.nodes.Document +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.ArgumentMatchers.anyString +import org.mockito.BDDMockito.given import org.mockito.InjectMocks import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension @@ -17,91 +25,192 @@ class ScheduleParserTest { private lateinit var scheduleParser: ScheduleParser -// @DisplayName("학사 일정을 크롤링 할 수 있다.") -// @Test -// fun parse() { -// // given -// // todo 외부로 옮겨야하나? -// val currentYear = LocalDate.now(ZoneId.of("Asia/Seoul")).year -// -// val mockDocument1 = mock(Document::class.java) -// val mockDocument2 = mock(Document::class.java) -// val mockDocument3 = mock(Document::class.java) -// -// // Mocking year and month tables -// val yearTable1 = mock(Element::class.java) -// val monthTable1 = mock(Element::class.java) -// -// val yearTable2 = mock(Element::class.java) -// val monthTable2 = mock(Element::class.java) -// -// val yearTable3 = mock(Element::class.java) -// val monthTable3 = mock(Element::class.java) -// -// // Create elements for the first mock document -// val yearElements1 = Elements(yearTable1) -// val monthElements1 = Elements(monthTable1) -// val yearElements2 = Elements(yearTable2) -// val monthElements2 = Elements(monthTable2) -// val yearElements3 = Elements(yearTable3) -// val monthElements3 = Elements(monthTable3) -// -// // Setting up different return values for different calls -// given(webPageLoader.getHTML(anyString())) -// .willReturn(mockDocument1) // 첫 번째 호출 -// .willReturn(mockDocument2) // 두 번째 호출 -// .willReturn(mockDocument3) // 세 번째 호출 -// -// // Setting up the behavior for the first document -// given(mockDocument1.select(anyString())).willReturn(yearElements1) -// given(yearTable1.select(anyString())).willReturn(monthElements1) -// val test = Elements(mock(Element::class.java)) -// given(monthTable1.select(anyString())).willReturn(test) -// given(test.first().text()).willReturn("2023.01") -// -// // Setting up the behavior for the second document -// given(mockDocument2.select(anyString())).willReturn(yearElements2) -// given(yearTable2.select(anyString())).willReturn(monthElements2) -// given(monthTable2.select(anyString())).willReturn(test) -// given(test.first().text()).willReturn("2023.02") -// -// // Setting up the behavior for the third document -// given(mockDocument3.select(anyString())).willReturn(yearElements3) -// given(yearTable3.select(anyString())).willReturn(monthElements3) -// given(monthTable3.select(anyString())).willReturn(test) -// given(test.first().text()).willReturn("2023.03") -// -// // Execute -// val result = scheduleParser.parse() -// -// // Verify the result -// assertEquals(3, result.size) -// } - - - // - // val test1 = Elements(mock(Element::class.java)) - // - // // Set up month text for the first month table - // given(monthTable1.select("p")).willReturn(test1) - // - // given(test1.text()).willReturn("2024.1") - // - // // Create elements for the second mock document - - // - // val test2 = Elements(mock(Element::class.java)) - // // Set up month text for the second month table - // given(monthTable2.select("p")).willReturn(test2) - // - // given(test2.text()).willReturn("2024.2") - // - // // Create elements for the third mock document - - // - // val test3 = Elements(mock(Element::class.java)) - // // Set up month text for the third month table - // given(monthTable3.select("p")).willReturn(test3) - // - // given(test3.text()).willReturn("2024.3") // 여기도 마찬가지. + @DisplayName("학사 일정을 크롤링 할 수 있다.") + @Test + fun parse() { + // given + val year = 2024 + + val html1 = createHtml(year - 1) + val html2 = createHtml(year) + val html3 = createHtml(year + 1) + + val document1 = Jsoup.parse(html1) + val document2 = Jsoup.parse(html2) + val document3 = Jsoup.parse(html3) + + given(htmlLoader.get(anyString())) + .willReturn(document1) + .willReturn(document2) + .willReturn(document3) + + // when + val result = scheduleParser.parse(year) + + // then + assertThat(result).hasSize(3) + + val parsedYear = result[1] + assertThat(parsedYear.year).isEqualTo(year) + assertThat(parsedYear.yearSchedule).hasSize(1) + + val month = parsedYear.yearSchedule[0] + assertThat(month.month).isEqualTo(1) + assertThat(month.monthSchedule).hasSize(2) + + val firstSchedule = month.monthSchedule[0] + assertThat(firstSchedule.dates).isEqualTo(listOf("01.01(월)", "01.01(월)")) + assertThat(firstSchedule.content).isEqualTo("신정") + + val secondSchedule = month.monthSchedule[1] + assertThat(secondSchedule.dates).isEqualTo(listOf("01.03(수)", "01.15(월)")) + assertThat(secondSchedule.content).isEqualTo("정시모집 원서 접수") + } + + @DisplayName("월 정보가 누락된 경우, ScheduleParserException 예외가 발생한다.") + @Test + fun parseWhenMonthEmpty() { + // given + val year = 2024 + + val html1 = createInvalidHtmlWhenEmptyMonth(year - 1) + val html2 = createInvalidHtmlWhenEmptyMonth(year) + val html3 = createInvalidHtmlWhenEmptyMonth(year + 1) + + val document1 = Jsoup.parse(html1) + val document2 = Jsoup.parse(html2) + val document3 = Jsoup.parse(html3) + + given(htmlLoader.get(anyString())) + .willReturn(document1) + .willReturn(document2) + .willReturn(document3) + + // when // then + assertThatThrownBy { scheduleParser.parse(year) } + .isInstanceOf(ScheduleParseException::class.java) + .hasMessage("학사 일정 월 정보를 찾을 수 없습니다.") + + } + + @DisplayName("월 정보가 숫자가 아닌 경우, ScheduleParseException 예외가 발생한다.") + @Test + fun parseWhenMonthIsNotInt() { + // given + val year = 2024 + + val html1 = createInvalidHtmlWhenMonthIsNotInt(year - 1) + val html2 = createInvalidHtmlWhenMonthIsNotInt(year) + val html3 = createInvalidHtmlWhenMonthIsNotInt(year + 1) + + val document1 = Jsoup.parse(html1) + val document2 = Jsoup.parse(html2) + val document3 = Jsoup.parse(html3) + + given(htmlLoader.get(anyString())) + .willReturn(document1) + .willReturn(document2) + .willReturn(document3) + + // when // then + assertThatThrownBy { scheduleParser.parse(year) } + .isInstanceOf(ScheduleParseException::class.java) + .hasMessage("학사 일정 월 정보를 숫자로 변경할 수 없습니다.") + } + + private fun createHtml(year: Int) = """ +
+
+ +

2024.01

+
+
+
    +
  • +
    +
    + " 01.01 (월) " +
    +
    + 신정 +
    +
    +
  • +
  • +
    +
    + " 01.03 (수) ~ 01.15 (월) " +
    +
    + 정시모집 원서 접수 +
    +
    +
  • +
+
+
+ """.trimIndent() + + private fun createInvalidHtmlWhenEmptyMonth(year: Int) = """ +
+
+
    +
  • +
    +
    + " 01.01 (월) " +
    +
    + 신정 +
    +
    +
  • +
  • +
    +
    + " 01.03 (수) ~ 01.15 (월) " +
    +
    + 정시모집 원서 접수 +
    +
    +
  • +
+
+
+ """.trimIndent() + + private fun createInvalidHtmlWhenMonthIsNotInt(year: Int) = """ +
+
+ +

2024.as

+ +
+
+
    +
  • +
    +
    + " 01.01 (월) " +
    +
    + 신정 +
    +
    +
  • +
  • +
    +
    + " 01.03 (수) ~ 01.15 (월) " +
    +
    + 정시모집 원서 접수 +
    +
    +
  • +
+
+
+ """.trimIndent() } \ No newline at end of file From 19d9c3d20f2f48a9f16dc0770166292f19b3bdfc Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 25 Oct 2024 21:52:43 +0900 Subject: [PATCH 143/223] =?UTF-8?q?fix:=20parser=EC=9D=98=20=EB=82=A0?= =?UTF-8?q?=EC=A7=9C=20=EA=B0=92=EC=9D=84=20=EC=99=B8=EB=B6=80=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=ED=95=A8=EC=97=90=20=EB=94=B0=EB=A5=B8=20Ser?= =?UTF-8?q?vice=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scheduler/crawling/ScheduleCrawlingService.kt | 5 +++-- .../kotlin/com/dmforu/domain/schedule/Schedule.kt | 13 ++----------- .../dmforu/domain/schedule/ScheduleReaderTest.kt | 2 +- .../com/dmforu/domain/schedule/ScheduleTest.kt | 5 ++--- .../dmforu/domain/schedule/ScheduleWriterTest.kt | 2 +- 5 files changed, 9 insertions(+), 18 deletions(-) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt index ace78cc..de1e45d 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt @@ -3,13 +3,14 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.parser.ScheduleParser import com.dmforu.domain.schedule.ScheduleWriter import org.springframework.stereotype.Service +import java.time.LocalDate @Service class ScheduleCrawlingService( private val scheduleParser: ScheduleParser, - private val scheduleWriter: ScheduleWriter + private val scheduleWriter: ScheduleWriter, ) { fun overwriteToRedis() { - scheduleWriter.overwrite(scheduleParser.parse()) + scheduleWriter.overwrite(scheduleParser.parse(LocalDate.now().year)) } } \ No newline at end of file diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt index 4bdff2a..e990654 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt @@ -1,13 +1,11 @@ package com.dmforu.domain.schedule class Schedule private constructor( - dateArray: Array, + val dates: List, val content: String, ) { - val date: String = dateConverter(dateArray) - companion object { - fun of(dateArray: Array, content: String): Schedule { + fun of(dateArray: List, content: String): Schedule { return Schedule(dateArray, content) } } @@ -34,11 +32,4 @@ class Schedule private constructor( } } - private fun dateConverter(dateArray: Array): String { - return dateArray.joinToString( - prefix = "[", - separator = ", ", - postfix = "]" - ) - } } \ No newline at end of file diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleReaderTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleReaderTest.kt index c08e370..a9c4f56 100644 --- a/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleReaderTest.kt +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleReaderTest.kt @@ -26,7 +26,7 @@ class ScheduleReaderTest { @Test fun read() { // given - val date = arrayOf("01.03 (수)", "01.05 (목)") + val date = listOf("01.03 (수)", "01.05 (목)") val expectedDate = "[01.03 (수), 01.05 (목)]" val content = "정시모집 원서 접수" val month = 1 diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleTest.kt index a243c74..e555dce 100644 --- a/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleTest.kt +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleTest.kt @@ -11,8 +11,7 @@ class ScheduleTest { @Test fun of() { // given - val date = arrayOf("01.03 (수)", "01.05 (목)") - val expectedDate = "[01.03 (수), 01.05 (목)]" + val date = listOf("01.03 (수)", "01.05 (목)") val content = "정시모집 원서 접수" val month = 1 val year = 2024 @@ -26,7 +25,7 @@ class ScheduleTest { // then assertThat(schedules[0].year).isEqualTo(year) assertThat(schedules[0].yearSchedule[0].month).isEqualTo(month) - assertThat(schedules[0].yearSchedule[0].monthSchedule[0].date).isEqualTo(expectedDate) + assertThat(schedules[0].yearSchedule[0].monthSchedule[0].dates).isEqualTo(date) assertThat(schedules[0].yearSchedule[0].monthSchedule[0].content).isEqualTo(content) } diff --git a/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleWriterTest.kt b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleWriterTest.kt index 97e8b20..b1332d2 100644 --- a/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleWriterTest.kt +++ b/dmforu-domain/src/test/kotlin/com/dmforu/domain/schedule/ScheduleWriterTest.kt @@ -21,7 +21,7 @@ class ScheduleWriterTest { @Test fun write() { // given - val date = arrayOf("01.03 (수)", "01.05 (목)") + val date = listOf("01.03 (수)", "01.05 (목)") val content = "정시모집 원서 접수" val schedule = Schedule.of(date, content) val scheduleMonth = Schedule.Month.of(1, listOf(schedule)) From c4623d1dc212942775a470044b342d810671abc3 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 27 Oct 2024 00:05:55 +0900 Subject: [PATCH 144/223] =?UTF-8?q?refactor:=20=EA=B5=AC=EB=B2=84=EC=A0=84?= =?UTF-8?q?=20API=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/old/OldDietController.kt | 24 ++++++++ .../api/controller/old/OldNoticeController.kt | 60 +++++++++++++++++++ .../controller/old/OldScheduleController.kt | 25 ++++++++ .../{v1 => old}/response/LegacySchedule.kt | 16 ++--- .../api/controller/v1/DietController.kt | 11 +--- .../api/controller/v1/NoticeController.kt | 51 ++-------------- .../api/controller/v1/ScheduleController.kt | 13 +--- .../api/controller/v1/SubscribeController.kt | 6 +- .../v1/request/RegisterSubscribeRequest.kt | 20 +++++-- .../UpdateSubscribeDepartmentRequest.kt | 7 ++- .../request/UpdateSubscribeKeywordsRequest.kt | 4 ++ .../request/UpdateSubscribeStatusRequest.kt | 8 ++- 12 files changed, 154 insertions(+), 91 deletions(-) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldDietController.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldNoticeController.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldScheduleController.kt rename dmforu-api/src/main/kotlin/com/dmforu/api/controller/{v1 => old}/response/LegacySchedule.kt (78%) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldDietController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldDietController.kt new file mode 100644 index 0000000..a0be9f6 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldDietController.kt @@ -0,0 +1,24 @@ +package com.dmforu.api.controller.old + +import com.dmforu.domain.diet.Diet +import com.dmforu.domain.diet.DietReader +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController + +@Tag(name = "[구버전] 식단") +@RestController +class OldDietController( + private val dietReader: DietReader, +) { + @Operation( + summary = "[구버전] 식단표 API", + description = "금주의 식단을 출력한다.
식단표는 매주 일요일에 갱신된다.
만약, 공휴일인 경우는 빈 리스트를 출력한다." + ) + @GetMapping("/api/v1/dmu/cafeteria") + fun readDietOld(): ResponseEntity> { + return ResponseEntity.ok().body(dietReader.read()) + } +} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldNoticeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldNoticeController.kt new file mode 100644 index 0000000..dc190a0 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldNoticeController.kt @@ -0,0 +1,60 @@ +package com.dmforu.api.controller.old + +import com.dmforu.api.controller.v1.response.NoticeResponse +import com.dmforu.domain.notice.NoticeReader +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@Tag(name = "[구버전] 공지") +@RestController +class OldNoticeController( + private val noticeReader: NoticeReader, +) { + @Operation( + summary = "[구버전] 대학 공지 API", + description = "대학 공지를 출력한다.
Page, Size의 default 값은 1, 20이다." + ) + @GetMapping("/api/v1/dmu/notice/universityNotice") + fun getOldUniversityNotice( + @RequestParam(name = "page", defaultValue = "1") page: Int, + @RequestParam(name = "size", defaultValue = "20") size: Int, + ): ResponseEntity> { + val universityNotices = noticeReader.readUniversityNotice(page, size).map { NoticeResponse.form(it) } + return ResponseEntity.ok().body(universityNotices) + } + + @Operation( + summary = "[구버전] 학과 공지 API", + description = "해당하는 학과의 공지를 출력한다.
Page, Size의 default 값은 1, 20이다." + ) + @GetMapping("/api/v1/dmu/departmentNotice/{department}") + fun getOldDepartmentNotice( + @PathVariable(name = "department") department: String, + @RequestParam(name = "page", defaultValue = "1") page: Int, + @RequestParam(name = "size", defaultValue = "20") size: Int, + ): ResponseEntity> { + val departmentNotices = + noticeReader.readDepartmentNotice(department, page, size).map { NoticeResponse.form(it) } + return ResponseEntity.ok().body(departmentNotices) + } + + @Operation( + summary = "[구버전] 공지 검색 API", + description = "해당하는 학과와 대학 공지에서 해당하는 공지를 출력한다.
Page, Size의 default 값은 1, 20이다." + ) + @GetMapping("/api/v1/dmu/notice/{searchWord}") + fun getOldNoticeByKeyword( + @PathVariable(name = "searchWord") searchWord: String, + @RequestParam(name = "department") department: String, + @RequestParam(name = "page", defaultValue = "1") page: Int, + @RequestParam(name = "size", defaultValue = "20") size: Int, + ): ResponseEntity> { + val notices = noticeReader.searchNotice(searchWord, department, page, size).map { NoticeResponse.form(it) } + return ResponseEntity.ok().body(notices) + } +} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldScheduleController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldScheduleController.kt new file mode 100644 index 0000000..af88bf7 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldScheduleController.kt @@ -0,0 +1,25 @@ +package com.dmforu.api.controller.old + +import com.dmforu.api.controller.old.response.LegacySchedule +import com.dmforu.domain.schedule.ScheduleReader +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController + +@Tag(name = "[구버전] 학사일정") +@RestController +class OldScheduleController( + private val scheduleReader: ScheduleReader, +) { + @GetMapping("/api/v1/dmu/schedule") + @Operation( + summary = "[구버전] 학사일정 API", + description = "현재년도를 기준으로 작년부터 내년 2월까지의 학사일정을 출력한다." + ) + fun readScheduleOld(): ResponseEntity> { + val schedules = LegacySchedule.fromScheduleYears(scheduleReader.read()) + return ResponseEntity.ok().body(schedules) + } +} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/response/LegacySchedule.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/response/LegacySchedule.kt similarity index 78% rename from dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/response/LegacySchedule.kt rename to dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/response/LegacySchedule.kt index cad44d9..9842328 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/response/LegacySchedule.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/response/LegacySchedule.kt @@ -1,20 +1,12 @@ -package com.dmforu.api.controller.v1.response +package com.dmforu.api.controller.old.response import com.dmforu.domain.schedule.Schedule data class LegacySchedule( - val date: String, + val date: List, val content: String ) { - private constructor() : this("", "") - - private constructor(dateArray: Array, content: String) : this( - dateArray.joinToString( - prefix = "[", - separator = ", ", - postfix = "]" - ), content - ) + private constructor() : this(emptyList(), "") data class MonthSchedule( val month: Int, @@ -51,7 +43,7 @@ data class LegacySchedule( private fun Schedule.toLegacySchedule(): LegacySchedule { return LegacySchedule( - date = this.date, + date = this.dates, content = this.content ) } diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt index d76cf09..02fe32c 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt @@ -11,17 +11,8 @@ import org.springframework.web.bind.annotation.RestController @Tag(name = "식단") @RestController class DietController( - private val dietReader: DietReader + private val dietReader: DietReader, ) { - @Operation( - summary = "[구버전] 식단표 API", - description = "금주의 식단을 출력한다.
식단표는 매주 일요일에 갱신된다.
만약, 공휴일인 경우는 빈 리스트를 출력한다." - ) - @GetMapping("/api/v1/dmu/cafeteria") - fun readDietOld(): ResponseEntity> { - return ResponseEntity.ok().body(dietReader.read()) - } - @Operation( summary = "식단표 API", description = "금주의 식단을 출력한다.
식단표는 매주 일요일에 갱신된다.
만약, 공휴일인 경우는 빈 리스트를 출력한다." diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt index d802a77..7adc4ee 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt @@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.RestController @Tag(name = "공지") @RestController class NoticeController( - private val noticeReader: NoticeReader + private val noticeReader: NoticeReader, ) { @Operation( summary = "대학 공지 API", @@ -22,7 +22,7 @@ class NoticeController( @GetMapping("/api/v1/notice/university") fun getUniversityNotice( @RequestParam(name = "page", defaultValue = "1") page: Int, - @RequestParam(name = "size", defaultValue = "20") size: Int + @RequestParam(name = "size", defaultValue = "20") size: Int, ): ResponseEntity> { val universityNotices = noticeReader.readUniversityNotice(page, size).map { NoticeResponse.form(it) } return ResponseEntity.ok().body(universityNotices) @@ -36,7 +36,7 @@ class NoticeController( fun getDepartmentNotice( @RequestParam(name = "department") department: String, @RequestParam(name = "page", defaultValue = "1") page: Int, - @RequestParam(name = "size", defaultValue = "20") size: Int + @RequestParam(name = "size", defaultValue = "20") size: Int, ): ResponseEntity> { val departmentNotices = noticeReader.readDepartmentNotice(department, page, size).map { NoticeResponse.form(it) } @@ -52,50 +52,7 @@ class NoticeController( @PathVariable(name = "searchWord") searchWord: String, @RequestParam(name = "department") department: String, @RequestParam(name = "page", defaultValue = "1") page: Int, - @RequestParam(name = "size", defaultValue = "20") size: Int - ): ResponseEntity> { - val notices = noticeReader.searchNotice(searchWord, department, page, size).map { NoticeResponse.form(it) } - return ResponseEntity.ok().body(notices) - } - - @Operation( - summary = "[구버전] 대학 공지 API", - description = "대학 공지를 출력한다.
Page, Size의 default 값은 1, 20이다." - ) - @GetMapping("/api/v1/dmu/notice/universityNotice") - fun getOldUniversityNotice( - @RequestParam(name = "page", defaultValue = "1") page: Int, - @RequestParam(name = "size", defaultValue = "20") size: Int - ): ResponseEntity> { - val universityNotices = noticeReader.readUniversityNotice(page, size).map { NoticeResponse.form(it) } - return ResponseEntity.ok().body(universityNotices) - } - - @Operation( - summary = "[구버전] 학과 공지 API", - description = "해당하는 학과의 공지를 출력한다.
Page, Size의 default 값은 1, 20이다." - ) - @GetMapping("/api/v1/dmu/departmentNotice/{department}") - fun getOldDepartmentNotice( - @PathVariable(name = "department") department: String, - @RequestParam(name = "page", defaultValue = "1") page: Int, - @RequestParam(name = "size", defaultValue = "20") size: Int - ): ResponseEntity> { - val departmentNotices = - noticeReader.readDepartmentNotice(department, page, size).map { NoticeResponse.form(it) } - return ResponseEntity.ok().body(departmentNotices) - } - - @Operation( - summary = "[구버전] 공지 검색 API", - description = "해당하는 학과와 대학 공지에서 해당하는 공지를 출력한다.
Page, Size의 default 값은 1, 20이다." - ) - @GetMapping("/api/v1/dmu/notice/{searchWord}") - fun getOldNoticeByKeyword( - @PathVariable(name = "searchWord") searchWord: String, - @RequestParam(name = "department") department: String, - @RequestParam(name = "page", defaultValue = "1") page: Int, - @RequestParam(name = "size", defaultValue = "20") size: Int + @RequestParam(name = "size", defaultValue = "20") size: Int, ): ResponseEntity> { val notices = noticeReader.searchNotice(searchWord, department, page, size).map { NoticeResponse.form(it) } return ResponseEntity.ok().body(notices) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt index ad4b90a..33b001d 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt @@ -1,6 +1,5 @@ package com.dmforu.api.controller.v1 -import com.dmforu.api.controller.v1.response.LegacySchedule import com.dmforu.domain.schedule.Schedule import com.dmforu.domain.schedule.ScheduleReader import io.swagger.v3.oas.annotations.Operation @@ -12,18 +11,8 @@ import org.springframework.web.bind.annotation.RestController @Tag(name = "학사일정") @RestController class ScheduleController( - private val scheduleReader: ScheduleReader + private val scheduleReader: ScheduleReader, ) { - @GetMapping("/api/v1/dmu/schedule") - @Operation( - summary = "[구버전] 학사일정 API", - description = "현재년도를 기준으로 작년부터 내년 2월까지의 학사일정을 출력한다." - ) - fun readScheduleOld(): ResponseEntity> { - val schedules = LegacySchedule.fromScheduleYears(scheduleReader.read()) - return ResponseEntity.ok().body(schedules) - } - @GetMapping("/api/v1/schedule") @Operation( summary = "학사일정 API", diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt index e256508..814a1a0 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt @@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.RestController @RestController class SubscribeController( private val subscribeWriter: SubscribeWriter, - private val subscribeUpdater: SubscribeUpdater + private val subscribeUpdater: SubscribeUpdater, ) { @Operation(summary = "최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") @PostMapping("/api/v1/subscribe/registration") @@ -35,7 +35,7 @@ class SubscribeController( @Operation(summary = "키워드 알림 상태 변경 API", description = "키워드 알림 상태를 변경한다.") @PatchMapping("/api/v1/subscribe/keyword/status") fun updateSubscribeKeywordStatus(@RequestBody request: UpdateSubscribeStatusRequest): ResponseEntity { - subscribeUpdater.updateKeywordSubscribeStatus(request.token, request.isSubscribed) + subscribeUpdater.updateKeywordSubscribeStatus(request.token, request.subscribeStatus) return ResponseEntity.status(HttpStatus.NO_CONTENT).build() } @@ -49,7 +49,7 @@ class SubscribeController( @Operation(summary = "학과 알림 상태 변경 API", description = "학과 알림 상태를 변경한다.") @PatchMapping("/api/v1/subscribe/department/status") fun updateSubscribeDepartmentStatus(@RequestBody request: UpdateSubscribeStatusRequest): ResponseEntity { - subscribeUpdater.updateDepartmentSubscribeStatus(token = request.token, request.isSubscribed) + subscribeUpdater.updateDepartmentSubscribeStatus(token = request.token, request.subscribeStatus) return ResponseEntity.status(HttpStatus.NO_CONTENT).build() } } diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt index 8727d3d..6b65935 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt @@ -1,21 +1,31 @@ package com.dmforu.api.controller.v1.request import com.dmforu.domain.subscribe.Subscribe +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.NotNull -data class RegisterSubscribeRequest ( +data class RegisterSubscribeRequest( + @NotBlank(message = "토큰은 필수입니다.") val token: String, + + @NotBlank(message = "학과는 필수입니다.") val department: String, + val keywords: List, - val isDepartmentSubscribed: Boolean, - val areKeywordSubscribed: Boolean, + + @NotNull(message = "학과 구독 상태는 필수입니다.") + val departmentSubscribeStatus: Boolean, + + @NotNull(message = "키워드 구독 상태는 필수입니다.") + val keywordSubscribeStatus: Boolean, ) { fun toSubscribe(): Subscribe { return Subscribe.of( token = token, department = department, keywords = keywords, - isDepartmentSubscribed = isDepartmentSubscribed, - isKeywordSubscribed = areKeywordSubscribed + isDepartmentSubscribed = departmentSubscribeStatus, + isKeywordSubscribed = keywordSubscribeStatus ) } } diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeDepartmentRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeDepartmentRequest.kt index 0f35df2..38ec79c 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeDepartmentRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeDepartmentRequest.kt @@ -1,6 +1,11 @@ package com.dmforu.api.controller.v1.request -data class UpdateSubscribeDepartmentRequest ( +import jakarta.validation.constraints.NotBlank + +data class UpdateSubscribeDepartmentRequest( + @NotBlank(message = "토큰은 필수입니다.") val token: String, + + @NotBlank(message = "학과는 필수입니다.") val department: String ) \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeKeywordsRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeKeywordsRequest.kt index 5f95a5c..db72e95 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeKeywordsRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeKeywordsRequest.kt @@ -1,6 +1,10 @@ package com.dmforu.api.controller.v1.request +import jakarta.validation.constraints.NotBlank + data class UpdateSubscribeKeywordsRequest( + @NotBlank(message = "토큰은 필수입니다.") val token: String, + val keywords: List ) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeStatusRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeStatusRequest.kt index a1cf615..8265909 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeStatusRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeStatusRequest.kt @@ -1,6 +1,12 @@ package com.dmforu.api.controller.v1.request +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.NotNull + data class UpdateSubscribeStatusRequest ( + @NotBlank(message = "토큰은 필수입니다.") val token: String, - val isSubscribed: Boolean + + @NotNull(message = "구독 상태는 필수입니다.") + val subscribeStatus: Boolean ) \ No newline at end of file From e8d6f3c97084a6c04042e7d3437d9c377ad4d822 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 27 Oct 2024 17:20:08 +0900 Subject: [PATCH 145/223] =?UTF-8?q?refactor:=20ResponseEntity=EC=97=90?= =?UTF-8?q?=EC=84=9C=20Custom=20Api=20Response=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=B0=8F=20Custom=20Exception=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/ApiControllerAdvice.kt | 39 ++++++++++++++++++ .../api/controller/v1/DietController.kt | 6 +-- .../api/controller/v1/NoticeController.kt | 14 +++---- .../api/controller/v1/ScheduleController.kt | 6 +-- .../api/controller/v1/SubscribeController.kt | 40 +++++++++++-------- .../dmforu/api/support/error/AppException.kt | 6 +++ .../com/dmforu/api/support/error/ErrorCode.kt | 6 +++ .../dmforu/api/support/error/ErrorMessage.kt | 13 ++++++ .../com/dmforu/api/support/error/ErrorType.kt | 9 +++++ .../api/support/response/ApiResponse.kt | 28 +++++++++++++ .../dmforu/api/support/response/ResultType.kt | 7 ++++ 11 files changed, 144 insertions(+), 30 deletions(-) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/support/error/AppException.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorCode.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorMessage.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorType.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ApiResponse.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ResultType.kt diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt new file mode 100644 index 0000000..045f717 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt @@ -0,0 +1,39 @@ +package com.dmforu.api.controller + +import com.dmforu.api.support.error.AppException +import com.dmforu.api.support.error.ErrorType +import com.dmforu.api.support.response.ApiResponse +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.springframework.boot.logging.LogLevel +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.RestControllerAdvice +import java.net.BindException + +@RestControllerAdvice +class ApiControllerAdvice { + private val log: Logger = LoggerFactory.getLogger(javaClass) + + @ExceptionHandler(AppException::class) + fun handleAppException(e: AppException): ResponseEntity> { + when (e.errorType.logLevel) { + LogLevel.ERROR -> log.error("AppException : {}", e.message, e) + LogLevel.WARN -> log.warn("AppException : {}", e.message, e) + else -> log.info("AppException : {}", e.message, e) + } + return ResponseEntity(ApiResponse.error(e.errorType, e.data), e.errorType.status) + } + + @ExceptionHandler(BindException::class) + fun handleRequestException(e: BindException): ResponseEntity> { + log.error("BindException : {}", e.message, e) + return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) + } + + @ExceptionHandler(Exception::class) + fun handleException(e: Exception): ResponseEntity> { + log.error("Exception : {}", e.message, e) + return ResponseEntity(ApiResponse.error(ErrorType.SERVER_ERROR), ErrorType.SERVER_ERROR.status) + } +} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt index 02fe32c..ab1115a 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt @@ -1,10 +1,10 @@ package com.dmforu.api.controller.v1 +import com.dmforu.api.support.response.ApiResponse import com.dmforu.domain.diet.Diet import com.dmforu.domain.diet.DietReader import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag -import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RestController @@ -18,7 +18,7 @@ class DietController( description = "금주의 식단을 출력한다.
식단표는 매주 일요일에 갱신된다.
만약, 공휴일인 경우는 빈 리스트를 출력한다." ) @GetMapping("/api/v1/cafeteria") - fun readDiet(): ResponseEntity> { - return ResponseEntity.ok().body(dietReader.read()) + fun readDiet(): ApiResponse> { + return ApiResponse.success(dietReader.read()) } } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt index 7adc4ee..6e9ae01 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt @@ -1,10 +1,10 @@ package com.dmforu.api.controller.v1 import com.dmforu.api.controller.v1.response.NoticeResponse +import com.dmforu.api.support.response.ApiResponse import com.dmforu.domain.notice.NoticeReader import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag -import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestParam @@ -23,9 +23,9 @@ class NoticeController( fun getUniversityNotice( @RequestParam(name = "page", defaultValue = "1") page: Int, @RequestParam(name = "size", defaultValue = "20") size: Int, - ): ResponseEntity> { + ): ApiResponse> { val universityNotices = noticeReader.readUniversityNotice(page, size).map { NoticeResponse.form(it) } - return ResponseEntity.ok().body(universityNotices) + return ApiResponse.success(universityNotices) } @Operation( @@ -37,10 +37,10 @@ class NoticeController( @RequestParam(name = "department") department: String, @RequestParam(name = "page", defaultValue = "1") page: Int, @RequestParam(name = "size", defaultValue = "20") size: Int, - ): ResponseEntity> { + ): ApiResponse> { val departmentNotices = noticeReader.readDepartmentNotice(department, page, size).map { NoticeResponse.form(it) } - return ResponseEntity.ok().body(departmentNotices) + return ApiResponse.success(departmentNotices) } @Operation( @@ -53,8 +53,8 @@ class NoticeController( @RequestParam(name = "department") department: String, @RequestParam(name = "page", defaultValue = "1") page: Int, @RequestParam(name = "size", defaultValue = "20") size: Int, - ): ResponseEntity> { + ): ApiResponse> { val notices = noticeReader.searchNotice(searchWord, department, page, size).map { NoticeResponse.form(it) } - return ResponseEntity.ok().body(notices) + return ApiResponse.success(notices) } } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt index 33b001d..e222aab 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt @@ -1,10 +1,10 @@ package com.dmforu.api.controller.v1 +import com.dmforu.api.support.response.ApiResponse import com.dmforu.domain.schedule.Schedule import com.dmforu.domain.schedule.ScheduleReader import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag -import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RestController @@ -18,7 +18,7 @@ class ScheduleController( summary = "학사일정 API", description = "현재년도를 기준으로 작년부터 내년 2월까지의 학사일정을 출력한다." ) - fun raedSchedule(): ResponseEntity> { - return ResponseEntity.ok().body(scheduleReader.read()) + fun raedSchedule(): ApiResponse> { + return ApiResponse.success(scheduleReader.read()) } } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt index 814a1a0..8059d21 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt @@ -1,12 +1,12 @@ package com.dmforu.api.controller.v1 import com.dmforu.api.controller.v1.request.* +import com.dmforu.api.support.response.ApiResponse import com.dmforu.domain.subscribe.SubscribeUpdater import com.dmforu.domain.subscribe.SubscribeWriter import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag -import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity +import jakarta.validation.Valid import org.springframework.web.bind.annotation.PatchMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody @@ -20,37 +20,43 @@ class SubscribeController( ) { @Operation(summary = "최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") @PostMapping("/api/v1/subscribe/registration") - fun tokenSubscribe(@RequestBody registerSubscribeRequest: RegisterSubscribeRequest): ResponseEntity { - subscribeWriter.write(registerSubscribeRequest.toSubscribe()) - return ResponseEntity.status(HttpStatus.CREATED).build() + fun tokenSubscribe(@Valid @RequestBody request: RegisterSubscribeRequest): ApiResponse { + subscribeWriter.write(request.toSubscribe()) + return ApiResponse.create() } @Operation(summary = "키워드 수정 API", description = "알림 키워드를 수정한다.") @PatchMapping("/api/v1/subscribe/keywords") - fun updateSubscribeKeywords(@RequestBody request: UpdateSubscribeKeywordsRequest): ResponseEntity { - subscribeUpdater.updateKeywords(request.token, request.keywords) - return ResponseEntity.status(HttpStatus.NO_CONTENT).build() + fun updateSubscribeKeywords(@Valid @RequestBody request: UpdateSubscribeKeywordsRequest): ApiResponse { + subscribeUpdater.updateKeywords(token = request.token, keywords = request.keywords) + return ApiResponse.success() } @Operation(summary = "키워드 알림 상태 변경 API", description = "키워드 알림 상태를 변경한다.") @PatchMapping("/api/v1/subscribe/keyword/status") - fun updateSubscribeKeywordStatus(@RequestBody request: UpdateSubscribeStatusRequest): ResponseEntity { - subscribeUpdater.updateKeywordSubscribeStatus(request.token, request.subscribeStatus) - return ResponseEntity.status(HttpStatus.NO_CONTENT).build() + fun updateSubscribeKeywordStatus(@Valid @RequestBody request: UpdateSubscribeStatusRequest): ApiResponse { + subscribeUpdater.updateKeywordSubscribeStatus( + token = request.token, + keywordSubscribeStatus = request.subscribeStatus + ) + return ApiResponse.success() } @Operation(summary = "학과 수정 API", description = "학과 정보를 수정한다.") @PatchMapping("/api/v1/subscribe/department") - fun updateSubscribeDepartment(@RequestBody request: UpdateSubscribeDepartmentRequest): ResponseEntity { - subscribeUpdater.updateDepartment(request.token, request.department) - return ResponseEntity.status(HttpStatus.NO_CONTENT).build() + fun updateSubscribeDepartment(@Valid @RequestBody request: UpdateSubscribeDepartmentRequest): ApiResponse { + subscribeUpdater.updateDepartment(token = request.token, department = request.department) + return ApiResponse.success() } @Operation(summary = "학과 알림 상태 변경 API", description = "학과 알림 상태를 변경한다.") @PatchMapping("/api/v1/subscribe/department/status") - fun updateSubscribeDepartmentStatus(@RequestBody request: UpdateSubscribeStatusRequest): ResponseEntity { - subscribeUpdater.updateDepartmentSubscribeStatus(token = request.token, request.subscribeStatus) - return ResponseEntity.status(HttpStatus.NO_CONTENT).build() + fun updateSubscribeDepartmentStatus(@Valid @RequestBody request: UpdateSubscribeStatusRequest): ApiResponse { + subscribeUpdater.updateDepartmentSubscribeStatus( + token = request.token, + departmentSubscribeStatus = request.subscribeStatus + ) + return ApiResponse.success() } } diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/AppException.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/AppException.kt new file mode 100644 index 0000000..c04f0c8 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/AppException.kt @@ -0,0 +1,6 @@ +package com.dmforu.api.support.error + +class AppException( + val errorType: ErrorType, + val data: Any? = null, +) : RuntimeException(errorType.message) \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorCode.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorCode.kt new file mode 100644 index 0000000..e0c06f1 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorCode.kt @@ -0,0 +1,6 @@ +package com.dmforu.api.support.error + +enum class ErrorCode { + E400, + E500, +} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorMessage.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorMessage.kt new file mode 100644 index 0000000..783d96a --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorMessage.kt @@ -0,0 +1,13 @@ +package com.dmforu.api.support.error + +data class ErrorMessage private constructor( + val code: String, + val message: String, + val data: Any? = null, +) { + constructor(errorType: ErrorType, data: Any? = null) : this( + code = errorType.code.name, + message = errorType.message, + data = data, + ) +} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorType.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorType.kt new file mode 100644 index 0000000..70c711f --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorType.kt @@ -0,0 +1,9 @@ +package com.dmforu.api.support.error + +import org.springframework.boot.logging.LogLevel +import org.springframework.http.HttpStatus + +enum class ErrorType(val status: HttpStatus, val code: ErrorCode, val message: String, val logLevel: LogLevel) { + BAD_REQUEST_ERROR(HttpStatus.BAD_REQUEST, ErrorCode.E400, "잘못된 요청을 하였습니다.", LogLevel.WARN), + SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, ErrorCode.E500, "An unexpected error has occurred.", LogLevel.ERROR), +} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ApiResponse.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ApiResponse.kt new file mode 100644 index 0000000..b231570 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ApiResponse.kt @@ -0,0 +1,28 @@ +package com.dmforu.api.support.response + +import com.dmforu.api.support.error.ErrorMessage +import com.dmforu.api.support.error.ErrorType + +data class ApiResponse private constructor( + val result: ResultType, + val data: T? = null, + val error: ErrorMessage? = null, +) { + companion object { + fun success(): ApiResponse { + return ApiResponse(ResultType.SUCCESS, null, null) + } + + fun create(): ApiResponse { + return ApiResponse(ResultType.CREATE, null, null) + } + + fun success(data: S): ApiResponse { + return ApiResponse(ResultType.SUCCESS, data, null) + } + + fun error(error: ErrorType, errorData: Any? = null): ApiResponse { + return ApiResponse(ResultType.ERROR, null, ErrorMessage(error, errorData)) + } + } +} diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ResultType.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ResultType.kt new file mode 100644 index 0000000..8a98ec5 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ResultType.kt @@ -0,0 +1,7 @@ +package com.dmforu.api.support.response + +enum class ResultType { + SUCCESS, + CREATE, + ERROR, +} \ No newline at end of file From 2d07e70028ee18a0dbec60228a03dbabe9676e5b Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 27 Oct 2024 19:33:17 +0900 Subject: [PATCH 146/223] =?UTF-8?q?refactor:=20API=20Reqeust=EC=8B=9C=20?= =?UTF-8?q?=EB=B0=9C=EC=83=9D=ED=95=98=EB=8A=94=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=ED=95=B8=EB=93=A4=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/api/controller/ApiControllerAdvice.kt | 15 ++++++++++++++- .../api/controller/v1/DietControllerTest.kt | 5 +++++ .../api/controller/v1/NoticeControllerTest.kt | 5 +++++ .../api/controller/v1/ScheduleControllerTest.kt | 5 +++++ .../api/controller/v1/SubscribeControllerTest.kt | 5 +++++ 5 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt create mode 100644 dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt create mode 100644 dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt create mode 100644 dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt index 045f717..228ea63 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt @@ -7,8 +7,10 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.boot.logging.LogLevel import org.springframework.http.ResponseEntity +import org.springframework.web.bind.MissingServletRequestParameterException import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice +import org.springframework.web.servlet.resource.NoResourceFoundException import java.net.BindException @RestControllerAdvice @@ -25,8 +27,19 @@ class ApiControllerAdvice { return ResponseEntity(ApiResponse.error(e.errorType, e.data), e.errorType.status) } + @ExceptionHandler(NoResourceFoundException::class) + fun handleNoResourceFoundException(e: NoResourceFoundException): ResponseEntity> { + return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) + } + + @ExceptionHandler(MissingServletRequestParameterException::class) + fun handleRequestParamException(e: MissingServletRequestParameterException): ResponseEntity> { + log.error("RequestParamException : {}", e.message, e) + return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) + } + @ExceptionHandler(BindException::class) - fun handleRequestException(e: BindException): ResponseEntity> { + fun handleRequestBodyException(e: BindException): ResponseEntity> { log.error("BindException : {}", e.message, e) return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) } diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt new file mode 100644 index 0000000..5cc9126 --- /dev/null +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt @@ -0,0 +1,5 @@ +package com.dmforu.api.controller.v1 + +import org.junit.jupiter.api.Assertions.* + +class DietControllerTest \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt new file mode 100644 index 0000000..93d0d89 --- /dev/null +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt @@ -0,0 +1,5 @@ +package com.dmforu.api.controller.v1 + +import org.junit.jupiter.api.Assertions.* + +class NoticeControllerTest \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt new file mode 100644 index 0000000..0f1ab84 --- /dev/null +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt @@ -0,0 +1,5 @@ +package com.dmforu.api.controller.v1 + +import org.junit.jupiter.api.Assertions.* + +class ScheduleControllerTest \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt new file mode 100644 index 0000000..78a8e2b --- /dev/null +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt @@ -0,0 +1,5 @@ +package com.dmforu.api.controller.v1 + +import org.junit.jupiter.api.Assertions.* + +class SubscribeControllerTest \ No newline at end of file From aeb51ac27c6a7c534bc569416704ff80333d1faf Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 28 Oct 2024 16:59:38 +0900 Subject: [PATCH 147/223] =?UTF-8?q?test:=20Subscribe=20Controller=20Init?= =?UTF-8?q?=20Request=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-api/build.gradle.kts | 3 + .../api/controller/ApiControllerAdvice.kt | 7 + .../api/controller/v1/SubscribeController.kt | 2 +- .../v1/request/RegisterSubscribeRequest.kt | 25 +-- .../controller/v1/SubscribeControllerTest.kt | 185 +++++++++++++++++- 5 files changed, 207 insertions(+), 15 deletions(-) diff --git a/dmforu-api/build.gradle.kts b/dmforu-api/build.gradle.kts index b72f29a..59a3a46 100644 --- a/dmforu-api/build.gradle.kts +++ b/dmforu-api/build.gradle.kts @@ -13,5 +13,8 @@ dependencies { runtimeOnly(project(":dmforu-infrastructure:storage:db-redis")) implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-validation") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0") + + testImplementation("org.springframework.boot:spring-boot-starter-validation") } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt index 228ea63..3703ad3 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt @@ -7,6 +7,7 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.boot.logging.LogLevel import org.springframework.http.ResponseEntity +import org.springframework.web.bind.MethodArgumentNotValidException import org.springframework.web.bind.MissingServletRequestParameterException import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice @@ -32,6 +33,12 @@ class ApiControllerAdvice { return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) } + @ExceptionHandler(MethodArgumentNotValidException::class) + fun handleRequestBodyException(e: MethodArgumentNotValidException): ResponseEntity> { + log.error("MethodArgumentNotValidException : {}", e.message, e) + return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR, e.fieldError?.defaultMessage), ErrorType.BAD_REQUEST_ERROR.status) + } + @ExceptionHandler(MissingServletRequestParameterException::class) fun handleRequestParamException(e: MissingServletRequestParameterException): ResponseEntity> { log.error("RequestParamException : {}", e.message, e) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt index 8059d21..870eb9f 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt @@ -20,7 +20,7 @@ class SubscribeController( ) { @Operation(summary = "최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") @PostMapping("/api/v1/subscribe/registration") - fun tokenSubscribe(@Valid @RequestBody request: RegisterSubscribeRequest): ApiResponse { + fun initSubscribe(@Valid @RequestBody request: RegisterSubscribeRequest): ApiResponse { subscribeWriter.write(request.toSubscribe()) return ApiResponse.create() } diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt index 6b65935..40b0328 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/RegisterSubscribeRequest.kt @@ -4,28 +4,29 @@ import com.dmforu.domain.subscribe.Subscribe import jakarta.validation.constraints.NotBlank import jakarta.validation.constraints.NotNull + data class RegisterSubscribeRequest( - @NotBlank(message = "토큰은 필수입니다.") - val token: String, + @field:NotBlank(message = "토큰은 필수입니다.") + val token: String?, - @NotBlank(message = "학과는 필수입니다.") - val department: String, + @field:NotBlank(message = "학과는 필수입니다.") + val department: String?, val keywords: List, - @NotNull(message = "학과 구독 상태는 필수입니다.") - val departmentSubscribeStatus: Boolean, + @field:NotNull(message = "학과 구독 상태는 필수입니다.") + val departmentSubscribeStatus: Boolean?, - @NotNull(message = "키워드 구독 상태는 필수입니다.") - val keywordSubscribeStatus: Boolean, + @field:NotNull(message = "키워드 구독 상태는 필수입니다.") + val keywordSubscribeStatus: Boolean?, ) { fun toSubscribe(): Subscribe { return Subscribe.of( - token = token, - department = department, + token = token!!, + department = department!!, keywords = keywords, - isDepartmentSubscribed = departmentSubscribeStatus, - isKeywordSubscribed = keywordSubscribeStatus + isDepartmentSubscribed = departmentSubscribeStatus!!, + isKeywordSubscribed = keywordSubscribeStatus!! ) } } diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt index 78a8e2b..bbf308c 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt @@ -1,5 +1,186 @@ package com.dmforu.api.controller.v1 -import org.junit.jupiter.api.Assertions.* +import com.dmforu.api.controller.v1.request.RegisterSubscribeRequest +import com.dmforu.api.support.error.ErrorCode +import com.dmforu.api.support.response.ResultType +import com.dmforu.domain.subscribe.SubscribeUpdater +import com.dmforu.domain.subscribe.SubscribeWriter +import com.fasterxml.jackson.databind.ObjectMapper +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.http.MediaType.APPLICATION_JSON +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -class SubscribeControllerTest \ No newline at end of file +@WebMvcTest(SubscribeController::class) +class SubscribeControllerTest { + + @Autowired + private lateinit var mockMvc: MockMvc + + @Autowired + private lateinit var objectMapper: ObjectMapper + + @MockBean + private lateinit var subscribeUpdater: SubscribeUpdater + + @MockBean + private lateinit var subscribeWriter: SubscribeWriter + + @DisplayName("구독을 생성한다.") + @Test + fun initSubscribe() { + // given + val request = RegisterSubscribeRequest( + token = "0001", + department = "컴퓨터소프트웨어공학과", + keywords = listOf("학사"), + departmentSubscribeStatus = true, + keywordSubscribeStatus = true + ) + + // when // then + mockMvc.perform( + post("/api/v1/subscribe/registration") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.CREATE.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error").isEmpty) + } + + @DisplayName("구독을 생성할 때, 토큰은 필수 값이다.") + @Test + fun initSubscribeWithoutToken() { + // given + val request = RegisterSubscribeRequest( + token = "", + department = "컴퓨터소프트웨어공학과", + keywords = listOf("학사"), + departmentSubscribeStatus = true, + keywordSubscribeStatus = true + ) + + // when // then + mockMvc.perform( + post("/api/v1/subscribe/registration") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) + } + + @DisplayName("구독을 생성할 때, 학과는 필수 값이다.") + @Test + fun initSubscribeWithoutDepartment() { + // given + val request = RegisterSubscribeRequest( + token = "0001", + department = "", + keywords = listOf("학사"), + departmentSubscribeStatus = true, + keywordSubscribeStatus = true + ) + + // when // then + mockMvc.perform( + post("/api/v1/subscribe/registration") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("학과는 필수입니다.")) + } + + @DisplayName("구독을 생성할 때, 키워드는 필수 값이 아니다.") + @Test + fun initSubscribeWithoutKeyword() { + // given + val request = RegisterSubscribeRequest( + token = "0001", + department = "컴퓨터소프트웨어공학과", + keywords = listOf(), + departmentSubscribeStatus = true, + keywordSubscribeStatus = true + ) + + // when // then + mockMvc.perform( + post("/api/v1/subscribe/registration") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.CREATE.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error").isEmpty) + } + + @DisplayName("구독을 생성할 때, 학과 구독 상태는 필수 값이다.") + @Test + fun initSubscribeWithoutDepartmentSubscribeStatus() { + // given + val request = RegisterSubscribeRequest( + token = "0001", + department = "컴퓨터소프트웨어공학과", + keywords = listOf(), + departmentSubscribeStatus = null, + keywordSubscribeStatus = true + ) + + // when // then + mockMvc.perform( + post("/api/v1/subscribe/registration") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("학과 구독 상태는 필수입니다.")) + } + + @DisplayName("구독을 생성할 때, 키워드 구독 상태는 필수 값이다.") + @Test + fun initSubscribeWithoutKeywordsSubscribeStatus() { + // given + val request = RegisterSubscribeRequest( + token = "0001", + department = "컴퓨터소프트웨어공학과", + keywords = listOf("학사"), + departmentSubscribeStatus = true, + keywordSubscribeStatus = null + ) + + // when // then + mockMvc.perform( + post("/api/v1/subscribe/registration") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("키워드 구독 상태는 필수입니다.")) + } +} From 17e5e77696dff6f52395d67680f863ab2f54b1b9 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 28 Oct 2024 17:44:19 +0900 Subject: [PATCH 148/223] =?UTF-8?q?test:=20Subscribe=20Controller=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=20API=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/v1/SubscribeController.kt | 10 +- .../UpdateSubscribeDepartmentRequest.kt | 4 +- .../request/UpdateSubscribeKeywordsRequest.kt | 6 +- .../request/UpdateSubscribeStatusRequest.kt | 8 +- .../controller/v1/SubscribeControllerTest.kt | 270 ++++++++++++++++++ 5 files changed, 284 insertions(+), 14 deletions(-) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt index 870eb9f..143bec6 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt @@ -28,7 +28,7 @@ class SubscribeController( @Operation(summary = "키워드 수정 API", description = "알림 키워드를 수정한다.") @PatchMapping("/api/v1/subscribe/keywords") fun updateSubscribeKeywords(@Valid @RequestBody request: UpdateSubscribeKeywordsRequest): ApiResponse { - subscribeUpdater.updateKeywords(token = request.token, keywords = request.keywords) + subscribeUpdater.updateKeywords(token = request.token!!, keywords = request.keywords) return ApiResponse.success() } @@ -36,8 +36,8 @@ class SubscribeController( @PatchMapping("/api/v1/subscribe/keyword/status") fun updateSubscribeKeywordStatus(@Valid @RequestBody request: UpdateSubscribeStatusRequest): ApiResponse { subscribeUpdater.updateKeywordSubscribeStatus( - token = request.token, - keywordSubscribeStatus = request.subscribeStatus + token = request.token!!, + keywordSubscribeStatus = request.subscribeStatus!! ) return ApiResponse.success() } @@ -53,8 +53,8 @@ class SubscribeController( @PatchMapping("/api/v1/subscribe/department/status") fun updateSubscribeDepartmentStatus(@Valid @RequestBody request: UpdateSubscribeStatusRequest): ApiResponse { subscribeUpdater.updateDepartmentSubscribeStatus( - token = request.token, - departmentSubscribeStatus = request.subscribeStatus + token = request.token!!, + departmentSubscribeStatus = request.subscribeStatus!! ) return ApiResponse.success() } diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeDepartmentRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeDepartmentRequest.kt index 38ec79c..c5754aa 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeDepartmentRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeDepartmentRequest.kt @@ -3,9 +3,9 @@ package com.dmforu.api.controller.v1.request import jakarta.validation.constraints.NotBlank data class UpdateSubscribeDepartmentRequest( - @NotBlank(message = "토큰은 필수입니다.") + @field:NotBlank(message = "토큰은 필수입니다.") val token: String, - @NotBlank(message = "학과는 필수입니다.") + @field:NotBlank(message = "학과는 필수입니다.") val department: String ) \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeKeywordsRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeKeywordsRequest.kt index db72e95..e5530b1 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeKeywordsRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeKeywordsRequest.kt @@ -3,8 +3,8 @@ package com.dmforu.api.controller.v1.request import jakarta.validation.constraints.NotBlank data class UpdateSubscribeKeywordsRequest( - @NotBlank(message = "토큰은 필수입니다.") - val token: String, + @field:NotBlank(message = "토큰은 필수입니다.") + val token: String?, - val keywords: List + val keywords: List, ) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeStatusRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeStatusRequest.kt index 8265909..53d38ec 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeStatusRequest.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/UpdateSubscribeStatusRequest.kt @@ -4,9 +4,9 @@ import jakarta.validation.constraints.NotBlank import jakarta.validation.constraints.NotNull data class UpdateSubscribeStatusRequest ( - @NotBlank(message = "토큰은 필수입니다.") - val token: String, + @field:NotBlank(message = "토큰은 필수입니다.") + val token: String?, - @NotNull(message = "구독 상태는 필수입니다.") - val subscribeStatus: Boolean + @field:NotNull(message = "구독 상태는 필수입니다.") + val subscribeStatus: Boolean? ) \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt index bbf308c..3b96e22 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt @@ -1,6 +1,9 @@ package com.dmforu.api.controller.v1 import com.dmforu.api.controller.v1.request.RegisterSubscribeRequest +import com.dmforu.api.controller.v1.request.UpdateSubscribeDepartmentRequest +import com.dmforu.api.controller.v1.request.UpdateSubscribeKeywordsRequest +import com.dmforu.api.controller.v1.request.UpdateSubscribeStatusRequest import com.dmforu.api.support.error.ErrorCode import com.dmforu.api.support.response.ResultType import com.dmforu.domain.subscribe.SubscribeUpdater @@ -13,6 +16,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.http.MediaType.APPLICATION_JSON import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status @@ -183,4 +187,270 @@ class SubscribeControllerTest { .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) .andExpect(jsonPath("$.error.data").value("키워드 구독 상태는 필수입니다.")) } + + @DisplayName("구독 키워드를 업데이트한다.") + @Test + fun updateSubscribeKeywords() { + // given + val request = UpdateSubscribeKeywordsRequest( + token = "0001", + keywords = listOf("학사"), + ) + + // when // then + mockMvc.perform( + patch("/api/v1/subscribe/keywords") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error").isEmpty) + } + + @DisplayName("구독 키워드를 업데이트할 때, 토큰은 필수 값이다.") + @Test + fun updateSubscribeKeywordsWithoutToken() { + // given + val request = UpdateSubscribeKeywordsRequest( + token = "", + keywords = listOf("학사"), + ) + + // when // then + mockMvc.perform( + patch("/api/v1/subscribe/keywords") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) + } + + @DisplayName("구독 키워드를 업데이트할 때, 키워드는 필수 값이 아니다. - 키워드를 전부 지워버릴 수 있기 때문") + @Test + fun updateSubscribeKeywordsWithoutKeyword() { + // given + val request = UpdateSubscribeKeywordsRequest( + token = "0001", + keywords = listOf(), + ) + + // when // then + mockMvc.perform( + patch("/api/v1/subscribe/keywords") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error").isEmpty) + } + + @DisplayName("키워드 알림 상태를 변경한다.") + @Test + fun updateSubscribeKeywordStatus() { + // given + val request = UpdateSubscribeStatusRequest( + token = "0001", + subscribeStatus = true + ) + + // when // then + mockMvc.perform( + patch("/api/v1/subscribe/keyword/status") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error").isEmpty) + } + + @DisplayName("키워드 알림 상태를 변경할 때, 토큰은 필수 값이다.") + @Test + fun updateSubscribeKeywordStatusWithoutToken() { + // given + val request = UpdateSubscribeStatusRequest( + token = "", + subscribeStatus = true + ) + + // when // then + mockMvc.perform( + patch("/api/v1/subscribe/keyword/status") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) + } + + @DisplayName("키워드 알림 상태를 변경할 때, 구독 상태는 필수 값이다.") + @Test + fun updateSubscribeKeywordStatusWithoutSubscribeStatus() { + // given + val request = UpdateSubscribeStatusRequest( + token = "0001", + subscribeStatus = null + ) + + // when // then + mockMvc.perform( + patch("/api/v1/subscribe/keyword/status") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("구독 상태는 필수입니다.")) + } + + @DisplayName("구독 학과를 업데이트한다.") + @Test + fun updateSubscribeDepartment() { + // given + val request = UpdateSubscribeDepartmentRequest( + token = "0001", + department = "컴퓨터소프트웨어공학과" + ) + + // when // then + mockMvc.perform( + patch("/api/v1/subscribe/department") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error").isEmpty) + } + + @DisplayName("구독 학과를 업데이트할 때, 토큰은 필수 값이다.") + @Test + fun updateSubscribeDepartmentWithoutToken() { + // given + val request = UpdateSubscribeDepartmentRequest( + token = "", + department = "컴퓨터소프트웨어공학과" + ) + + // when // then + mockMvc.perform( + patch("/api/v1/subscribe/department") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) + } + + @DisplayName("구독 학과를 업데이트할 때, 학과는 필수 값이다.") + @Test + fun updateSubscribeKeywordsWithoutDepartment() { + // given + val request = UpdateSubscribeDepartmentRequest( + token = "0001", + department = "" + ) + + // when // then + mockMvc.perform( + patch("/api/v1/subscribe/department") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("학과는 필수입니다.")) + } + + @DisplayName("학과 알림 상태를 변경한다.") + @Test + fun updateSubscribeDepartmentStatus() { + // given + val request = UpdateSubscribeStatusRequest( + token = "0001", + subscribeStatus = true + ) + + // when // then + mockMvc.perform( + patch("/api/v1/subscribe/department/status") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error").isEmpty) + } + + @DisplayName("학과 알림 상태를 변경할 때, 토큰은 필수 값이다.") + @Test + fun updateSubscribeDepartmentStatusWithoutToken() { + // given + val request = UpdateSubscribeStatusRequest( + token = "", + subscribeStatus = true + ) + + // when // then + mockMvc.perform( + patch("/api/v1/subscribe/department/status") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) + } + + @DisplayName("키워드 알림 상태를 변경할 때, 구독 상태 필수 값이다.") + @Test + fun updateSubscribeDepartmentStatusWithoutSubscribeStatus() { + // given + val request = UpdateSubscribeStatusRequest( + token = "0001", + subscribeStatus = null + ) + + // when // then + mockMvc.perform( + patch("/api/v1/subscribe/department/status") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("구독 상태는 필수입니다.")) + } } From a5890eff209e26087fe2c09e0299ab34daf12fe1 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:23:40 +0900 Subject: [PATCH 149/223] =?UTF-8?q?test:=20Diet=20Controller=20API=20Test?= =?UTF-8?q?=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/v1/DietControllerTest.kt | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt index 5cc9126..4578750 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt @@ -1,5 +1,38 @@ package com.dmforu.api.controller.v1 +import com.dmforu.api.support.response.ResultType +import com.dmforu.domain.diet.DietReader import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.http.MediaType.APPLICATION_JSON +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -class DietControllerTest \ No newline at end of file +@WebMvcTest(controllers = [DietController::class]) +class DietControllerTest { + + @Autowired + private lateinit var mockMvc: MockMvc + + @MockBean + private lateinit var dietReader: DietReader + + @DisplayName("식단을 불러온다.") + @Test + fun readDiet() { + mockMvc.perform( + get("/api/v1/cafeteria") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isArray) + .andExpect(jsonPath("$.error").isEmpty) + } +} \ No newline at end of file From 4b8e16deca010e9ca818b780a23369ebc5bc5b07 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:24:03 +0900 Subject: [PATCH 150/223] =?UTF-8?q?test:=20Schedule=20Controller=20API=20T?= =?UTF-8?q?est=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/v1/ScheduleControllerTest.kt | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt index 0f1ab84..b9345bd 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt @@ -1,5 +1,43 @@ package com.dmforu.api.controller.v1 +import com.dmforu.api.support.response.ResultType +import com.dmforu.domain.schedule.ScheduleReader import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.mockito.BDDMockito.given +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.http.MediaType.APPLICATION_JSON +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -class ScheduleControllerTest \ No newline at end of file +@WebMvcTest(ScheduleController::class) +class ScheduleControllerTest { + + @Autowired + private lateinit var mockMvc: MockMvc + + @MockBean + private lateinit var scheduleReader: ScheduleReader + + @DisplayName("식단을 불러온다.") + @Test + fun readDiet() { + // given + given(scheduleReader.read()).willReturn(listOf()) + + // when // then + mockMvc.perform( + get("/api/v1/schedule") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isArray) + .andExpect(jsonPath("$.error").isEmpty) + } +} From 82b37e157b51e6b0b81a98c8381a8e8ea4e24f6c Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:24:33 +0900 Subject: [PATCH 151/223] =?UTF-8?q?test:=20Notice=20Controller=20API=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1=20=EB=B0=8F=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/ApiControllerAdvice.kt | 7 - .../api/controller/v1/NoticeController.kt | 35 ++- .../v1/request/PaginationRequest.kt | 11 + .../api/controller/v1/NoticeControllerTest.kt | 280 +++++++++++++++++- 4 files changed, 311 insertions(+), 22 deletions(-) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/PaginationRequest.kt diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt index 3703ad3..559a992 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt @@ -12,7 +12,6 @@ import org.springframework.web.bind.MissingServletRequestParameterException import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice import org.springframework.web.servlet.resource.NoResourceFoundException -import java.net.BindException @RestControllerAdvice class ApiControllerAdvice { @@ -45,12 +44,6 @@ class ApiControllerAdvice { return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) } - @ExceptionHandler(BindException::class) - fun handleRequestBodyException(e: BindException): ResponseEntity> { - log.error("BindException : {}", e.message, e) - return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) - } - @ExceptionHandler(Exception::class) fun handleException(e: Exception): ResponseEntity> { log.error("Exception : {}", e.message, e) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt index 6e9ae01..1d6cb39 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt @@ -1,14 +1,13 @@ package com.dmforu.api.controller.v1 +import com.dmforu.api.controller.v1.request.PaginationRequest import com.dmforu.api.controller.v1.response.NoticeResponse import com.dmforu.api.support.response.ApiResponse import com.dmforu.domain.notice.NoticeReader import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestParam -import org.springframework.web.bind.annotation.RestController +import jakarta.validation.Valid +import org.springframework.web.bind.annotation.* @Tag(name = "공지") @RestController @@ -21,10 +20,13 @@ class NoticeController( ) @GetMapping("/api/v1/notice/university") fun getUniversityNotice( - @RequestParam(name = "page", defaultValue = "1") page: Int, - @RequestParam(name = "size", defaultValue = "20") size: Int, + @Valid @ModelAttribute paginationRequest: PaginationRequest, ): ApiResponse> { - val universityNotices = noticeReader.readUniversityNotice(page, size).map { NoticeResponse.form(it) } + val universityNotices = + noticeReader.readUniversityNotice( + page = paginationRequest.page, + size = paginationRequest.size + ).map { NoticeResponse.form(it) } return ApiResponse.success(universityNotices) } @@ -35,11 +37,14 @@ class NoticeController( @GetMapping("/api/v1/notice/department") fun getDepartmentNotice( @RequestParam(name = "department") department: String, - @RequestParam(name = "page", defaultValue = "1") page: Int, - @RequestParam(name = "size", defaultValue = "20") size: Int, + @Valid @ModelAttribute paginationRequest: PaginationRequest, ): ApiResponse> { val departmentNotices = - noticeReader.readDepartmentNotice(department, page, size).map { NoticeResponse.form(it) } + noticeReader.readDepartmentNotice( + department = department, + page = paginationRequest.page, + size = paginationRequest.size + ).map { NoticeResponse.form(it) } return ApiResponse.success(departmentNotices) } @@ -51,10 +56,14 @@ class NoticeController( fun getNoticeByKeyword( @PathVariable(name = "searchWord") searchWord: String, @RequestParam(name = "department") department: String, - @RequestParam(name = "page", defaultValue = "1") page: Int, - @RequestParam(name = "size", defaultValue = "20") size: Int, + @Valid @ModelAttribute paginationRequest: PaginationRequest, ): ApiResponse> { - val notices = noticeReader.searchNotice(searchWord, department, page, size).map { NoticeResponse.form(it) } + val notices = noticeReader.searchNotice( + searchWord = searchWord, + department = department, + page = paginationRequest.page, + size = paginationRequest.size + ).map { NoticeResponse.form(it) } return ApiResponse.success(notices) } } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/PaginationRequest.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/PaginationRequest.kt new file mode 100644 index 0000000..494a645 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/request/PaginationRequest.kt @@ -0,0 +1,11 @@ +package com.dmforu.api.controller.v1.request + +import jakarta.validation.constraints.Min + +data class PaginationRequest( + @field:Min(value = 1, message = "페이지는 1이상이어야 합니다.") + val page: Int = 1, + + @field:Min(value = 1, message = "사이즈는 1이상이어야 합니다.") + val size: Int = 20 +) \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt index 93d0d89..df1f3b7 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt @@ -1,5 +1,281 @@ package com.dmforu.api.controller.v1 -import org.junit.jupiter.api.Assertions.* +import com.dmforu.api.support.error.ErrorCode +import com.dmforu.api.support.response.ResultType +import com.dmforu.domain.notice.NoticeReader +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyString +import org.mockito.BDDMockito.given +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.http.MediaType.APPLICATION_JSON +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -class NoticeControllerTest \ No newline at end of file +@WebMvcTest(controllers = [NoticeController::class]) +class NoticeControllerTest { + + @Autowired + private lateinit var mockMvc: MockMvc + + @MockBean + private lateinit var noticeReader: NoticeReader + + @DisplayName("대학 공지를 불러온다.") + @Test + fun getUniversityNotice() { + // given + given(noticeReader.readUniversityNotice(anyInt(), anyInt())).willReturn(listOf()) + + // when then + mockMvc.perform( + get("/api/v1/notice/university") + .param("page", "1") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isArray) + .andExpect(jsonPath("$.error").isEmpty) + } + + @DisplayName("학과 공지를 불러온다.") + @Test + fun getDepartmentNotice() { + // given + given(noticeReader.readDepartmentNotice(anyString(), anyInt(), anyInt())).willReturn(listOf()) + + // when then + mockMvc.perform( + get("/api/v1/notice/department") + .param("department", "컴퓨터소프트웨어공학과") + .param("page", "1") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isArray) + .andExpect(jsonPath("$.error").isEmpty) + } + + @DisplayName("학과 공지를 불러올 때, 학과는 필수 값이다.") + @Test + fun getDepartmentNoticeWhenDepartmentIsEmpty() { + mockMvc.perform( + get("/api/v1/notice/department") + .param("page", "1") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").isEmpty) + .andExpect(jsonPath("$.data").isEmpty) + } + + + @DisplayName("공지를 검색한다.") + @Test + fun getNoticeByKeyword() { + // given + given(noticeReader.searchNotice(anyString(), anyString(), anyInt(), anyInt())).willReturn(listOf()) + + // when then + mockMvc.perform( + get("/api/v1/notice/공지사항") + .param("department", "컴퓨터소프트웨어공학과") + .param("page", "1") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isArray) + .andExpect(jsonPath("$.error").isEmpty) + } + + @DisplayName("공지를 검색할 때, 학과는 필수 값이다.") + @Test + fun getNoticeByKeywordWhen() { + mockMvc.perform( + get("/api/v1/notice/search") + .param("page", "1") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").isEmpty) + .andExpect(jsonPath("$.data").isEmpty) + } + + @DisplayName("공지를 검색할 때, 검색어는 필수 값이다. ") + @Test + fun getNoticeByKeywordWhenPathValueIsEmpty() { + mockMvc.perform( + get("/api/v1/notice/") + .param("department", "컴퓨터소프트웨어공학과") + .param("page", "1") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").isEmpty) + .andExpect(jsonPath("$.data").isEmpty) + } + + @DisplayName("공지를 불러올 때, 페이지네이션 값이 빠져있다면 페이지 1, 사이즈 20으로 자동 설정된다.") + @Test + fun getNoticeWithoutPagination() { + // given + given(noticeReader.readUniversityNotice(anyInt(), anyInt())).willReturn(listOf()) + given(noticeReader.readDepartmentNotice(anyString(), anyInt(), anyInt())).willReturn(listOf()) + given(noticeReader.searchNotice(anyString(), anyString(), anyInt(), anyInt())).willReturn(listOf()) + + // when then + mockMvc.perform( + get("/api/v1/notice/university") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isArray) + .andExpect(jsonPath("$.error").isEmpty) + + mockMvc.perform( + get("/api/v1/notice/department") + .param("department", "컴퓨터소프트웨어공학과") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isArray) + .andExpect(jsonPath("$.error").isEmpty) + + mockMvc.perform( + get("/api/v1/notice/공지사항") + .param("department", "컴퓨터소프트웨어공학과") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) + .andExpect(jsonPath("$.data").isArray) + .andExpect(jsonPath("$.error").isEmpty) + } + + @DisplayName("공지를 불러올 때, 페이지의 값은 1이상이어야 한다.") + @Test + fun getNoticeWhenPageIsLessThenOne() { + // given + given(noticeReader.readUniversityNotice(anyInt(), anyInt())).willReturn(listOf()) + given(noticeReader.readDepartmentNotice(anyString(), anyInt(), anyInt())).willReturn(listOf()) + given(noticeReader.searchNotice(anyString(), anyString(), anyInt(), anyInt())).willReturn(listOf()) + + // when then + mockMvc.perform( + get("/api/v1/notice/university") + .param("page", "0") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("페이지는 1이상이어야 합니다.")) + + mockMvc.perform( + get("/api/v1/notice/department") + .param("page", "0") + .param("size", "20") + .param("department", "컴퓨터소프트웨어공학과") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("페이지는 1이상이어야 합니다.")) + + mockMvc.perform( + get("/api/v1/notice/공지사항") + .param("page", "0") + .param("size", "20") + .param("department", "컴퓨터소프트웨어공학과") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("페이지는 1이상이어야 합니다.")) + } + + @DisplayName("공지를 불러올 때, 사이즈의 값은 1이상이어야 한다.") + @Test + fun getNoticeWhenSizeIsLessThenOne() { + // given + given(noticeReader.readUniversityNotice(anyInt(), anyInt())).willReturn(listOf()) + given(noticeReader.readDepartmentNotice(anyString(), anyInt(), anyInt())).willReturn(listOf()) + given(noticeReader.searchNotice(anyString(), anyString(), anyInt(), anyInt())).willReturn(listOf()) + + // when then + mockMvc.perform( + get("/api/v1/notice/university") + .param("page", "1") + .param("size", "0") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("사이즈는 1이상이어야 합니다.")) + + mockMvc.perform( + get("/api/v1/notice/department") + .param("page", "1") + .param("size", "0") + .param("department", "컴퓨터소프트웨어공학과") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("사이즈는 1이상이어야 합니다.")) + + mockMvc.perform( + get("/api/v1/notice/공지사항") + .param("page", "1") + .param("size", "0") + .param("department", "컴퓨터소프트웨어공학과") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) + .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("사이즈는 1이상이어야 합니다.")) + } +} \ No newline at end of file From cb8b376c8a71c6e8137511c27e68adbdc6e1aa9a Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:28:45 +0900 Subject: [PATCH 152/223] =?UTF-8?q?chore:=20jacoco=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=98=88=EC=99=B8=20=ED=8C=8C=EC=9D=BC=20'Error'?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle.kts b/build.gradle.kts index 7dfae3a..df71044 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -74,6 +74,7 @@ subprojects { "**/*Application*", "**/*Config*", "**/*Dto*", + "**/*Error*", "**/*Request*", "**/*Response*", "**/*Interceptor*", From 0b480702f1ca94ac689d33466b23de59d0f6db66 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:51:48 +0900 Subject: [PATCH 153/223] =?UTF-8?q?test:=20Controller=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=ED=99=98=EA=B2=BD=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/api/ControllerTestSupport.kt | 48 +++++++++++++++++++ .../api/controller/v1/DietControllerTest.kt | 15 +----- .../api/controller/v1/NoticeControllerTest.kt | 15 +----- .../controller/v1/ScheduleControllerTest.kt | 15 +----- .../controller/v1/SubscribeControllerTest.kt | 23 +-------- 5 files changed, 56 insertions(+), 60 deletions(-) create mode 100644 dmforu-api/src/test/kotlin/com/dmforu/api/ControllerTestSupport.kt diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/ControllerTestSupport.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/ControllerTestSupport.kt new file mode 100644 index 0000000..f774bcf --- /dev/null +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/ControllerTestSupport.kt @@ -0,0 +1,48 @@ +package com.dmforu.api + +import com.dmforu.api.controller.v1.DietController +import com.dmforu.api.controller.v1.NoticeController +import com.dmforu.api.controller.v1.ScheduleController +import com.dmforu.api.controller.v1.SubscribeController +import com.dmforu.domain.diet.DietReader +import com.dmforu.domain.notice.NoticeReader +import com.dmforu.domain.schedule.ScheduleReader +import com.dmforu.domain.subscribe.SubscribeUpdater +import com.dmforu.domain.subscribe.SubscribeWriter +import com.fasterxml.jackson.databind.ObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.test.web.servlet.MockMvc + +@WebMvcTest(controllers = [DietController::class, NoticeController::class, ScheduleController::class, SubscribeController::class]) +abstract class ControllerTestSupport { + + @Autowired + protected lateinit var mockMvc: MockMvc + + @Autowired + protected lateinit var objectMapper: ObjectMapper + + @MockBean + protected lateinit var dietReader: DietReader + + @MockBean + protected lateinit var noticeReader: NoticeReader + + @MockBean + protected lateinit var scheduleReader: ScheduleReader + + @MockBean + protected lateinit var subscribeUpdater: SubscribeUpdater + + @MockBean + protected lateinit var subscribeWriter: SubscribeWriter + +} + + + + + + diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt index 4578750..819d893 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt @@ -1,27 +1,16 @@ package com.dmforu.api.controller.v1 +import com.dmforu.api.ControllerTestSupport import com.dmforu.api.support.response.ResultType -import com.dmforu.domain.diet.DietReader import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest -import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.http.MediaType.APPLICATION_JSON -import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -@WebMvcTest(controllers = [DietController::class]) -class DietControllerTest { - - @Autowired - private lateinit var mockMvc: MockMvc - - @MockBean - private lateinit var dietReader: DietReader +class DietControllerTest : ControllerTestSupport() { @DisplayName("식단을 불러온다.") @Test diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt index df1f3b7..e556b34 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt @@ -1,30 +1,19 @@ package com.dmforu.api.controller.v1 +import com.dmforu.api.ControllerTestSupport import com.dmforu.api.support.error.ErrorCode import com.dmforu.api.support.response.ResultType -import com.dmforu.domain.notice.NoticeReader import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString import org.mockito.BDDMockito.given -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest -import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.http.MediaType.APPLICATION_JSON -import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -@WebMvcTest(controllers = [NoticeController::class]) -class NoticeControllerTest { - - @Autowired - private lateinit var mockMvc: MockMvc - - @MockBean - private lateinit var noticeReader: NoticeReader +class NoticeControllerTest : ControllerTestSupport() { @DisplayName("대학 공지를 불러온다.") @Test diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt index b9345bd..959577b 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt @@ -1,28 +1,17 @@ package com.dmforu.api.controller.v1 +import com.dmforu.api.ControllerTestSupport import com.dmforu.api.support.response.ResultType -import com.dmforu.domain.schedule.ScheduleReader import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.mockito.BDDMockito.given -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest -import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.http.MediaType.APPLICATION_JSON -import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -@WebMvcTest(ScheduleController::class) -class ScheduleControllerTest { - - @Autowired - private lateinit var mockMvc: MockMvc - - @MockBean - private lateinit var scheduleReader: ScheduleReader +class ScheduleControllerTest : ControllerTestSupport() { @DisplayName("식단을 불러온다.") @Test diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt index 3b96e22..9bdfdd5 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt @@ -1,40 +1,21 @@ package com.dmforu.api.controller.v1 +import com.dmforu.api.ControllerTestSupport import com.dmforu.api.controller.v1.request.RegisterSubscribeRequest import com.dmforu.api.controller.v1.request.UpdateSubscribeDepartmentRequest import com.dmforu.api.controller.v1.request.UpdateSubscribeKeywordsRequest import com.dmforu.api.controller.v1.request.UpdateSubscribeStatusRequest import com.dmforu.api.support.error.ErrorCode import com.dmforu.api.support.response.ResultType -import com.dmforu.domain.subscribe.SubscribeUpdater -import com.dmforu.domain.subscribe.SubscribeWriter -import com.fasterxml.jackson.databind.ObjectMapper import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest -import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.http.MediaType.APPLICATION_JSON -import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -@WebMvcTest(SubscribeController::class) -class SubscribeControllerTest { - - @Autowired - private lateinit var mockMvc: MockMvc - - @Autowired - private lateinit var objectMapper: ObjectMapper - - @MockBean - private lateinit var subscribeUpdater: SubscribeUpdater - - @MockBean - private lateinit var subscribeWriter: SubscribeWriter +class SubscribeControllerTest : ControllerTestSupport() { @DisplayName("구독을 생성한다.") @Test From caf7ed3b728ac2ee9b814f9f5a5d53cb6e5dc9eb Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 00:58:00 +0900 Subject: [PATCH 154/223] =?UTF-8?q?feat:=20MongoDB=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20=ED=95=99=EC=82=AC=EC=9D=BC=EC=A0=95=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/build.gradle.kts | 2 +- .../com/dmforu/admin/AdminApplication.kt | 2 +- dmforu-api/build.gradle.kts | 2 +- .../kotlin/com/dmforu/api/ApiApplication.kt | 4 +- .../com/dmforu/domain/schedule/Schedule.kt | 58 +++++++++++++ .../storage/db/redis/config/RedisConfig.kt | 5 +- .../storage/db/redis/diet/DietEntity.kt | 2 +- .../db/redis/diet/DietEntityRepository.kt | 2 +- .../db/redis/schedule/ScheduleEntity.kt | 2 +- .../schedule/ScheduleEntityRepository.kt | 82 +++++++++---------- .../storage/mongo/build.gradle.kts | 7 ++ .../storage/db/mongo/config/MongoConfig.kt | 47 +++++++++++ .../schedule/ScheduleEntityRepository.kt | 22 +++++ .../db/mongo/schedule/ScheduleMapper.kt | 63 ++++++++++++++ .../mongo/schedule/ScheduleMongoRepository.kt | 8 ++ .../db/mongo/schedule/entity/MonthEntity.kt | 9 ++ .../mongo/schedule/entity/ScheduleEntity.kt | 9 ++ .../mongo/schedule/entity/SchedulesEntity.kt | 11 +++ .../db/mongo/schedule/entity/YearEntity.kt | 9 ++ .../storage/db/mongo/MongoApplicationTest.kt | 8 ++ .../ScheduleEntityMongoRepositoryTest.kt | 80 ++++++++++++++++++ settings.gradle.kts | 3 +- 22 files changed, 386 insertions(+), 51 deletions(-) create mode 100644 dmforu-infrastructure/storage/mongo/build.gradle.kts create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/config/MongoConfig.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityRepository.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleMapper.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleMongoRepository.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/MonthEntity.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/ScheduleEntity.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/SchedulesEntity.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/YearEntity.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoApplicationTest.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityMongoRepositoryTest.kt diff --git a/dmforu-admin/build.gradle.kts b/dmforu-admin/build.gradle.kts index a77bd3c..2f0c9e3 100644 --- a/dmforu-admin/build.gradle.kts +++ b/dmforu-admin/build.gradle.kts @@ -12,5 +12,5 @@ dependencies { runtimeOnly(project(":dmforu-infrastructure:fcm")) runtimeOnly(project(":dmforu-infrastructure:storage:db-mysql")) - runtimeOnly(project(":dmforu-infrastructure:storage:db-redis")) + runtimeOnly(project(":dmforu-infrastructure:storage:mongo")) } \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt index 86e8891..ab56d95 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt @@ -8,7 +8,7 @@ import org.springframework.scheduling.annotation.EnableScheduling scanBasePackages = [ "com.dmforu.admin", "com.dmforu.fcm", - "com.dmforu.storage.db.redis", + "com.dmforu.storage.db.mongo", "com.dmforu.storage.db.mysql" ] ) diff --git a/dmforu-api/build.gradle.kts b/dmforu-api/build.gradle.kts index 59a3a46..56dfc7f 100644 --- a/dmforu-api/build.gradle.kts +++ b/dmforu-api/build.gradle.kts @@ -10,7 +10,7 @@ dependencies { implementation(project(":dmforu-domain")) runtimeOnly(project(":dmforu-infrastructure:storage:db-mysql")) - runtimeOnly(project(":dmforu-infrastructure:storage:db-redis")) + runtimeOnly(project(":dmforu-infrastructure:storage:mongo")) implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-validation") diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt index bc79386..bc684f6 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/ApiApplication.kt @@ -1,13 +1,15 @@ package com.dmforu.api import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.context.properties.ConfigurationPropertiesScan import org.springframework.boot.runApplication +@ConfigurationPropertiesScan @SpringBootApplication( scanBasePackages = [ "com.dmforu.api", "com.dmforu.domain", - "com.dmforu.storage.db.redis", + "com.dmforu.storage.db.mongo", "com.dmforu.storage.db.mysql" ] ) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt index e990654..e104801 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt @@ -3,6 +3,7 @@ package com.dmforu.domain.schedule class Schedule private constructor( val dates: List, val content: String, + ) { companion object { fun of(dateArray: List, content: String): Schedule { @@ -19,6 +20,25 @@ class Schedule private constructor( return Month(month, monthSchedule) } } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Month + + if (month != other.month) return false + if (monthSchedule != other.monthSchedule) return false + + return true + } + + override fun hashCode(): Int { + var result = month + result = 31 * result + monthSchedule.hashCode() + return result + } + } class Year private constructor( @@ -30,6 +50,44 @@ class Schedule private constructor( return Year(year, yearSchedule) } } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Year + + if (year != other.year) return false + if (yearSchedule != other.yearSchedule) return false + + return true + } + + override fun hashCode(): Int { + var result = year + result = 31 * result + yearSchedule.hashCode() + return result + } + + + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Schedule + + if (dates != other.dates) return false + if (content != other.content) return false + + return true + } + + override fun hashCode(): Int { + var result = dates.hashCode() + result = 31 * result + content.hashCode() + return result } } \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt index a550ca6..467141d 100644 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt +++ b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt @@ -1,8 +1,9 @@ -package com.dmforu.storage.db.redis.config +package com.dmforu.storage.db.mongo.config import org.springframework.beans.factory.annotation.Value import org.springframework.boot.autoconfigure.domain.EntityScan +import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.cache.CacheManager import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -19,7 +20,7 @@ import java.time.Duration @Configuration @EntityScan(basePackages = ["com.dmforu.storage.db.redis"]) -@EnableRedisRepositories(basePackages = ["com.dmforu.storage.db.redis"]) +@EnableRedisRepositories(basePackages = ["com.dmforu.storage.db.mongo"]) internal class RedisConfig( @Value("\${spring.data.redis.host}") var host: String, diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt index 60d5516..7a73d6c 100644 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt +++ b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt @@ -1,4 +1,4 @@ -package com.dmforu.storage.db.redis.diet +package com.dmforu.storage.db.mongo.diet import com.dmforu.domain.diet.Diet import org.springframework.data.annotation.Id diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt index b3cf2a3..f0b2fc6 100644 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt +++ b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt @@ -1,4 +1,4 @@ -package com.dmforu.storage.db.redis.diet +package com.dmforu.storage.db.mongo.diet import com.dmforu.domain.diet.Diet import com.dmforu.domain.diet.DietRepository diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt index 7158353..52dd109 100644 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt +++ b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt @@ -1,4 +1,4 @@ -package com.dmforu.storage.db.redis.schedule +package com.dmforu.storage.db.mongo.schedule import com.dmforu.domain.schedule.Schedule import org.springframework.data.annotation.Id diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt index 3c9b73d..27c1435 100644 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt +++ b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt @@ -1,41 +1,41 @@ -package com.dmforu.storage.db.redis.schedule - -import com.dmforu.domain.schedule.Schedule -import com.dmforu.domain.schedule.ScheduleRepository -import org.springframework.data.redis.core.RedisTemplate -import org.springframework.stereotype.Repository - -@Repository -internal class ScheduleEntityRepository( - private val redisTemplate: RedisTemplate -) : ScheduleRepository { - - private companion object { - const val SCHEDULE_KEY = "schedule" - } - - - override fun write(schedules: List) { - writeEntity(SCHEDULE_KEY, ScheduleEntity(schedules = schedules)) - } - - - override fun read(): List? { - return readEntity(SCHEDULE_KEY)?.schedules - } - - /** - * 공통된 엔티티 쓰기 메서드 - */ - private fun writeEntity(key: String, entity: T) { - redisTemplate.opsForValue().set(key, entity) - } - - /** - * 공통된 엔티티 읽기 메서드 - */ - @Suppress("UNCHECKED_CAST") - private fun readEntity(key: String): T? { - return redisTemplate.opsForValue().get(key) as? T - } -} \ No newline at end of file +//package com.dmforu.storage.db.mongo.schedule +// +//import com.dmforu.domain.schedule.Schedule +//import com.dmforu.domain.schedule.ScheduleRepository +//import org.springframework.data.redis.core.RedisTemplate +//import org.springframework.stereotype.Repository +// +//@Repository +//internal class ScheduleEntityRepository( +// private val redisTemplate: RedisTemplate +//) : ScheduleRepository { +// +// private companion object { +// const val SCHEDULE_KEY = "schedule" +// } +// +// +// override fun write(schedules: List) { +// writeEntity(SCHEDULE_KEY, ScheduleEntity(schedules = schedules)) +// } +// +// +// override fun read(): List? { +// return readEntity(SCHEDULE_KEY)?.schedules +// } +// +// /** +// * 공통된 엔티티 쓰기 메서드 +// */ +// private fun writeEntity(key: String, entity: T) { +// redisTemplate.opsForValue().set(key, entity) +// } +// +// /** +// * 공통된 엔티티 읽기 메서드 +// */ +// @Suppress("UNCHECKED_CAST") +// private fun readEntity(key: String): T? { +// return redisTemplate.opsForValue().get(key) as? T +// } +//} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/build.gradle.kts b/dmforu-infrastructure/storage/mongo/build.gradle.kts new file mode 100644 index 0000000..d47a6e1 --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/build.gradle.kts @@ -0,0 +1,7 @@ +dependencies { + implementation("org.springframework.boot:spring-boot-starter-data-mongodb") + + compileOnly(project(":dmforu-domain")) + + testImplementation(project(":dmforu-domain")) +} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/config/MongoConfig.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/config/MongoConfig.kt new file mode 100644 index 0000000..861d100 --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/config/MongoConfig.kt @@ -0,0 +1,47 @@ +package com.dmforu.storage.db.mongo.config + +import com.mongodb.ConnectionString +import com.mongodb.MongoClientSettings +import com.mongodb.client.MongoClient +import com.mongodb.client.MongoClients +import org.bson.codecs.configuration.CodecRegistries.fromProviders +import org.bson.codecs.configuration.CodecRegistries.fromRegistries +import org.bson.codecs.configuration.CodecRegistry +import org.bson.codecs.pojo.PojoCodecProvider +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.data.mongodb.core.MongoTemplate +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories + + +@Configuration +@EnableMongoRepositories(basePackages = ["com.dmforu.storage.db.mongo"]) +internal class MongoConfig( + @Value("\${spring.data.mongodb.uri}") + val uri: String, + + @Value("\${spring.data.mongodb.database}") + val database: String +) { + + + @Bean + fun mongoClient(): MongoClient { + val pojoCodecRegistry: CodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build()) + val codecRegistry: CodecRegistry = + fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry) + return MongoClients.create( + MongoClientSettings.builder() + .applyConnectionString(ConnectionString(uri)) + .codecRegistry(codecRegistry) + .build() + ) + } + + @Bean + fun mongoTemplate(): MongoTemplate { + return MongoTemplate(mongoClient(), database) + } + +} diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityRepository.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityRepository.kt new file mode 100644 index 0000000..4b4f094 --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityRepository.kt @@ -0,0 +1,22 @@ +package com.dmforu.storage.db.mongo.schedule + +import com.dmforu.domain.schedule.Schedule +import com.dmforu.domain.schedule.ScheduleRepository +import org.springframework.stereotype.Repository +import org.springframework.transaction.annotation.Transactional + +@Repository +internal class ScheduleEntityRepository( + private val scheduleMongoRepository: ScheduleMongoRepository +) : ScheduleRepository { + + @Transactional + override fun write(schedules: List) { + scheduleMongoRepository.deleteAll() + scheduleMongoRepository.save(ScheduleMapper.mapToEntity(schedules)) + } + + override fun read(): List? { + return ScheduleMapper.entityToSchedules(scheduleMongoRepository.findAll().firstOrNull()) + } +} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleMapper.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleMapper.kt new file mode 100644 index 0000000..8042c2b --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleMapper.kt @@ -0,0 +1,63 @@ +package com.dmforu.storage.db.mongo.schedule + +import com.dmforu.domain.schedule.Schedule +import com.dmforu.storage.db.mongo.schedule.entity.MonthEntity +import com.dmforu.storage.db.mongo.schedule.entity.ScheduleEntity +import com.dmforu.storage.db.mongo.schedule.entity.SchedulesEntity +import com.dmforu.storage.db.mongo.schedule.entity.YearEntity + +internal object ScheduleMapper { + fun mapToEntity(schedules: List): SchedulesEntity { + val result = schedules.map { toYearEntity(it) } + return SchedulesEntity( + years = result + ) + } + + fun entityToSchedules(entity: SchedulesEntity?): List? { + return entity?.years?.map { toYearSchedule(it) } + } + + private fun toYearEntity(yearSchedule: Schedule.Year): YearEntity { + val result = yearSchedule.yearSchedule.map { + toMonthEntity(it) + } + + return YearEntity( + year = yearSchedule.year, + yearSchedule = result + ) + } + + private fun toMonthEntity(monthSchedule: Schedule.Month): MonthEntity { + val result = monthSchedule.monthSchedule.map { + toScheduleEntity(it) + } + + return MonthEntity( + month = monthSchedule.month, + monthSchedule = result + ) + } + + private fun toScheduleEntity(schedule: Schedule): ScheduleEntity { + return ScheduleEntity( + dates = schedule.dates, + content = schedule.content + ) + } + + private fun toYearSchedule(yearEntity: YearEntity): Schedule.Year { + val monthSchedules = yearEntity.yearSchedule.map { toMonthSchedule(it) } + return Schedule.Year.of(yearEntity.year, monthSchedules) + } + + private fun toMonthSchedule(monthEntity: MonthEntity): Schedule.Month { + val schedules = monthEntity.monthSchedule.map { toSchedule(it) } + return Schedule.Month.of(monthEntity.month, schedules) + } + + private fun toSchedule(scheduleEntity: ScheduleEntity): Schedule { + return Schedule.of(scheduleEntity.dates, scheduleEntity.content) + } +} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleMongoRepository.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleMongoRepository.kt new file mode 100644 index 0000000..cfa4a72 --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleMongoRepository.kt @@ -0,0 +1,8 @@ +package com.dmforu.storage.db.mongo.schedule + +import com.dmforu.storage.db.mongo.schedule.entity.SchedulesEntity +import org.springframework.data.mongodb.repository.MongoRepository +import org.springframework.stereotype.Repository + +@Repository +internal interface ScheduleMongoRepository : MongoRepository {} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/MonthEntity.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/MonthEntity.kt new file mode 100644 index 0000000..1d3fd7b --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/MonthEntity.kt @@ -0,0 +1,9 @@ +package com.dmforu.storage.db.mongo.schedule.entity + +import org.springframework.data.mongodb.core.mapping.Document + +@Document(collection = "months") +internal data class MonthEntity( + val month: Int, + val monthSchedule: List, +) diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/ScheduleEntity.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/ScheduleEntity.kt new file mode 100644 index 0000000..2d614e0 --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/ScheduleEntity.kt @@ -0,0 +1,9 @@ +package com.dmforu.storage.db.mongo.schedule.entity + +import org.springframework.data.mongodb.core.mapping.Document + +@Document(collection = "schedules") +internal data class ScheduleEntity( + val dates: List, + val content: String +) \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/SchedulesEntity.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/SchedulesEntity.kt new file mode 100644 index 0000000..1a18215 --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/SchedulesEntity.kt @@ -0,0 +1,11 @@ +package com.dmforu.storage.db.mongo.schedule.entity + +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.mapping.Document + +@Document(collection = "schedules_entity") +internal data class SchedulesEntity( + @Id + val id: String? = null, + val years: List, +) diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/YearEntity.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/YearEntity.kt new file mode 100644 index 0000000..fdd9021 --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/entity/YearEntity.kt @@ -0,0 +1,9 @@ +package com.dmforu.storage.db.mongo.schedule.entity + +import org.springframework.data.mongodb.core.mapping.Document + +@Document(collection = "years") +internal data class YearEntity( + val year: Int, + val yearSchedule: List +) diff --git a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoApplicationTest.kt b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoApplicationTest.kt new file mode 100644 index 0000000..f977e92 --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoApplicationTest.kt @@ -0,0 +1,8 @@ +package com.dmforu.storage.db.mongo + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.test.context.ActiveProfiles + +@SpringBootApplication +@ActiveProfiles("test") +class MongoApplicationTest \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityMongoRepositoryTest.kt b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityMongoRepositoryTest.kt new file mode 100644 index 0000000..921387c --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityMongoRepositoryTest.kt @@ -0,0 +1,80 @@ +package com.dmforu.storage.db.mongo.schedule + + +import com.dmforu.domain.schedule.Schedule +import com.dmforu.storage.db.mongo.MongoApplicationTest +import com.dmforu.storage.db.mongo.config.MongoConfig +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.DisplayName +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.context.annotation.Import +import org.springframework.test.context.TestPropertySource +import kotlin.test.Test + +@TestPropertySource(properties = ["spring.config.location = src/main/resources/mongo.yml"]) +@SpringBootTest(classes = [MongoApplicationTest::class]) +@Import(MongoConfig::class) +class ScheduleEntityMongoRepositoryTest { + + @Autowired + private lateinit var mongoRepository: ScheduleMongoRepository + + @Autowired + private lateinit var entityRepository: ScheduleEntityRepository + + @AfterEach + fun tearDown() { + mongoRepository.deleteAll() + } + + @DisplayName("학사 일정을 저장한다.") + @Test + fun write() { + // given + val schedule = Schedule.of(listOf("날짜1", "날짜2"), "내용") + val monthSchedule = Schedule.Month.of(1, listOf(schedule)) + val yearSchedule = Schedule.Year.of(1, listOf(monthSchedule)) + val schedules = listOf(yearSchedule, yearSchedule) + + // when + entityRepository.write(schedules) + + // then + val result = mongoRepository.findAll()[0] + + assertThat(result).isNotNull + assertThat(ScheduleMapper.entityToSchedules(result)).isEqualTo(schedules) + } + + @DisplayName("학사 일정을 불러온다.") + @Test + fun read() { + // given + val schedule = Schedule.of(listOf("날짜1", "날짜2"), "내용") + val monthSchedule = Schedule.Month.of(1, listOf(schedule)) + val yearSchedule = Schedule.Year.of(1, listOf(monthSchedule)) + val schedules = listOf(yearSchedule, yearSchedule) + + mongoRepository.save(ScheduleMapper.mapToEntity(schedules)) + + // when + val savedEntity = entityRepository.read() + + assertThat(savedEntity).isNotNull + assertThat(savedEntity).isEqualTo(schedules) + } + + @DisplayName("학사 일정을 불러올 때, 학사 일정이 없다면 null을 반환한다.") + @Test + fun readWhenEmpty() { + // given + + // when + val savedEntity = entityRepository.read() + + // then + assertThat(savedEntity).isNull() + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 55435b3..c128a7b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -7,7 +7,8 @@ include( "dmforu-crawling", "dmforu-infrastructure:fcm", "dmforu-infrastructure:storage:db-mysql", - "dmforu-infrastructure:storage:db-redis" + "dmforu-infrastructure:storage:db-redis", + "dmforu-infrastructure:storage:mongo", ) pluginManagement { From cfd5025d341388e9ad769b80746105e198fa25ca Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 00:59:06 +0900 Subject: [PATCH 155/223] =?UTF-8?q?fix:=20Redis=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=9E=98=EB=AA=BB=20=EC=88=98=EC=A0=95=EB=90=9C=20?= =?UTF-8?q?=EB=B6=80=EB=B6=84=20=EC=9B=90=EC=83=81=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt | 5 ++--- .../kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt | 2 +- .../com/dmforu/storage/db/redis/diet/DietEntityRepository.kt | 2 +- .../com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt index 467141d..a550ca6 100644 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt +++ b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt @@ -1,9 +1,8 @@ -package com.dmforu.storage.db.mongo.config +package com.dmforu.storage.db.redis.config import org.springframework.beans.factory.annotation.Value import org.springframework.boot.autoconfigure.domain.EntityScan -import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.cache.CacheManager import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -20,7 +19,7 @@ import java.time.Duration @Configuration @EntityScan(basePackages = ["com.dmforu.storage.db.redis"]) -@EnableRedisRepositories(basePackages = ["com.dmforu.storage.db.mongo"]) +@EnableRedisRepositories(basePackages = ["com.dmforu.storage.db.redis"]) internal class RedisConfig( @Value("\${spring.data.redis.host}") var host: String, diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt index 7a73d6c..60d5516 100644 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt +++ b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt @@ -1,4 +1,4 @@ -package com.dmforu.storage.db.mongo.diet +package com.dmforu.storage.db.redis.diet import com.dmforu.domain.diet.Diet import org.springframework.data.annotation.Id diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt index f0b2fc6..b3cf2a3 100644 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt +++ b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt @@ -1,4 +1,4 @@ -package com.dmforu.storage.db.mongo.diet +package com.dmforu.storage.db.redis.diet import com.dmforu.domain.diet.Diet import com.dmforu.domain.diet.DietRepository diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt index 52dd109..7158353 100644 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt +++ b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt @@ -1,4 +1,4 @@ -package com.dmforu.storage.db.mongo.schedule +package com.dmforu.storage.db.redis.schedule import com.dmforu.domain.schedule.Schedule import org.springframework.data.annotation.Id From 5a7c848200312d822c91f6b9aa435620272e4472 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 01:38:18 +0900 Subject: [PATCH 156/223] =?UTF-8?q?refactor:=20=ED=86=B5=ED=95=A9=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=A4=91,=20Spring=20Boot=20?= =?UTF-8?q?=EC=95=A0=ED=94=8C=EB=A6=AC=EC=BC=80=EC=9D=B4=EC=85=98=EC=9D=B4?= =?UTF-8?q?=201=EB=B2=88=EB=A7=8C=20=EC=BC=9C=EC=A7=80=EB=8F=84=EB=A1=9D?= =?UTF-8?q?=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/db/mongo/MongoApplicationTest.kt | 2 -- .../storage/db/mongo/MongoTestSupport.kt | 13 +++++++++ .../db/mongo/diet/DietEntityRepositoryTest.kt | 5 ++++ .../ScheduleEntityMongoRepositoryTest.kt | 27 +++++++------------ 4 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoTestSupport.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepositoryTest.kt diff --git a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoApplicationTest.kt b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoApplicationTest.kt index f977e92..a4f5433 100644 --- a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoApplicationTest.kt +++ b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoApplicationTest.kt @@ -1,8 +1,6 @@ package com.dmforu.storage.db.mongo import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.test.context.ActiveProfiles @SpringBootApplication -@ActiveProfiles("test") class MongoApplicationTest \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoTestSupport.kt b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoTestSupport.kt new file mode 100644 index 0000000..09ced75 --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoTestSupport.kt @@ -0,0 +1,13 @@ +package com.dmforu.storage.db.mongo + +import com.dmforu.storage.db.mongo.config.MongoConfig +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.context.annotation.Import +import org.springframework.test.context.ActiveProfiles +import org.springframework.test.context.TestPropertySource + +@TestPropertySource(properties = ["spring.config.location = src/main/resources/mongo.yml"]) +@SpringBootTest(classes = [MongoApplicationTest::class]) +@Import(MongoConfig::class) +@ActiveProfiles("test") +class MongoTestSupport \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepositoryTest.kt b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepositoryTest.kt new file mode 100644 index 0000000..30a0378 --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepositoryTest.kt @@ -0,0 +1,5 @@ +package com.dmforu.storage.db.mongo.diet + +import org.junit.jupiter.api.Assertions.* + +class DietEntityRepositoryTest \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityMongoRepositoryTest.kt b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityMongoRepositoryTest.kt index 921387c..9cebbff 100644 --- a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityMongoRepositoryTest.kt +++ b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityMongoRepositoryTest.kt @@ -2,31 +2,24 @@ package com.dmforu.storage.db.mongo.schedule import com.dmforu.domain.schedule.Schedule -import com.dmforu.storage.db.mongo.MongoApplicationTest -import com.dmforu.storage.db.mongo.config.MongoConfig +import com.dmforu.storage.db.mongo.MongoTestSupport import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.DisplayName import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.context.annotation.Import -import org.springframework.test.context.TestPropertySource import kotlin.test.Test -@TestPropertySource(properties = ["spring.config.location = src/main/resources/mongo.yml"]) -@SpringBootTest(classes = [MongoApplicationTest::class]) -@Import(MongoConfig::class) -class ScheduleEntityMongoRepositoryTest { +class ScheduleEntityMongoRepositoryTest : MongoTestSupport(){ @Autowired - private lateinit var mongoRepository: ScheduleMongoRepository + private lateinit var scheduleMongoRepository: ScheduleMongoRepository @Autowired - private lateinit var entityRepository: ScheduleEntityRepository + private lateinit var scheduleEntityRepository: ScheduleEntityRepository @AfterEach fun tearDown() { - mongoRepository.deleteAll() + scheduleMongoRepository.deleteAll() } @DisplayName("학사 일정을 저장한다.") @@ -39,10 +32,10 @@ class ScheduleEntityMongoRepositoryTest { val schedules = listOf(yearSchedule, yearSchedule) // when - entityRepository.write(schedules) + scheduleEntityRepository.write(schedules) // then - val result = mongoRepository.findAll()[0] + val result = scheduleMongoRepository.findAll()[0] assertThat(result).isNotNull assertThat(ScheduleMapper.entityToSchedules(result)).isEqualTo(schedules) @@ -57,10 +50,10 @@ class ScheduleEntityMongoRepositoryTest { val yearSchedule = Schedule.Year.of(1, listOf(monthSchedule)) val schedules = listOf(yearSchedule, yearSchedule) - mongoRepository.save(ScheduleMapper.mapToEntity(schedules)) + scheduleMongoRepository.save(ScheduleMapper.mapToEntity(schedules)) // when - val savedEntity = entityRepository.read() + val savedEntity = scheduleEntityRepository.read() assertThat(savedEntity).isNotNull assertThat(savedEntity).isEqualTo(schedules) @@ -72,7 +65,7 @@ class ScheduleEntityMongoRepositoryTest { // given // when - val savedEntity = entityRepository.read() + val savedEntity = scheduleEntityRepository.read() // then assertThat(savedEntity).isNull() From db9296ec06dc04a21c316f81ba4d48e9b4fb5485 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 01:41:41 +0900 Subject: [PATCH 157/223] =?UTF-8?q?feat:=20MongoDB=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8A=94=20Diet=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/domain/diet/Diet.kt | 23 ++++++ .../db/mongo/diet/DietEntityRepository.kt | 22 ++++++ .../storage/db/mongo/diet/DietMapper.kt | 24 +++++++ .../db/mongo/diet/DietMongoRepository.kt | 8 +++ .../db/mongo/diet/entity/DietEntity.kt | 10 +++ .../db/mongo/diet/entity/DietsEntity.kt | 11 +++ .../db/mongo/diet/DietEntityRepositoryTest.kt | 71 ++++++++++++++++++- 7 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepository.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietMapper.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietMongoRepository.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/entity/DietEntity.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/entity/DietsEntity.kt diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt index c1455bc..5bf0d2f 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt @@ -11,4 +11,27 @@ class Diet private constructor( return Diet(date, menus) } } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Diet + + if (date != other.date) return false + if (menus != other.menus) return false + + return true + } + + override fun hashCode(): Int { + var result = date.hashCode() + result = 31 * result + menus.hashCode() + return result + } + + override fun toString(): String { + return "Diet(date=$date, menus=$menus)" + } + } diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepository.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepository.kt new file mode 100644 index 0000000..51cdc9e --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepository.kt @@ -0,0 +1,22 @@ +package com.dmforu.storage.db.mongo.diet + +import com.dmforu.domain.diet.Diet +import com.dmforu.domain.diet.DietRepository +import org.springframework.stereotype.Repository +import org.springframework.transaction.annotation.Transactional + +@Repository +internal class DietEntityRepository( + private val dietRepository: DietMongoRepository, +) : DietRepository { + + @Transactional + override fun write(diets: List) { + dietRepository.deleteAll() + dietRepository.save(DietMapper.mapToEntity(diets)) + } + + override fun read(): List? { + return DietMapper.entityToDiet(dietRepository.findAll().firstOrNull()) + } +} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietMapper.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietMapper.kt new file mode 100644 index 0000000..88be88d --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietMapper.kt @@ -0,0 +1,24 @@ +package com.dmforu.storage.db.mongo.diet + +import com.dmforu.domain.diet.Diet +import com.dmforu.storage.db.mongo.diet.entity.DietEntity +import com.dmforu.storage.db.mongo.diet.entity.DietsEntity + +internal object DietMapper { + + fun mapToEntity(diets: List): DietsEntity { + return DietsEntity(diets = diets.map { toDietEntity(it) }) + } + + fun entityToDiet(dietEntity: DietsEntity?): List? { + return dietEntity?.diets?.map { toDiet(it) } + } + + private fun toDietEntity(diet: Diet): DietEntity { + return DietEntity(date = diet.date, menus = diet.menus) + } + + private fun toDiet(dietEntity: DietEntity): Diet { + return Diet.of(date = dietEntity.date, menus = dietEntity.menus) + } +} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietMongoRepository.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietMongoRepository.kt new file mode 100644 index 0000000..3415ac1 --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietMongoRepository.kt @@ -0,0 +1,8 @@ +package com.dmforu.storage.db.mongo.diet + +import com.dmforu.storage.db.mongo.diet.entity.DietsEntity +import org.springframework.data.mongodb.repository.MongoRepository +import org.springframework.stereotype.Repository + +@Repository +internal interface DietMongoRepository : MongoRepository {} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/entity/DietEntity.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/entity/DietEntity.kt new file mode 100644 index 0000000..76ae8da --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/entity/DietEntity.kt @@ -0,0 +1,10 @@ +package com.dmforu.storage.db.mongo.diet.entity + +import org.springframework.data.mongodb.core.mapping.Document +import java.time.LocalDate + +@Document(collection = "diet") +internal class DietEntity( + val date: LocalDate, + val menus: List, +) \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/entity/DietsEntity.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/entity/DietsEntity.kt new file mode 100644 index 0000000..8ae7118 --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/entity/DietsEntity.kt @@ -0,0 +1,11 @@ +package com.dmforu.storage.db.mongo.diet.entity + +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.mapping.Document + +@Document(collection = "diet_entity") +internal class DietsEntity( + @Id + val id: String? = null, + val diets: List, +) \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepositoryTest.kt b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepositoryTest.kt index 30a0378..0a4df47 100644 --- a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepositoryTest.kt +++ b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepositoryTest.kt @@ -1,5 +1,72 @@ package com.dmforu.storage.db.mongo.diet -import org.junit.jupiter.api.Assertions.* +import com.dmforu.domain.diet.Diet +import com.dmforu.storage.db.mongo.MongoTestSupport +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import java.time.LocalDate -class DietEntityRepositoryTest \ No newline at end of file + +class DietEntityRepositoryTest: MongoTestSupport(){ + + @Autowired + private lateinit var dietMongoRepository: DietMongoRepository + + @Autowired + private lateinit var dietEntityRepository: DietEntityRepository + + @AfterEach + fun tearDown() { + dietMongoRepository.deleteAll() + } + + @DisplayName("식단을 저장한다.") + @Test + fun write() { + // given + val diet1 = Diet.of(date = LocalDate.of(2024, 10, 1), menus = listOf("메뉴1, 메뉴2")) + val diet2 = Diet.of(date = LocalDate.of(2024, 10, 2), menus = listOf("메뉴3, 메뉴4")) + + // when + dietEntityRepository.write(listOf(diet1, diet2)) + + // then + val result = dietMongoRepository.findAll()[0] + + assertThat(result).isNotNull + assertThat(DietMapper.entityToDiet(result)).isEqualTo(listOf(diet1, diet2)) + } + + @DisplayName("식단을 불러온다.") + @Test + fun read() { + // given + val diet1 = Diet.of(date = LocalDate.of(2024, 10, 1), menus = listOf("메뉴1, 메뉴2")) + val diet2 = Diet.of(date = LocalDate.of(2024, 10, 2), menus = listOf("메뉴3, 메뉴4")) + val diets = listOf(diet1, diet2) + + dietMongoRepository.save(DietMapper.mapToEntity(diets)) + + // when + val savedEntity = dietEntityRepository.read() + + assertThat(savedEntity).isNotNull + assertThat(savedEntity).isEqualTo(diets) + } + + @DisplayName("식단을 불러올 때, 식단이 없다면 null을 반환한다.") + @Test + fun readWhenEmpty() { + // given + + // when + val savedEntity = dietEntityRepository.read() + + // then + assertThat(savedEntity).isNull() + } + +} From 9cdf20b1183b1c42e03aec878248b6f11a2e00dc Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 01:45:58 +0900 Subject: [PATCH 158/223] =?UTF-8?q?chore:=20jacoco=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=98=88=EC=99=B8=20=ED=8C=8C=EC=9D=BC=20=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index df71044..f79b8c0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -78,7 +78,8 @@ subprojects { "**/*Request*", "**/*Response*", "**/*Interceptor*", - "**/*Exception*" + "**/*Exception*", + "**/*TestSupport*" ) } } From 304a0fd8d671c425b8b146323b597473cc84def3 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 04:46:19 +0900 Subject: [PATCH 159/223] =?UTF-8?q?test:=20FirebaseMessageSender=20?= =?UTF-8?q?=EB=8B=A8=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DepartmentNoticeCrawlingService.kt | 1 - dmforu-infrastructure/fcm/build.gradle.kts | 2 + .../com/dmforu/fcm/FirebaseMessageSender.kt | 5 +- .../kotlin/com/dmforu/fcm/config/FCMConfig.kt | 8 +++- .../dmforu/fcm/FirebaseMessageSenderTest.kt | 48 +++++++++++++++++++ 5 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 dmforu-infrastructure/fcm/src/test/kotlin/com/dmforu/fcm/FirebaseMessageSenderTest.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index 540ea3c..5c32901 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -65,7 +65,6 @@ class DepartmentNoticeCrawlingService( } noticeWriter.write(notice) - // TODO: FCM 메세지 전송을 위한 이벤트 트리거 applicationEventPublisher.publishEvent(notice) if (notice.isLastInType()) { diff --git a/dmforu-infrastructure/fcm/build.gradle.kts b/dmforu-infrastructure/fcm/build.gradle.kts index d333b10..f1cf7f1 100644 --- a/dmforu-infrastructure/fcm/build.gradle.kts +++ b/dmforu-infrastructure/fcm/build.gradle.kts @@ -2,4 +2,6 @@ dependencies { compileOnly(project(":dmforu-domain")) implementation("com.google.firebase:firebase-admin:9.2.0") + testImplementation(project(":dmforu-domain")) + testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0") } \ No newline at end of file diff --git a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt index 2de946a..64da353 100644 --- a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt +++ b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt @@ -9,15 +9,14 @@ import org.springframework.stereotype.Component @Component internal class FirebaseMessageSender( private val firebaseMessageConverter: FirebaseMessageConverter, + private val firebaseMessaging: FirebaseMessaging, ) : MessageSender { override fun sendNoticeMessage(message: NoticeMessage, tokens: List) { val firebaseMessage = firebaseMessageConverter.buildMessageToNotice(message, tokens) - val firebaseApp = FirebaseApp.getInstance("DMFORU_APP_PROD") - FirebaseMessaging.getInstance(firebaseApp).sendEachForMulticast(firebaseMessage) + firebaseMessaging.sendEachForMulticast(firebaseMessage) } - } \ No newline at end of file diff --git a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt index 9dd7846..74ab63e 100644 --- a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt +++ b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt @@ -3,14 +3,13 @@ package com.dmforu.fcm.config import com.google.auth.oauth2.GoogleCredentials import com.google.firebase.FirebaseApp import com.google.firebase.FirebaseOptions -import org.springframework.boot.autoconfigure.domain.EntityScan +import com.google.firebase.messaging.FirebaseMessaging import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.core.io.ClassPathResource import java.io.IOException @Configuration -@EntityScan(basePackages = ["com.dmforu.fcm"]) internal class FCMConfig { @Bean @Throws(IOException::class) @@ -24,4 +23,9 @@ internal class FCMConfig { return FirebaseApp.initializeApp(options, "DMFORU_APP_PROD") } + + @Bean + fun firebaseMessaging(firebaseApp: FirebaseApp): FirebaseMessaging { + return FirebaseMessaging.getInstance(FirebaseApp.getInstance("DMFORU_APP_PROD")) + } } \ No newline at end of file diff --git a/dmforu-infrastructure/fcm/src/test/kotlin/com/dmforu/fcm/FirebaseMessageSenderTest.kt b/dmforu-infrastructure/fcm/src/test/kotlin/com/dmforu/fcm/FirebaseMessageSenderTest.kt new file mode 100644 index 0000000..d4d2fbf --- /dev/null +++ b/dmforu-infrastructure/fcm/src/test/kotlin/com/dmforu/fcm/FirebaseMessageSenderTest.kt @@ -0,0 +1,48 @@ +package com.dmforu.fcm + +import com.dmforu.domain.message.NoticeMessage +import com.google.firebase.messaging.FirebaseMessaging +import com.google.firebase.messaging.MulticastMessage +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.eq + +@ExtendWith(MockitoExtension::class) +class FirebaseMessageSenderTest { + + @Mock + private lateinit var firebaseMessageConverter: FirebaseMessageConverter + + @Mock + private lateinit var firebaseMessaging: FirebaseMessaging + + @InjectMocks + private lateinit var messageSender: FirebaseMessageSender + + @DisplayName("공지를 푸시 알림으로 전송한다.") + @Test + fun sendNoticeMessage() { + // given + val message = mock(NoticeMessage::class.java) + val multicastMessage = mock(MulticastMessage::class.java) + val tokens = listOf("토큰1", "토큰2") + + given(firebaseMessageConverter.buildMessageToNotice(eq(message), eq(tokens))).willReturn(multicastMessage) + + // when + messageSender.sendNoticeMessage(message, tokens) + + // then + verify(firebaseMessageConverter).buildMessageToNotice(message, tokens) + verify(firebaseMessaging).sendEachForMulticast(multicastMessage) + } +} \ No newline at end of file From 87cad56dcdd2b6d9f6b6c58993d50b1a0030286a Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 05:05:01 +0900 Subject: [PATCH 160/223] =?UTF-8?q?test:=20MockBean=EC=9D=84=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=9C=20Crawling=20Scheduler=20=ED=86=B5=ED=95=A9?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/scheduler/CrawlingScheduler.kt | 10 ++-- .../DepartmentNoticeCrawlingService.kt | 2 +- .../scheduler/crawling/DietCrawlingService.kt | 2 +- .../crawling/ScheduleCrawlingService.kt | 2 +- .../UniversityNoticeCrawlingService.kt | 2 +- .../admin/scheduler/CrawlingSchedulerTest.kt | 54 +++++++++++++++++++ 6 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/CrawlingSchedulerTest.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/CrawlingScheduler.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/CrawlingScheduler.kt index 471aeb2..6c7ef65 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/CrawlingScheduler.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/CrawlingScheduler.kt @@ -16,13 +16,13 @@ class CrawlingScheduler ( ) { @Scheduled(cron = "0 */10 9-19 * * MON-FRI") fun noticeCrawling() { - departmentNoticeCrawlingService.crawling() - universityNoticeCrawlingService.crawling() + departmentNoticeCrawlingService.addRecentDepartmentNotice() + universityNoticeCrawlingService.addRecnetUniversityNotice() } @Scheduled(cron = "0 0 8,20 * * *") - fun dietCrawling() { - dietCrawlingService.overwriteToRedis() - scheduleCrawlingService.overwriteToRedis() + fun dietAndScheduleCrawling() { + dietCrawlingService.updateToRecentDiet() + scheduleCrawlingService.updateToRecentSchedule() } } \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index 5c32901..548bb2e 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -18,7 +18,7 @@ class DepartmentNoticeCrawlingService( * 데이터베이스에 저장된 공지사항이 존재한다면, 최신 공지사항만 크롤링하여 업데이트 한다.

* 평일 오전 10시, 오후 17시 자동으로 메서드를 실행한다. */ - fun crawling() { + fun addRecentDepartmentNotice() { for (major in Major.entries) { crawlMajorDepartment(major) } diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt index 5239e0f..134bc7f 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingService.kt @@ -9,7 +9,7 @@ class DietCrawlingService( private val dietParser: DietParser, private val dietWriter: DietWriter, ) { - fun overwriteToRedis() { + fun updateToRecentDiet() { dietWriter.overwrite(dietParser.parse()) } } \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt index de1e45d..17a45e4 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingService.kt @@ -10,7 +10,7 @@ class ScheduleCrawlingService( private val scheduleParser: ScheduleParser, private val scheduleWriter: ScheduleWriter, ) { - fun overwriteToRedis() { + fun updateToRecentSchedule() { scheduleWriter.overwrite(scheduleParser.parse(LocalDate.now().year)) } } \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt index 5b9f049..5d1d0f4 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt @@ -21,7 +21,7 @@ class UniversityNoticeCrawlingService( * 데이터베이스에 저장된 공지사항이 존재한다면, 최신 공지사항만 크롤링하여 업데이트 한다.

* 평일 오전 10시, 오후 17시 자동으로 메서드를 실행한다. */ - fun crawling() { + fun addRecnetUniversityNotice() { val parser: UniversityNoticeParser = prototypeBeanProvider.getObject() val maxNumber: Int? = noticeReader.findMaxNumberByType("대학") val currentMaxNumber = maxNumber ?: 0 diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/CrawlingSchedulerTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/CrawlingSchedulerTest.kt new file mode 100644 index 0000000..696584d --- /dev/null +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/CrawlingSchedulerTest.kt @@ -0,0 +1,54 @@ +package com.dmforu.admin.scheduler + +import com.dmforu.admin.scheduler.crawling.DepartmentNoticeCrawlingService +import com.dmforu.admin.scheduler.crawling.DietCrawlingService +import com.dmforu.admin.scheduler.crawling.ScheduleCrawlingService +import com.dmforu.admin.scheduler.crawling.UniversityNoticeCrawlingService +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.mockito.Mockito.verify +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.mock.mockito.MockBean + +@SpringBootTest +class CrawlingSchedulerTest { + + @Autowired + private lateinit var crawlingScheduler: CrawlingScheduler + + @MockBean + private lateinit var departmentNoticeCrawlingService: DepartmentNoticeCrawlingService + + @MockBean + private lateinit var universityNoticeCrawlingService: UniversityNoticeCrawlingService + + @MockBean + private lateinit var dietCrawlingService: DietCrawlingService + + @MockBean + private lateinit var scheduleCrawlingService: ScheduleCrawlingService + + @DisplayName("대학 공지와 학과 공지를 크롤링하고 최신 정보를 추가한다.") + @Test + fun noticeCrawling() { + // when + crawlingScheduler.noticeCrawling() + + // then + verify(departmentNoticeCrawlingService).addRecentDepartmentNotice() + verify(universityNoticeCrawlingService).addRecnetUniversityNotice() + } + + @DisplayName("식단과 학사 일정을 크롤링하고 최신 정보로 업데이트한다.") + @Test + fun dietAndScheduleCrawling() { + // when + crawlingScheduler.dietAndScheduleCrawling() + + // then + verify(dietCrawlingService).updateToRecentDiet() + verify(scheduleCrawlingService).updateToRecentSchedule() + } + +} \ No newline at end of file From 3a80e0153466a6b8100c4205b52b3e2021f1a15e Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:51:18 +0900 Subject: [PATCH 161/223] =?UTF-8?q?test:=20Mock=EC=9D=84=20=EC=A3=BC?= =?UTF-8?q?=EC=9E=85=ED=95=98=EC=97=AC=20=ED=96=89=EB=8F=99=EC=9D=84=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=ED=95=98=EB=8A=94=20=EB=8B=A8=EC=9C=84=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/admin/AdminApplicationTests.kt | 13 ----------- .../admin/message/NoticeListenerTest.kt | 5 ++++ .../admin/scheduler/CrawlingSchedulerTest.kt | 23 ++++++++++--------- 3 files changed, 17 insertions(+), 24 deletions(-) delete mode 100644 dmforu-admin/src/test/kotlin/com/dmforu/admin/AdminApplicationTests.kt create mode 100644 dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/AdminApplicationTests.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/AdminApplicationTests.kt deleted file mode 100644 index e0ba44b..0000000 --- a/dmforu-admin/src/test/kotlin/com/dmforu/admin/AdminApplicationTests.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.dmforu.admin - -import org.junit.jupiter.api.Test -import org.springframework.boot.test.context.SpringBootTest - -@SpringBootTest -class AdminApplicationTests { - - @Test - fun contextLoads() { - } - -} diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt new file mode 100644 index 0000000..0213fca --- /dev/null +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt @@ -0,0 +1,5 @@ +package com.dmforu.admin.message + +import org.junit.jupiter.api.Assertions.* + +class NoticeListenerTest \ No newline at end of file diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/CrawlingSchedulerTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/CrawlingSchedulerTest.kt index 696584d..1658764 100644 --- a/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/CrawlingSchedulerTest.kt +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/CrawlingSchedulerTest.kt @@ -6,29 +6,30 @@ import com.dmforu.admin.scheduler.crawling.ScheduleCrawlingService import com.dmforu.admin.scheduler.crawling.UniversityNoticeCrawlingService import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock import org.mockito.Mockito.verify -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.boot.test.mock.mockito.MockBean +import org.mockito.junit.jupiter.MockitoExtension -@SpringBootTest +@ExtendWith(MockitoExtension::class) class CrawlingSchedulerTest { - @Autowired - private lateinit var crawlingScheduler: CrawlingScheduler - - @MockBean + @Mock private lateinit var departmentNoticeCrawlingService: DepartmentNoticeCrawlingService - @MockBean + @Mock private lateinit var universityNoticeCrawlingService: UniversityNoticeCrawlingService - @MockBean + @Mock private lateinit var dietCrawlingService: DietCrawlingService - @MockBean + @Mock private lateinit var scheduleCrawlingService: ScheduleCrawlingService + @InjectMocks + private lateinit var crawlingScheduler: CrawlingScheduler + @DisplayName("대학 공지와 학과 공지를 크롤링하고 최신 정보를 추가한다.") @Test fun noticeCrawling() { From 322ac0e12868da0813fd31dc861f85fc66f9501e Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:52:40 +0900 Subject: [PATCH 162/223] =?UTF-8?q?test:=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=EB=84=88=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/message/NoticeListenerTest.kt | 32 ++++++++++++++++++- .../dmforu/fcm/FirebaseMessageConverter.kt | 1 - .../kotlin/com/dmforu/fcm/config/FCMConfig.kt | 3 +- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt index 0213fca..fc6537a 100644 --- a/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt @@ -1,5 +1,35 @@ package com.dmforu.admin.message +import com.dmforu.domain.notice.Notice import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.context.ApplicationEventPublisher -class NoticeListenerTest \ No newline at end of file +@SpringBootTest(classes = [NoticeListener::class]) +class NoticeListenerTest { + + @Autowired + private lateinit var eventPublisher: ApplicationEventPublisher + + @MockBean + private lateinit var messageService: MessageService + + @DisplayName("notice 이벤트가 발생하면, 푸시 알림을 전송한다.") + @Test + fun onNoticeMessageSendEventHandler() { + // given + val notice = mock(Notice::class.java) + + // when + eventPublisher.publishEvent(notice) + + // then + verify(messageService).sendNoticeMessage(notice) + } +} \ No newline at end of file diff --git a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt index 321110f..56fa160 100644 --- a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt +++ b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt @@ -22,5 +22,4 @@ internal class FirebaseMessageConverter { .build() } - } \ No newline at end of file diff --git a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt index 74ab63e..01ddb0c 100644 --- a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt +++ b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt @@ -25,7 +25,8 @@ internal class FCMConfig { } @Bean - fun firebaseMessaging(firebaseApp: FirebaseApp): FirebaseMessaging { + fun firebaseMessaging(): FirebaseMessaging { return FirebaseMessaging.getInstance(FirebaseApp.getInstance("DMFORU_APP_PROD")) } + } \ No newline at end of file From 57d4d5f9432ee616fa4eea62b6b99428df2d967a Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:58:40 +0900 Subject: [PATCH 163/223] =?UTF-8?q?refactor:=20FCM=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EB=B9=88=20=EC=88=9C=EC=84=9C=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt | 2 +- .../fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt index fc6537a..933fe26 100644 --- a/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt @@ -11,7 +11,7 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.context.ApplicationEventPublisher -@SpringBootTest(classes = [NoticeListener::class]) +@SpringBootTest class NoticeListenerTest { @Autowired diff --git a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt index 01ddb0c..79089c6 100644 --- a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt +++ b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/config/FCMConfig.kt @@ -6,6 +6,7 @@ import com.google.firebase.FirebaseOptions import com.google.firebase.messaging.FirebaseMessaging import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.DependsOn import org.springframework.core.io.ClassPathResource import java.io.IOException @@ -25,6 +26,7 @@ internal class FCMConfig { } @Bean + @DependsOn("someAppProdFirebaseApp") fun firebaseMessaging(): FirebaseMessaging { return FirebaseMessaging.getInstance(FirebaseApp.getInstance("DMFORU_APP_PROD")) } From 1699fc6f714619993d3eb98f8e79f6486b7cd95c Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 18:43:36 +0900 Subject: [PATCH 164/223] =?UTF-8?q?test:=20Department=20Notice=20Crawling?= =?UTF-8?q?=20Service=20=EB=8B=A8=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/build.gradle.kts | 2 + .../DepartmentNoticeCrawlingService.kt | 33 +------- .../admin/scheduler/crawling/NoticeService.kt | 30 +++++++ .../DepartmentNoticeCrawlingServiceTest.kt | 82 +++++++++++++++++++ 4 files changed, 117 insertions(+), 30 deletions(-) create mode 100644 dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/NoticeService.kt create mode 100644 dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingServiceTest.kt diff --git a/dmforu-admin/build.gradle.kts b/dmforu-admin/build.gradle.kts index 2f0c9e3..938f4ca 100644 --- a/dmforu-admin/build.gradle.kts +++ b/dmforu-admin/build.gradle.kts @@ -13,4 +13,6 @@ dependencies { runtimeOnly(project(":dmforu-infrastructure:fcm")) runtimeOnly(project(":dmforu-infrastructure:storage:db-mysql")) runtimeOnly(project(":dmforu-infrastructure:storage:mongo")) + + testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0") } \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index 548bb2e..7ada9ab 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -9,9 +9,8 @@ import org.springframework.stereotype.Service @Service class DepartmentNoticeCrawlingService( private val prototypeBeanProvider: ObjectProvider, - private val applicationEventPublisher: ApplicationEventPublisher, private val noticeReader: NoticeReader, - private val noticeWriter: NoticeWriter, + private val noticeService: NoticeService ) { /** * Major 열거형의 모든 값을 반복하여 모든 학과의 공지사항을 크롤링한다.

@@ -35,12 +34,12 @@ class DepartmentNoticeCrawlingService( private fun crawlMajorDepartment(major: Major) { val parser = prototypeBeanProvider.getObject() - val maxNumber: Int? = noticeReader.findMaxNumberByType(major.type) + val maxNumber = noticeReader.findMaxNumberByType(major.type) val currentMaxNumber = maxNumber ?: 0 while (true) { val notices: List = parser.parse(major) - val isNewNoticeFound = saveNewNotices(notices, currentMaxNumber) + val isNewNoticeFound = noticeService.saveNewNotices(notices, currentMaxNumber) if (!isNewNoticeFound) { return @@ -48,30 +47,4 @@ class DepartmentNoticeCrawlingService( } } - /** - * 새로운 학과 공지사항을 저장한다.

- * 데이터베이스에 저장된 최신 공지사항 번호보다 큰 번호를 가진 학과 공지사항을 저장한다.

- * 데이터베이스에 저장된 공지사항이 존재하지 않아 currentMaxNumber가 0이라면 게시글의 번호가 1번이 될 때 까지 저장한다.

- * 위의 조건을 만족하기 전까지 true를 반환하고, 만족하게 되면 false를 반환한다. - * - * @param notices 저장할 학과의 공지사항 목록 - * @param currentMaxNumber 현재 데이터베이스에 저장된 최신 공지사항의 번호 - * @return 저장이 성공했다면 true, 그렇지 않다면 false - */ - private fun saveNewNotices(notices: List, currentMaxNumber: Int): Boolean { - for (notice in notices) { - if (notice.isNumberLessThanOrEqualTo(currentMaxNumber)) { - return false - } - - noticeWriter.write(notice) - applicationEventPublisher.publishEvent(notice) - - if (notice.isLastInType()) { - return false - } - } - - return true - } } diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/NoticeService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/NoticeService.kt new file mode 100644 index 0000000..0142d0e --- /dev/null +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/NoticeService.kt @@ -0,0 +1,30 @@ +package com.dmforu.admin.scheduler.crawling + +import com.dmforu.domain.notice.Notice +import com.dmforu.domain.notice.NoticeWriter +import org.springframework.context.ApplicationEventPublisher +import org.springframework.stereotype.Component + +@Component +class NoticeService( + private val applicationEventPublisher: ApplicationEventPublisher, + private val noticeWriter: NoticeWriter, +) { + + fun saveNewNotices(notices: List, currentMaxNumber: Int): Boolean { + for (notice in notices) { + if (notice.isNumberLessThanOrEqualTo(currentMaxNumber)) { + return false + } + + noticeWriter.write(notice) + applicationEventPublisher.publishEvent(notice) + + if (notice.isLastInType()) { + return false + } + } + + return true + } +} \ No newline at end of file diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingServiceTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingServiceTest.kt new file mode 100644 index 0000000..c42895c --- /dev/null +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingServiceTest.kt @@ -0,0 +1,82 @@ +package com.dmforu.admin.scheduler.crawling + +import com.dmforu.crawling.parser.DepartmentNoticeParser +import com.dmforu.domain.notice.Major +import com.dmforu.domain.notice.Notice +import com.dmforu.domain.notice.NoticeReader +import com.dmforu.domain.notice.NoticeWriter +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.* +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.springframework.beans.factory.ObjectProvider +import org.springframework.context.ApplicationEventPublisher + +@ExtendWith(MockitoExtension::class) +class DepartmentNoticeCrawlingServiceTest { + + @Mock + lateinit var departmentNoticeParser: DepartmentNoticeParser + + @Mock + lateinit var noticeReader: NoticeReader + + @Mock + lateinit var noticeService: NoticeService + + @Mock + lateinit var prototypeBeanProvider: ObjectProvider + + @InjectMocks + lateinit var service: DepartmentNoticeCrawlingService + + @DisplayName("학과별 공지사항을 크롤링하고, 새로운 공지사항이 있을 경우 저장한다.") + @Test + fun addRecentDepartmentNotice() { + // given + val notices = listOf( + mock(Notice::class.java), + mock(Notice::class.java), + ) + + given(prototypeBeanProvider.getObject()).willReturn(departmentNoticeParser) + given(noticeReader.findMaxNumberByType(any())).willReturn(1) + given(noticeService.saveNewNotices(any(), any())).willReturn(false) + given(departmentNoticeParser.parse(any())).willReturn(notices) + + // when + service.addRecentDepartmentNotice() + + // then + verify(prototypeBeanProvider, times(Major.entries.size)).getObject() + verify(noticeReader, times(Major.entries.size)).findMaxNumberByType(any()) +} + +// @Test +// fun `현재 최대 번호보다 작거나 같은 공지사항은 저장되지 않아야 한다`() { +// // Given +// val major = Major.COMPUTER_SCIENCE // 예시 학과 +// val notices = listOf( +// Notice(1, "오래된 공지사항", major) // 이 공지사항은 새로운 것이 아님 +// ) +// +// // 모킹된 동작 설정 +// every { prototypeBeanProvider.getObject() } returns departmentNoticeParser +// every { noticeReader.findMaxNumberByType(major.type) } returns 1 +// every { departmentNoticeParser.parse(major) } returns notices +// +// // When +// service.addRecentDepartmentNotice() +// +// // Then +// verify { noticeReader.findMaxNumberByType(major.type) } +// verify(exactly = 0) { noticeWriter.write(any()) } // 저장이 발생하지 않아야 함 +// } + +} \ No newline at end of file From 8895925cdea444fda48075828dbaba5bef85399a Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 19:44:39 +0900 Subject: [PATCH 165/223] =?UTF-8?q?test:=20Notice=20Service=20=EB=8B=A8?= =?UTF-8?q?=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/scheduler/CrawlingScheduler.kt | 2 +- .../DepartmentNoticeCrawlingService.kt | 14 +-- .../UniversityNoticeCrawlingService.kt | 42 +-------- .../admin/scheduler/CrawlingSchedulerTest.kt | 2 +- .../scheduler/crawling/NoticeServiceTest.kt | 85 +++++++++++++++++++ 5 files changed, 92 insertions(+), 53 deletions(-) create mode 100644 dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/NoticeServiceTest.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/CrawlingScheduler.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/CrawlingScheduler.kt index 6c7ef65..4ea7e27 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/CrawlingScheduler.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/CrawlingScheduler.kt @@ -17,7 +17,7 @@ class CrawlingScheduler ( @Scheduled(cron = "0 */10 9-19 * * MON-FRI") fun noticeCrawling() { departmentNoticeCrawlingService.addRecentDepartmentNotice() - universityNoticeCrawlingService.addRecnetUniversityNotice() + universityNoticeCrawlingService.addRecentUniversityNotice() } @Scheduled(cron = "0 0 8,20 * * *") diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt index 7ada9ab..b17a3f9 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingService.kt @@ -12,25 +12,13 @@ class DepartmentNoticeCrawlingService( private val noticeReader: NoticeReader, private val noticeService: NoticeService ) { - /** - * Major 열거형의 모든 값을 반복하여 모든 학과의 공지사항을 크롤링한다.

- * 데이터베이스에 저장된 공지사항이 존재한다면, 최신 공지사항만 크롤링하여 업데이트 한다.

- * 평일 오전 10시, 오후 17시 자동으로 메서드를 실행한다. - */ + fun addRecentDepartmentNotice() { for (major in Major.entries) { crawlMajorDepartment(major) } } - /** - * 해당 학과의 모든 공지사항을 크롤링한다.

- * 공지사항 첫번째 페이지부터 크롤링을 시작한다.

- * 데이터베이스에 저장된 공지사항의 가장 최신 번호와, 파싱된 공지사항 목록을 saveNewNotices 메서드를 통해 저장할지 결정한다.

- * 만일, 저장이 이뤄지지 않는다면 더이상 파싱할 필요가 없기 때문에 무한 루트에서 빠져나온다.

- * - * @param major 학과 정보 - */ private fun crawlMajorDepartment(major: Major) { val parser = prototypeBeanProvider.getObject() diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt index 5d1d0f4..d78003a 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingService.kt @@ -3,62 +3,28 @@ package com.dmforu.admin.scheduler.crawling import com.dmforu.crawling.parser.UniversityNoticeParser import com.dmforu.domain.notice.Notice import com.dmforu.domain.notice.NoticeReader -import com.dmforu.domain.notice.NoticeWriter import org.springframework.beans.factory.ObjectProvider -import org.springframework.context.ApplicationEventPublisher import org.springframework.stereotype.Service @Service class UniversityNoticeCrawlingService( private val prototypeBeanProvider: ObjectProvider, - private val applicationEventPublisher: ApplicationEventPublisher, + private val noticeService: NoticeService, private val noticeReader: NoticeReader, - private val noticeWriter: NoticeWriter, ) { - /** - * 모든 대학 공지사항을 크롤링한다.

- * 데이터베이스에 저장된 공지사항이 존재한다면, 최신 공지사항만 크롤링하여 업데이트 한다.

- * 평일 오전 10시, 오후 17시 자동으로 메서드를 실행한다. - */ - fun addRecnetUniversityNotice() { + + fun addRecentUniversityNotice() { val parser: UniversityNoticeParser = prototypeBeanProvider.getObject() val maxNumber: Int? = noticeReader.findMaxNumberByType("대학") val currentMaxNumber = maxNumber ?: 0 while (true) { val departmentNotices: List = parser.parse() - val isNewNoticeFound = saveNewNotices(departmentNotices, currentMaxNumber) + val isNewNoticeFound = noticeService.saveNewNotices(departmentNotices, currentMaxNumber) if (!isNewNoticeFound) { return } } } - - /** - * 새로운 대학 공지사항을 저장한다.

- * 데이터베이스에 저장된 최신 공지사항 번호보다 큰 번호를 가진 학과 공지사항을 저장한다.

- * 데이터베이스에 저장된 공지사항이 존재하지 않아 currentMaxNumber가 0이라면 게시글의 번호가 1번이 될 때 까지 저장한다.

- * 위의 조건을 만족하기 전까지 true를 반환하고, 만족하게 되면 false를 반환한다. - * - * @param notices 저장할 대학 공지사항 목록 - * @param currentMaxNumber 현재 데이터베이스에 저장된 최신 공지사항의 번호 - * @return 저장에 성공했다면 true, 그렇지 않다면 false - */ - private fun saveNewNotices(notices: List, currentMaxNumber: Int): Boolean { - for (notice in notices) { - if (notice.isNumberLessThanOrEqualTo(currentMaxNumber)) { - return false - } - - noticeWriter.write(notice) - applicationEventPublisher.publishEvent(notice) - - if (notice.isLastInType()) { - return false - } - } - - return true - } } \ No newline at end of file diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/CrawlingSchedulerTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/CrawlingSchedulerTest.kt index 1658764..bde304b 100644 --- a/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/CrawlingSchedulerTest.kt +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/CrawlingSchedulerTest.kt @@ -38,7 +38,7 @@ class CrawlingSchedulerTest { // then verify(departmentNoticeCrawlingService).addRecentDepartmentNotice() - verify(universityNoticeCrawlingService).addRecnetUniversityNotice() + verify(universityNoticeCrawlingService).addRecentUniversityNotice() } @DisplayName("식단과 학사 일정을 크롤링하고 최신 정보로 업데이트한다.") diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/NoticeServiceTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/NoticeServiceTest.kt new file mode 100644 index 0000000..5b2186f --- /dev/null +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/NoticeServiceTest.kt @@ -0,0 +1,85 @@ +package com.dmforu.admin.scheduler.crawling + +import com.dmforu.domain.notice.Notice +import com.dmforu.domain.notice.NoticeWriter +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.* +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.springframework.context.ApplicationEventPublisher + +@ExtendWith(MockitoExtension::class) +class NoticeServiceTest { + + @Mock + private lateinit var applicationEventPublisher: ApplicationEventPublisher + + @Mock + private lateinit var noticeWriter: NoticeWriter + + @InjectMocks + private lateinit var noticeService: NoticeService + + @DisplayName("신규 공지를 저장하며, 이벤트를 발행한다. 정상적으로 처리가 되었다면 True를 반환한다.") + @Test + fun saveNewNotices() { + // given + val notice = mock(Notice::class.java) + val notices = listOf(notice, notice) + + given(notice.isNumberLessThanOrEqualTo(any())).willReturn(false) + given(notice.isLastInType()).willReturn(false) + + // when + val result = noticeService.saveNewNotices(notices, 0) + + // then + assertThat(result).isTrue() + verify(noticeWriter, times(notices.size)).write(notice) + verify(applicationEventPublisher, times(notices.size)).publishEvent(notice) + } + + @DisplayName("신규 공지가 아닌 경우, False을 반환한다.") + @Test + fun saveNewNoticesWhenLegacyNotice() { + // given + val notice = mock(Notice::class.java) + val notices = listOf(notice, notice) + + given(notice.isNumberLessThanOrEqualTo(any())).willReturn(true) + + // when + val result = noticeService.saveNewNotices(notices, 0) + + // then + assertThat(result).isFalse() + } + + @DisplayName("가장 최초의 공지인 경우, 공지를 저장하며, 이벤트를 발행한다. 결과는 False를 반환한다.") + @Test + fun saveNewNoticesWhenLastNotice() { + // given + val notice = mock(Notice::class.java) + val notices = listOf(notice, notice) + + given(notice.isNumberLessThanOrEqualTo(any())).willReturn(false) + given(notice.isLastInType()).willReturn(true) + + // when + val result = noticeService.saveNewNotices(notices, 0) + + // then + assertThat(result).isFalse() + verify(noticeWriter).write(notice) + verify(applicationEventPublisher).publishEvent(notice) + } + + +} \ No newline at end of file From f58a1b45281d180a065f1714a8e3522bb4828d13 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 19:54:55 +0900 Subject: [PATCH 166/223] =?UTF-8?q?test=20University=20Notice=20Crawling?= =?UTF-8?q?=20Service=20=EB=8B=A8=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DepartmentNoticeCrawlingServiceTest.kt | 23 +------- .../UniversityNoticeCrawlingServiceTest.kt | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+), 22 deletions(-) create mode 100644 dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingServiceTest.kt diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingServiceTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingServiceTest.kt index c42895c..b661821 100644 --- a/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingServiceTest.kt +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/DepartmentNoticeCrawlingServiceTest.kt @@ -56,27 +56,6 @@ class DepartmentNoticeCrawlingServiceTest { // then verify(prototypeBeanProvider, times(Major.entries.size)).getObject() verify(noticeReader, times(Major.entries.size)).findMaxNumberByType(any()) -} - -// @Test -// fun `현재 최대 번호보다 작거나 같은 공지사항은 저장되지 않아야 한다`() { -// // Given -// val major = Major.COMPUTER_SCIENCE // 예시 학과 -// val notices = listOf( -// Notice(1, "오래된 공지사항", major) // 이 공지사항은 새로운 것이 아님 -// ) -// -// // 모킹된 동작 설정 -// every { prototypeBeanProvider.getObject() } returns departmentNoticeParser -// every { noticeReader.findMaxNumberByType(major.type) } returns 1 -// every { departmentNoticeParser.parse(major) } returns notices -// -// // When -// service.addRecentDepartmentNotice() -// -// // Then -// verify { noticeReader.findMaxNumberByType(major.type) } -// verify(exactly = 0) { noticeWriter.write(any()) } // 저장이 발생하지 않아야 함 -// } + } } \ No newline at end of file diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingServiceTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingServiceTest.kt new file mode 100644 index 0000000..51cbe39 --- /dev/null +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/UniversityNoticeCrawlingServiceTest.kt @@ -0,0 +1,58 @@ +package com.dmforu.admin.scheduler.crawling + +import com.dmforu.crawling.parser.UniversityNoticeParser +import com.dmforu.domain.notice.Notice +import com.dmforu.domain.notice.NoticeReader +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.* +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.springframework.beans.factory.ObjectProvider + +@ExtendWith(MockitoExtension::class) +class UniversityNoticeCrawlingServiceTest { + + @Mock + lateinit var universityNoticeParser: UniversityNoticeParser + + @Mock + lateinit var noticeReader: NoticeReader + + @Mock + lateinit var noticeService: NoticeService + + @Mock + lateinit var prototypeBeanProvider: ObjectProvider + + @InjectMocks + lateinit var service: UniversityNoticeCrawlingService + + @DisplayName("대학 공지사항을 크롤링하고, 새로운 공지사항이 있을 경우 저장한다.") + @Test + fun addRecentUniversityNotice() { + // given + val notices = listOf( + mock(Notice::class.java), + mock(Notice::class.java), + ) + + given(prototypeBeanProvider.getObject()).willReturn(universityNoticeParser) + given(noticeReader.findMaxNumberByType(any())).willReturn(1) + given(noticeService.saveNewNotices(any(), any())).willReturn(false) + given(universityNoticeParser.parse()).willReturn(notices) + + // when + service.addRecentUniversityNotice() + + // then + verify(prototypeBeanProvider).getObject() + verify(noticeReader).findMaxNumberByType(any()) + } + +} \ No newline at end of file From 5a271e8750fb0aca463cd8c087cc0d7451b41ab7 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 20:30:33 +0900 Subject: [PATCH 167/223] =?UTF-8?q?test:=20Message=20Service=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/admin/message/KeywordFilter.kt | 28 ++++ .../dmforu/admin/message/MessageService.kt | 23 +-- .../admin/message/MessageServiceTest.kt | 157 ++++++++++++++++++ 3 files changed, 189 insertions(+), 19 deletions(-) create mode 100644 dmforu-admin/src/main/kotlin/com/dmforu/admin/message/KeywordFilter.kt create mode 100644 dmforu-admin/src/test/kotlin/com/dmforu/admin/message/MessageServiceTest.kt diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/KeywordFilter.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/KeywordFilter.kt new file mode 100644 index 0000000..964edaa --- /dev/null +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/KeywordFilter.kt @@ -0,0 +1,28 @@ +package com.dmforu.admin.message + +import com.dmforu.domain.message.Keywords +import org.springframework.stereotype.Component + +@Component +class KeywordFilter { + + fun extractKeywordFrom(title: String): String? { + Keywords.entries.forEach { + if (title.contains(it.korean)) { + return it.korean + } + } + + val whiteSpaceRemovedTitle = title.replace(" ", "") + if (whiteSpaceRemovedTitle.contains("중간고사")) { + return "시험" + } + + if (whiteSpaceRemovedTitle.contains("기말고사")) { + return "시험" + } + + return null + } + +} \ No newline at end of file diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt index 9269f67..e539c75 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/MessageService.kt @@ -1,6 +1,5 @@ package com.dmforu.admin.message -import com.dmforu.domain.message.Keywords import com.dmforu.domain.message.MessageSender import com.dmforu.domain.message.NoticeMessage import com.dmforu.domain.notice.Notice @@ -10,19 +9,22 @@ import org.springframework.stereotype.Service @Service class MessageService( private val subscribeReader: SubscribeReader, + private val keywordFilter: KeywordFilter, private val messageSender: MessageSender, ) { fun sendNoticeMessage(notice: Notice) { if (notice.isUniversityNotice()) { sendUniversityNoticeMessage(notice) + + return } sendDepartmentNoticeMessage(notice) } private fun sendUniversityNoticeMessage(notice: Notice) { - val keyword = keywordFilter(notice.title) ?: return + val keyword = keywordFilter.extractKeywordFrom(notice.title) ?: return val tokens = subscribeReader.getTokensBySubscribedToKeyword(keyword = keyword) @@ -47,22 +49,5 @@ class MessageService( messageSender.sendNoticeMessage(message = message, tokens = tokens) } - private fun keywordFilter(title: String): String? { - Keywords.entries.forEach { - if (title.contains(it.korean)) { - return it.korean - } - } - - val whiteSpaceRemovedTitle = title.replace(" ", "") - if (whiteSpaceRemovedTitle.contains("중간고사")) { - return "시험" - } - - if (whiteSpaceRemovedTitle.contains("기말고사")) { - return "시험" - } - return null - } } \ No newline at end of file diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/MessageServiceTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/MessageServiceTest.kt new file mode 100644 index 0000000..869d29f --- /dev/null +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/MessageServiceTest.kt @@ -0,0 +1,157 @@ +package com.dmforu.admin.message + +import com.dmforu.domain.message.MessageSender +import com.dmforu.domain.notice.Notice +import com.dmforu.domain.subscribe.SubscribeReader +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import java.time.LocalDate + +@ExtendWith(MockitoExtension::class) +class MessageServiceTest { + + @Mock + private lateinit var keywordFilter: KeywordFilter + + @Mock + private lateinit var subscribeReader: SubscribeReader + + @Mock + private lateinit var messageSender: MessageSender + + @InjectMocks + private lateinit var messageService: MessageService + + @DisplayName("대학 공지사항은 키워드를 추출하고, 키워드에 해당하는 토큰을 불러와 푸시 알림을 전송한다.") + @Test + fun sendUniversityNoticeMessage() { + // given + val universityNotice = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 10), + title = "중간고사 안내", + author = "저자", + url = "http://test.com", + ) + + val tokens = listOf("토큰1", "토큰2") + + given(keywordFilter.extractKeywordFrom(universityNotice.title)).willReturn("시험") + given(subscribeReader.getTokensBySubscribedToKeyword(any())).willReturn(tokens) + + // when + messageService.sendNoticeMessage(universityNotice) + + // then + verify(messageSender).sendNoticeMessage(any(), eq(tokens)) + } + + @DisplayName("키워드에 해당하지 않는 경우, 푸시 알림을 전송하지 않는다.") + @Test + fun sendUniversityNoticeMessageWithoutKeyword() { + // given + val universityNotice = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 10), + title = "제목", + author = "저자", + url = "http://test.com", + ) + + val tokens = listOf("토큰1", "토큰2") + + given(keywordFilter.extractKeywordFrom(universityNotice.title)).willReturn(null) + + // when + messageService.sendNoticeMessage(universityNotice) + + // then + verify(messageSender, never()).sendNoticeMessage(any(), eq(tokens)) + + } + + @DisplayName("키워드에 해당하는 토큰이 없는 경우, 푸시 알림을 전송하지 않는다.") + @Test + fun sendUniversityNoticeMessageWithoutTokens() { + // given + val universityNotice = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 10), + title = "중간고사 안내", + author = "저자", + url = "http://test.com", + ) + + val tokens = listOf("토큰1", "토큰2") + + given(keywordFilter.extractKeywordFrom(universityNotice.title)).willReturn("시험") + given(subscribeReader.getTokensBySubscribedToKeyword(any())).willReturn(listOf()) + + // when + messageService.sendNoticeMessage(universityNotice) + + // then + verify(messageSender, never()).sendNoticeMessage(any(), eq(tokens)) + + } + + @DisplayName("학과 공지사항은 학과에 해당하는 토큰을 불러와 푸시 알림을 전송한다.") + @Test + fun sendDepartmentNoticeMessage() { + // given + val departmentNotice = Notice.of( + number = 1, + type = "컴퓨터소프트웨어공학과", + date = LocalDate.of(2024, 10, 10), + title = "중간고사 안내", + author = "저자", + url = "http://test.com", + ) + + val tokens = listOf("토큰1", "토큰2") + + given(subscribeReader.getTokensBySubscribedToDepartment(any())).willReturn(tokens) + + // when + messageService.sendNoticeMessage(departmentNotice) + + // then + verify(messageSender).sendNoticeMessage(any(), eq(tokens)) + } + + @DisplayName("학과에 해당하는 토큰이 없는 경우, 푸시 알림을 전송하지 않는다.") + @Test + fun sendDepartmentNoticeMessageWithoutTokens() { + // given + val departmentNotice = Notice.of( + number = 1, + type = "컴퓨터소프트웨어공학과", + date = LocalDate.of(2024, 10, 10), + title = "중간고사 안내", + author = "저자", + url = "http://test.com", + ) + + val tokens = listOf("토큰1", "토큰2") + + given(subscribeReader.getTokensBySubscribedToDepartment(any())).willReturn(listOf()) + + // when + messageService.sendNoticeMessage(departmentNotice) + + // then + verify(messageSender, never()).sendNoticeMessage(any(), eq(tokens)) + } +} \ No newline at end of file From 69bbe2d9859ff7ace25672031067ed13127015bc Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 20:42:03 +0900 Subject: [PATCH 168/223] =?UTF-8?q?test:=20Keyword=20Filter=20=EB=8B=A8?= =?UTF-8?q?=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/admin/message/KeywordFilterTest.kt | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 dmforu-admin/src/test/kotlin/com/dmforu/admin/message/KeywordFilterTest.kt diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/KeywordFilterTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/KeywordFilterTest.kt new file mode 100644 index 0000000..d3f83b8 --- /dev/null +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/KeywordFilterTest.kt @@ -0,0 +1,64 @@ +package com.dmforu.admin.message + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + + +class KeywordFilterTest { + + private val keywordFilter = KeywordFilter() + + @DisplayName("제목에서 키워드를 추출한다.") + @Test + fun extractKeywordFrom() { + // given + val title = "중간고사" + + // when + val keyword = keywordFilter.extractKeywordFrom(title) + + // then + assertThat(keyword).isEqualTo("시험") + } + + @DisplayName("제목에 추출할 키워드가 없다면, null을 반환한다.") + @Test + fun extractKeywordFromTitleNotContainingKeyword() { + // given + val title = "일반공지" + + // when + val keyword = keywordFilter.extractKeywordFrom(title) + + // then + assertThat(keyword).isNull() + } + + @DisplayName("제목이 비어 있다면, null을 반환한다.") + @Test + fun extractKeywordFromEmptyTitle() { + // given + val title = "" + + // when + val keyword = keywordFilter.extractKeywordFrom(title) + + // then + assertThat(keyword).isNull() + } + + @DisplayName("제목에 띄어쓰기가 있다면, 띄어쓰기를 무시하고 키워드를 추출한다.") + @Test + fun extractKeywordFromTitleWithExtraSpaces() { + // given + val title = " 중 간 고 사 " + + // when + val keyword = keywordFilter.extractKeywordFrom(title) + + // then + assertThat(keyword).isEqualTo("시험") + } +} \ No newline at end of file From e8b4ef34656e1c5c4bb53613e54250a91efa25ca Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 20:47:49 +0900 Subject: [PATCH 169/223] =?UTF-8?q?test:=20Keyword=20Filter=20=ED=8A=B9?= =?UTF-8?q?=EC=88=98=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=ED=82=A4=EC=9B=8C?= =?UTF-8?q?=EB=93=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/admin/message/KeywordFilter.kt | 5 ++-- .../dmforu/admin/message/KeywordFilterTest.kt | 23 ++++++++++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/KeywordFilter.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/KeywordFilter.kt index 964edaa..e9899a9 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/KeywordFilter.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/message/KeywordFilter.kt @@ -7,13 +7,14 @@ import org.springframework.stereotype.Component class KeywordFilter { fun extractKeywordFrom(title: String): String? { + val whiteSpaceRemovedTitle = title.replace(" ", "") + Keywords.entries.forEach { - if (title.contains(it.korean)) { + if (whiteSpaceRemovedTitle.contains(it.korean)) { return it.korean } } - val whiteSpaceRemovedTitle = title.replace(" ", "") if (whiteSpaceRemovedTitle.contains("중간고사")) { return "시험" } diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/KeywordFilterTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/KeywordFilterTest.kt index d3f83b8..745e457 100644 --- a/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/KeywordFilterTest.kt +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/KeywordFilterTest.kt @@ -1,5 +1,6 @@ package com.dmforu.admin.message +import com.dmforu.domain.message.Keywords.EXAM import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName @@ -14,13 +15,13 @@ class KeywordFilterTest { @Test fun extractKeywordFrom() { // given - val title = "중간고사" + val title = "시험" // when val keyword = keywordFilter.extractKeywordFrom(title) // then - assertThat(keyword).isEqualTo("시험") + assertThat(keyword).isEqualTo(EXAM.korean) } @DisplayName("제목에 추출할 키워드가 없다면, null을 반환한다.") @@ -53,7 +54,7 @@ class KeywordFilterTest { @Test fun extractKeywordFromTitleWithExtraSpaces() { // given - val title = " 중 간 고 사 " + val title = " 시 험 안 내 " // when val keyword = keywordFilter.extractKeywordFrom(title) @@ -61,4 +62,20 @@ class KeywordFilterTest { // then assertThat(keyword).isEqualTo("시험") } + + @DisplayName("중간고사, 기말고사는 시험 키워드 반환한다.") + @Test + fun extractKeywordFromTitleAboutExam() { + // given + val title1 = "중간고사" + val title2 = "기말고사" + + // when + val keyword1 = keywordFilter.extractKeywordFrom(title1) + val keyword2 = keywordFilter.extractKeywordFrom(title2) + + // then + assertThat(keyword1).isEqualTo(EXAM.korean) + assertThat(keyword2).isEqualTo(EXAM.korean) + } } \ No newline at end of file From 95f08f40ff37f76b62003aa0f8afcf6812612728 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:00:17 +0900 Subject: [PATCH 170/223] =?UTF-8?q?test:=20@Generated=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/dmforu/domain/diet/Diet.kt | 4 ++++ .../main/kotlin/com/dmforu/domain/schedule/Schedule.kt | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt index 5bf0d2f..df06380 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/diet/Diet.kt @@ -1,5 +1,6 @@ package com.dmforu.domain.diet +import com.dmforu.domain.Generated import java.time.LocalDate class Diet private constructor( @@ -12,6 +13,7 @@ class Diet private constructor( } } + @Generated override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -24,12 +26,14 @@ class Diet private constructor( return true } + @Generated override fun hashCode(): Int { var result = date.hashCode() result = 31 * result + menus.hashCode() return result } + @Generated override fun toString(): String { return "Diet(date=$date, menus=$menus)" } diff --git a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt index e104801..03e4544 100644 --- a/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt +++ b/dmforu-domain/src/main/kotlin/com/dmforu/domain/schedule/Schedule.kt @@ -1,5 +1,7 @@ package com.dmforu.domain.schedule +import com.dmforu.domain.Generated + class Schedule private constructor( val dates: List, val content: String, @@ -21,6 +23,7 @@ class Schedule private constructor( } } + @Generated override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -33,6 +36,7 @@ class Schedule private constructor( return true } + @Generated override fun hashCode(): Int { var result = month result = 31 * result + monthSchedule.hashCode() @@ -51,6 +55,7 @@ class Schedule private constructor( } } + @Generated override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -63,6 +68,7 @@ class Schedule private constructor( return true } + @Generated override fun hashCode(): Int { var result = year result = 31 * result + yearSchedule.hashCode() @@ -72,6 +78,7 @@ class Schedule private constructor( } + @Generated override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -84,6 +91,7 @@ class Schedule private constructor( return true } + @Generated override fun hashCode(): Int { var result = dates.hashCode() result = 31 * result + content.hashCode() From 8ea0857e2db2b5eceff3b85cda8aca91f11f2c26 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 16:51:46 +0900 Subject: [PATCH 171/223] Create ci.yml --- .github/workflows/ci.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c619828 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: CI + +on: + push: + branches: [ "develop" ] + pull_request: + branches: [ "develop" ] + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + - name: Test + uses: gradle/gradle-build-action@af1da67850ed9a4cedd57bfd976089dd991e2582 + with: + arguments: test + From 0f26b7ad1a3b0f5972f4ab465a157c9faf9f6eef Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 16:54:21 +0900 Subject: [PATCH 172/223] Update ci.yml --- .github/workflows/ci.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c619828..250831e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,19 +9,20 @@ on: permissions: contents: read + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '17' - distribution: 'temurin' - - name: Test - uses: gradle/gradle-build-action@af1da67850ed9a4cedd57bfd976089dd991e2582 - with: + - uses: actions/checkout@v3 + - name: Set up JDK + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + - name: Test + uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 + with: arguments: test From 390f9c7e47f7734a093b7316226eb54570882a79 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 17:35:22 +0900 Subject: [PATCH 173/223] =?UTF-8?q?chore:=20=ED=99=98=EA=B2=BD=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20yml=EC=9D=84=20=ED=94=84=EB=A1=9C=EC=A0=9D=ED=8A=B8?= =?UTF-8?q?=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 6aff4ad..255ee35 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,5 @@ out/ .kotlin ### Configuration Settings ### -**/application.yml -**/*.yml +secret.yml **/fire-base-key.json \ No newline at end of file From 41cd98853f106bedceb2376c811d0f1b61b85c5a Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 17:41:17 +0900 Subject: [PATCH 174/223] =?UTF-8?q?chore:=20redis=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EB=B0=8F=20db-mysql=EC=97=90=EC=84=9C=20m?= =?UTF-8?q?ysql=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/build.gradle.kts | 2 +- .../src/main/resources/application.yml | 22 +++++++ dmforu-api/build.gradle.kts | 7 +-- dmforu-api/src/main/resources/application.yml | 28 +++++++++ .../storage/db-redis/build.gradle.kts | 4 -- .../storage/db/redis/config/RedisConfig.kt | 61 ------------------- .../storage/db/redis/diet/DietEntity.kt | 12 ---- .../db/redis/diet/DietEntityRepository.kt | 38 ------------ .../db/redis/schedule/ScheduleEntity.kt | 13 ---- .../schedule/ScheduleEntityRepository.kt | 41 ------------- .../mongo/src/main/resources/mongo.yml | 21 +++++++ .../{db-mysql => mysql}/build.gradle.kts | 0 .../storage/db/mysql/config/MysqlJpaConfig.kt | 0 .../db/mysql/converter/StringListConverter.kt | 0 .../exception/StringListConverterException.kt | 0 .../storage/db/mysql/notice/NoticeEntity.kt | 0 .../db/mysql/notice/NoticeEntityRepository.kt | 0 .../db/mysql/notice/NoticeJpaRepository.kt | 0 .../db/mysql/subscribe/SubscribeEntity.kt | 0 .../subscribe/SubscribeEntityRepository.kt | 0 .../mysql/subscribe/SubscribeJpaRepository.kt | 0 .../mysql/src/main/resources/mysql.yml | 35 +++++++++++ .../storage/db/mysql/MysqlApplicationTest.kt | 0 .../converter/StringListConverterTest.kt | 0 .../notice/NoticeEntityRepositoryTest.kt | 0 .../db/mysql/notice/NoticeEntityTest.kt | 0 .../mysql/notice/NoticeJpaRepositoryTest.kt | 0 .../SubscribeEntityRepositoryTest.kt | 0 .../db/mysql/subscribe/SubscribeEntityTest.kt | 0 .../subscribe/SubscribeJpaRepositoryTest.kt | 0 settings.gradle.kts | 3 +- 31 files changed, 111 insertions(+), 176 deletions(-) create mode 100644 dmforu-admin/src/main/resources/application.yml create mode 100644 dmforu-api/src/main/resources/application.yml delete mode 100644 dmforu-infrastructure/storage/db-redis/build.gradle.kts delete mode 100644 dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt delete mode 100644 dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt delete mode 100644 dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt delete mode 100644 dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt delete mode 100644 dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt create mode 100644 dmforu-infrastructure/storage/mongo/src/main/resources/mongo.yml rename dmforu-infrastructure/storage/{db-mysql => mysql}/build.gradle.kts (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/main/kotlin/com/dmforu/storage/db/mysql/exception/StringListConverterException.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt (100%) create mode 100644 dmforu-infrastructure/storage/mysql/src/main/resources/mysql.yml rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/test/kotlin/com/dmforu/storage/db/mysql/MysqlApplicationTest.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityTest.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityTest.kt (100%) rename dmforu-infrastructure/storage/{db-mysql => mysql}/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt (100%) diff --git a/dmforu-admin/build.gradle.kts b/dmforu-admin/build.gradle.kts index 938f4ca..336669b 100644 --- a/dmforu-admin/build.gradle.kts +++ b/dmforu-admin/build.gradle.kts @@ -11,7 +11,7 @@ dependencies { implementation(project(":dmforu-crawling")) runtimeOnly(project(":dmforu-infrastructure:fcm")) - runtimeOnly(project(":dmforu-infrastructure:storage:db-mysql")) + runtimeOnly(project(":dmforu-infrastructure:storage:mysql")) runtimeOnly(project(":dmforu-infrastructure:storage:mongo")) testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0") diff --git a/dmforu-admin/src/main/resources/application.yml b/dmforu-admin/src/main/resources/application.yml new file mode 100644 index 0000000..2c0a8e7 --- /dev/null +++ b/dmforu-admin/src/main/resources/application.yml @@ -0,0 +1,22 @@ +spring.application.name: dmforu-admin +spring.profiles.active: local + +spring: + config: + import: + - db-mysql.yml + - mongo.yml + +spring.lifecycle.timeout-per-shutdown-phase: 30s +server.shutdown: graceful + +--- +spring.config.activate.on-profile: local + + +--- +spring.config.activate.on-profile: test + + +--- +spring.config.activate.on-profile: dev \ No newline at end of file diff --git a/dmforu-api/build.gradle.kts b/dmforu-api/build.gradle.kts index 56dfc7f..f14b99a 100644 --- a/dmforu-api/build.gradle.kts +++ b/dmforu-api/build.gradle.kts @@ -8,13 +8,12 @@ tasks.getByName("jar") { dependencies { implementation(project(":dmforu-domain")) - - runtimeOnly(project(":dmforu-infrastructure:storage:db-mysql")) - runtimeOnly(project(":dmforu-infrastructure:storage:mongo")) - implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-validation") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0") + runtimeOnly(project(":dmforu-infrastructure:storage:mysql")) + runtimeOnly(project(":dmforu-infrastructure:storage:mongo")) + testImplementation("org.springframework.boot:spring-boot-starter-validation") } \ No newline at end of file diff --git a/dmforu-api/src/main/resources/application.yml b/dmforu-api/src/main/resources/application.yml new file mode 100644 index 0000000..669a1de --- /dev/null +++ b/dmforu-api/src/main/resources/application.yml @@ -0,0 +1,28 @@ +spring.application.name: dmforu-api +spring.profiles.active: local + +spring: + config: + import: + - db-mysql.yml + - mongo.yml + web.resources.add-mappings: false + +spring-doc: + swagger-ui: + tags-sorter: alpha + operations-sorter: method + +spring.lifecycle.timeout-per-shutdown-phase: 30s +server.shutdown: graceful + +--- +spring.config.activate.on-profile: local + + +--- +spring.config.activate.on-profile: test + + +--- +spring.config.activate.on-profile: dev \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-redis/build.gradle.kts b/dmforu-infrastructure/storage/db-redis/build.gradle.kts deleted file mode 100644 index 151b3e3..0000000 --- a/dmforu-infrastructure/storage/db-redis/build.gradle.kts +++ /dev/null @@ -1,4 +0,0 @@ -dependencies { - compileOnly(project(":dmforu-domain")) - implementation("org.springframework.boot:spring-boot-starter-data-redis") -} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt deleted file mode 100644 index a550ca6..0000000 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/config/RedisConfig.kt +++ /dev/null @@ -1,61 +0,0 @@ -package com.dmforu.storage.db.redis.config - - -import org.springframework.beans.factory.annotation.Value -import org.springframework.boot.autoconfigure.domain.EntityScan -import org.springframework.cache.CacheManager -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.data.redis.cache.RedisCacheConfiguration -import org.springframework.data.redis.cache.RedisCacheManager -import org.springframework.data.redis.connection.RedisConnectionFactory -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory -import org.springframework.data.redis.core.RedisTemplate -import org.springframework.data.redis.repository.configuration.EnableRedisRepositories -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer -import org.springframework.data.redis.serializer.RedisSerializationContext -import org.springframework.data.redis.serializer.StringRedisSerializer -import java.time.Duration - -@Configuration -@EntityScan(basePackages = ["com.dmforu.storage.db.redis"]) -@EnableRedisRepositories(basePackages = ["com.dmforu.storage.db.redis"]) -internal class RedisConfig( - @Value("\${spring.data.redis.host}") - var host: String, - @Value("\${spring.data.redis.port}") - val port: Int -) { - @Bean - fun redisConnectionFactory(): RedisConnectionFactory { - return LettuceConnectionFactory(host, port) - } - - @Bean - fun redisTemplate(redisConnectionFactory: RedisConnectionFactory): RedisTemplate<*, *> { - return RedisTemplate().apply { - this.connectionFactory = redisConnectionFactory - - this.keySerializer = StringRedisSerializer() - this.valueSerializer = GenericJackson2JsonRedisSerializer() - this.hashKeySerializer = StringRedisSerializer() - this.hashValueSerializer = GenericJackson2JsonRedisSerializer() - } - } - - @Bean - fun cacheManager(redisConnectionFactory: RedisConnectionFactory): CacheManager { - val configuration = RedisCacheConfiguration.defaultCacheConfig() - .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer())) - .serializeValuesWith( - RedisSerializationContext.SerializationPair.fromSerializer( - GenericJackson2JsonRedisSerializer() - )) // Serialize 관련 설정 - .entryTtl(Duration.ofDays(2)) // 캐시 기본 ttl 2분 설정 - .disableCachingNullValues() // Null 캐싱 제외 - return RedisCacheManager.RedisCacheManagerBuilder - .fromConnectionFactory(redisConnectionFactory) - .cacheDefaults(configuration) - .build() - } -} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt deleted file mode 100644 index 60d5516..0000000 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.dmforu.storage.db.redis.diet - -import com.dmforu.domain.diet.Diet -import org.springframework.data.annotation.Id -import org.springframework.data.redis.core.RedisHash - -@RedisHash("diet") -internal class DietEntity( - @Id val id: String = "diet", - val diets: List -) - diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt deleted file mode 100644 index b3cf2a3..0000000 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/diet/DietEntityRepository.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.dmforu.storage.db.redis.diet - -import com.dmforu.domain.diet.Diet -import com.dmforu.domain.diet.DietRepository -import org.springframework.data.redis.core.RedisTemplate -import org.springframework.stereotype.Repository - -@Repository -internal class DietEntityRepository( - private val redisTemplate: RedisTemplate -) : DietRepository { - private companion object { - const val DIET_KEY = "diet" - } - - override fun write(diets: List) { - writeEntity(DIET_KEY, DietEntity(diets = diets)) - } - - override fun read(): List? { - return readEntity(DIET_KEY)?.diets - } - - /** - * 공통된 엔티티 쓰기 메서드 - */ - private fun writeEntity(key: String, entity: T) { - redisTemplate.opsForValue().set(key, entity) - } - - /** - * 공통된 엔티티 읽기 메서드 - */ - @Suppress("UNCHECKED_CAST") - private fun readEntity(key: String): T? { - return redisTemplate.opsForValue().get(key) as? T - } -} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt deleted file mode 100644 index 7158353..0000000 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntity.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.dmforu.storage.db.redis.schedule - -import com.dmforu.domain.schedule.Schedule -import org.springframework.data.annotation.Id -import org.springframework.data.redis.core.RedisHash - -@RedisHash("schedule") -internal class ScheduleEntity( - @Id val id: String = "schedule", - val schedules: List -) { - private constructor(): this("", emptyList()) -} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt b/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt deleted file mode 100644 index 27c1435..0000000 --- a/dmforu-infrastructure/storage/db-redis/src/main/kotlin/com/dmforu/storage/db/redis/schedule/ScheduleEntityRepository.kt +++ /dev/null @@ -1,41 +0,0 @@ -//package com.dmforu.storage.db.mongo.schedule -// -//import com.dmforu.domain.schedule.Schedule -//import com.dmforu.domain.schedule.ScheduleRepository -//import org.springframework.data.redis.core.RedisTemplate -//import org.springframework.stereotype.Repository -// -//@Repository -//internal class ScheduleEntityRepository( -// private val redisTemplate: RedisTemplate -//) : ScheduleRepository { -// -// private companion object { -// const val SCHEDULE_KEY = "schedule" -// } -// -// -// override fun write(schedules: List) { -// writeEntity(SCHEDULE_KEY, ScheduleEntity(schedules = schedules)) -// } -// -// -// override fun read(): List? { -// return readEntity(SCHEDULE_KEY)?.schedules -// } -// -// /** -// * 공통된 엔티티 쓰기 메서드 -// */ -// private fun writeEntity(key: String, entity: T) { -// redisTemplate.opsForValue().set(key, entity) -// } -// -// /** -// * 공통된 엔티티 읽기 메서드 -// */ -// @Suppress("UNCHECKED_CAST") -// private fun readEntity(key: String): T? { -// return redisTemplate.opsForValue().get(key) as? T -// } -//} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/main/resources/mongo.yml b/dmforu-infrastructure/storage/mongo/src/main/resources/mongo.yml new file mode 100644 index 0000000..b7b75ef --- /dev/null +++ b/dmforu-infrastructure/storage/mongo/src/main/resources/mongo.yml @@ -0,0 +1,21 @@ +--- +spring.config.activate.on-profile: local +spring: + data: + mongodb: + uri: ${storage.database.mongo.uri} + database: ${storage.database.mongo.database} +--- +spring.config.activate.on-profile: test +spring: + data: + mongodb: + uri: ${storage.database.mongo.uri} + database: ${storage.database.mongo.database} +--- +spring.config.activate.on-profile: dev +spring: + data: + mongodb: + uri: ${storage.database.mongo.uri} + database: ${storage.database.mongo.database} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/build.gradle.kts b/dmforu-infrastructure/storage/mysql/build.gradle.kts similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/build.gradle.kts rename to dmforu-infrastructure/storage/mysql/build.gradle.kts diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt b/dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt rename to dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/config/MysqlJpaConfig.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt b/dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt rename to dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverter.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/exception/StringListConverterException.kt b/dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/exception/StringListConverterException.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/exception/StringListConverterException.kt rename to dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/exception/StringListConverterException.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt b/dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt rename to dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntity.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt b/dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt rename to dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepository.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt b/dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt rename to dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepository.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt b/dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt rename to dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntity.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt b/dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt rename to dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepository.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt b/dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt rename to dmforu-infrastructure/storage/mysql/src/main/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepository.kt diff --git a/dmforu-infrastructure/storage/mysql/src/main/resources/mysql.yml b/dmforu-infrastructure/storage/mysql/src/main/resources/mysql.yml new file mode 100644 index 0000000..dffd1ce --- /dev/null +++ b/dmforu-infrastructure/storage/mysql/src/main/resources/mysql.yml @@ -0,0 +1,35 @@ +spring: + jpa: + hibernate: + ddl-auto: none + show-sql: true + properties: + hibernate: + format_sql: true +--- +spring.config.activate.on-profile: local +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: ${storage.database.mysql.url} + username: ${storage.database.mysql.username} + password: ${storage.database.mysql.password} +--- +spring.config.activate.on-profile: test +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + username: sa + password: + h2: + console: + enabled: true +--- +spring.config.activate.on-profile: dev +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: ${storage.database.mysql.url} + username: ${storage.database.mysql.username} + password: ${storage.database.mysql.password} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/MysqlApplicationTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/MysqlApplicationTest.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/MysqlApplicationTest.kt rename to dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/MysqlApplicationTest.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt rename to dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/converter/StringListConverterTest.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt rename to dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityTest.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityTest.kt rename to dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityTest.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt rename to dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt rename to dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityTest.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityTest.kt rename to dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityTest.kt diff --git a/dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt similarity index 100% rename from dmforu-infrastructure/storage/db-mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt rename to dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index c128a7b..4c00d08 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,8 +6,7 @@ include( "dmforu-domain", "dmforu-crawling", "dmforu-infrastructure:fcm", - "dmforu-infrastructure:storage:db-mysql", - "dmforu-infrastructure:storage:db-redis", + "dmforu-infrastructure:storage:mysql", "dmforu-infrastructure:storage:mongo", ) From 363ff50ca5d1d1d71c16f73b9453d5c9f7a1ca93 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 19:23:43 +0900 Subject: [PATCH 175/223] =?UTF-8?q?chore:=20Database=20yml=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=88=A8=EA=B8=B0=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 255ee35..bc993a8 100644 --- a/.gitignore +++ b/.gitignore @@ -40,5 +40,6 @@ out/ .kotlin ### Configuration Settings ### -secret.yml +**/mongo.yml +**/mysql.yml **/fire-base-key.json \ No newline at end of file From 777c0829f5827fd50e7a77afcb26debce592a405 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 19:26:26 +0900 Subject: [PATCH 176/223] =?UTF-8?q?chore:=20Application=20yml=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EA=B5=AC=EC=A1=B0=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/src/main/resources/application.yml | 2 +- dmforu-api/src/main/resources/application.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dmforu-admin/src/main/resources/application.yml b/dmforu-admin/src/main/resources/application.yml index 2c0a8e7..bd28647 100644 --- a/dmforu-admin/src/main/resources/application.yml +++ b/dmforu-admin/src/main/resources/application.yml @@ -4,7 +4,7 @@ spring.profiles.active: local spring: config: import: - - db-mysql.yml + - mysql.yml - mongo.yml spring.lifecycle.timeout-per-shutdown-phase: 30s diff --git a/dmforu-api/src/main/resources/application.yml b/dmforu-api/src/main/resources/application.yml index 669a1de..76c1df4 100644 --- a/dmforu-api/src/main/resources/application.yml +++ b/dmforu-api/src/main/resources/application.yml @@ -4,7 +4,7 @@ spring.profiles.active: local spring: config: import: - - db-mysql.yml + - mysql.yml - mongo.yml web.resources.add-mappings: false From 92040552932dfb092fa8cfec15522f0d10fb2c5d Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 19:27:48 +0900 Subject: [PATCH 177/223] =?UTF-8?q?chore:=20database=20yml=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mongo/src/main/resources/mongo.yml | 21 ----------- .../mysql/src/main/resources/mysql.yml | 35 ------------------- 2 files changed, 56 deletions(-) delete mode 100644 dmforu-infrastructure/storage/mongo/src/main/resources/mongo.yml delete mode 100644 dmforu-infrastructure/storage/mysql/src/main/resources/mysql.yml diff --git a/dmforu-infrastructure/storage/mongo/src/main/resources/mongo.yml b/dmforu-infrastructure/storage/mongo/src/main/resources/mongo.yml deleted file mode 100644 index b7b75ef..0000000 --- a/dmforu-infrastructure/storage/mongo/src/main/resources/mongo.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -spring.config.activate.on-profile: local -spring: - data: - mongodb: - uri: ${storage.database.mongo.uri} - database: ${storage.database.mongo.database} ---- -spring.config.activate.on-profile: test -spring: - data: - mongodb: - uri: ${storage.database.mongo.uri} - database: ${storage.database.mongo.database} ---- -spring.config.activate.on-profile: dev -spring: - data: - mongodb: - uri: ${storage.database.mongo.uri} - database: ${storage.database.mongo.database} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mysql/src/main/resources/mysql.yml b/dmforu-infrastructure/storage/mysql/src/main/resources/mysql.yml deleted file mode 100644 index dffd1ce..0000000 --- a/dmforu-infrastructure/storage/mysql/src/main/resources/mysql.yml +++ /dev/null @@ -1,35 +0,0 @@ -spring: - jpa: - hibernate: - ddl-auto: none - show-sql: true - properties: - hibernate: - format_sql: true ---- -spring.config.activate.on-profile: local -spring: - datasource: - driver-class-name: com.mysql.cj.jdbc.Driver - url: ${storage.database.mysql.url} - username: ${storage.database.mysql.username} - password: ${storage.database.mysql.password} ---- -spring.config.activate.on-profile: test -spring: - datasource: - driver-class-name: org.h2.Driver - url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE - username: sa - password: - h2: - console: - enabled: true ---- -spring.config.activate.on-profile: dev -spring: - datasource: - driver-class-name: com.mysql.cj.jdbc.Driver - url: ${storage.database.mysql.url} - username: ${storage.database.mysql.username} - password: ${storage.database.mysql.password} \ No newline at end of file From 1bc6a062297d27767bbd00a5b25126b580f42dc4 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 19:28:08 +0900 Subject: [PATCH 178/223] =?UTF-8?q?fix:=20mongodb=20transactional=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/storage/db/mongo/config/MongoConfig.kt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/config/MongoConfig.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/config/MongoConfig.kt index 861d100..a9824e4 100644 --- a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/config/MongoConfig.kt +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/config/MongoConfig.kt @@ -11,21 +11,21 @@ import org.bson.codecs.pojo.PojoCodecProvider import org.springframework.beans.factory.annotation.Value import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.data.mongodb.MongoDatabaseFactory +import org.springframework.data.mongodb.MongoTransactionManager import org.springframework.data.mongodb.core.MongoTemplate import org.springframework.data.mongodb.repository.config.EnableMongoRepositories - @Configuration @EnableMongoRepositories(basePackages = ["com.dmforu.storage.db.mongo"]) internal class MongoConfig( - @Value("\${spring.data.mongodb.uri}") + @Value("\${spring.data.mongo.uri}") val uri: String, - @Value("\${spring.data.mongodb.database}") + @Value("\${spring.data.mongo.database}") val database: String ) { - @Bean fun mongoClient(): MongoClient { val pojoCodecRegistry: CodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build()) @@ -44,4 +44,9 @@ internal class MongoConfig( return MongoTemplate(mongoClient(), database) } + @Bean + fun transactionManager(mongoDatabaseFactory: MongoDatabaseFactory): MongoTransactionManager{ + return MongoTransactionManager(mongoDatabaseFactory) + } + } From 1d65e2ce8b8d2c47a77f7e9efc32cbb00cf0421d Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 20:02:20 +0900 Subject: [PATCH 179/223] Update ci.yml --- .github/workflows/ci.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 250831e..3519eac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,36 @@ jobs: with: java-version: '17' distribution: 'temurin' + + - name: make mysql.yml + run: | + touch ./mysql.yml + echo "${{ secrets.MYSQL }}" > ./mysql.yml + working-directory: ./dmforu-infrastructure/storage/mysql/src/main/resources + + - name: make mongo.yml + run: | + touch ./mongo.yml + echo "${{ secrets.MONGO }}" > ./mongo.yml + working-directory: ./dmforu-infrastructure/storage/mongo/src/main/resources + + - name: create JSON file + run: | + echo '{ + "type": "${{ secrets.FCM_TYPE }}", + "project_id": "${{ secrets.FCM_PROJECT_ID }}", + "private_key_id": "${{ secrets.FCM_PRIVATE_KEY_ID }}", + "private_key": "${{ secrets.FCM_PRIVATE_KEY }}", + "client_email": "${{ secrets.FCM_CLIENT_EMAIL }}", + "client_id": "${{ secrets.FCM_CLIENT_ID }}", + "auth_uri": "${{ secrets.FCM_AUTH_URI }}", + "token_uri": "${{ secrets.FCM_TOKEN_URI }}", + "auth_provider_x509_cert_url": "${{ secrets.FCM_AUTH_PROVIDER_X509_CERT_URL }}", + "client_x509_cert_url": "${{ secrets.FCM_CLIENT_X509_CERT_URL }}", + "universe_domain": "${{ secrets.FCM_UNIVERSE_DOMAIN }}" + }' > ./fire-base-key.json + working-directory: ./dmforu-infrastructure/fcm/src/main/resources/key + - name: Test uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 with: From a9528ea25f92a9de27f59b1b516f3b195d836782 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 20:04:36 +0900 Subject: [PATCH 180/223] =?UTF-8?q?chore:=20=EC=84=A4=EC=A0=95=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EC=9D=B4=20=EC=83=9D=EC=84=B1=EB=90=A0=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3519eac..af2adf6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,18 +22,30 @@ jobs: java-version: '17' distribution: 'temurin' + - name: Create MySQL resources directory + run: | + mkdir -p ./dmforu-infrastructure/storage/mysql/src/main/resources + - name: make mysql.yml run: | touch ./mysql.yml echo "${{ secrets.MYSQL }}" > ./mysql.yml working-directory: ./dmforu-infrastructure/storage/mysql/src/main/resources + - name: Create MongoDB resources directory + run: | + mkdir -p ./dmforu-infrastructure/storage/mongo/src/main/resources + - name: make mongo.yml run: | touch ./mongo.yml echo "${{ secrets.MONGO }}" > ./mongo.yml working-directory: ./dmforu-infrastructure/storage/mongo/src/main/resources + - name: Create Firebase key resources directory + run: | + mkdir -p ./dmforu-infrastructure/fcm/src/main/resources/key + - name: create JSON file run: | echo '{ From e1c7cfa18734c94722bc30df60996e6f28ba9440 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 20:13:20 +0900 Subject: [PATCH 181/223] =?UTF-8?q?fix:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20UR?= =?UTF-8?q?L=20=EC=9A=94=EC=B2=AD=20=ED=95=B8=EB=93=A4=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt | 6 ++++++ .../main/kotlin/com/dmforu/api/support/error/ErrorCode.kt | 1 + .../main/kotlin/com/dmforu/api/support/error/ErrorType.kt | 1 + .../com/dmforu/api/controller/v1/NoticeControllerTest.kt | 6 +++--- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt index 559a992..29b70ce 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt @@ -11,6 +11,7 @@ import org.springframework.web.bind.MethodArgumentNotValidException import org.springframework.web.bind.MissingServletRequestParameterException import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice +import org.springframework.web.servlet.NoHandlerFoundException import org.springframework.web.servlet.resource.NoResourceFoundException @RestControllerAdvice @@ -27,6 +28,11 @@ class ApiControllerAdvice { return ResponseEntity(ApiResponse.error(e.errorType, e.data), e.errorType.status) } + @ExceptionHandler(NoHandlerFoundException::class) + fun handleNoResourceFoundException(e: NoHandlerFoundException): ResponseEntity> { + return ResponseEntity(ApiResponse.error(ErrorType.NOT_FOUND_ERROR), ErrorType.NOT_FOUND_ERROR.status) + } + @ExceptionHandler(NoResourceFoundException::class) fun handleNoResourceFoundException(e: NoResourceFoundException): ResponseEntity> { return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorCode.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorCode.kt index e0c06f1..6603b1b 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorCode.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorCode.kt @@ -2,5 +2,6 @@ package com.dmforu.api.support.error enum class ErrorCode { E400, + E404, E500, } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorType.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorType.kt index 70c711f..20393ad 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorType.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/support/error/ErrorType.kt @@ -5,5 +5,6 @@ import org.springframework.http.HttpStatus enum class ErrorType(val status: HttpStatus, val code: ErrorCode, val message: String, val logLevel: LogLevel) { BAD_REQUEST_ERROR(HttpStatus.BAD_REQUEST, ErrorCode.E400, "잘못된 요청을 하였습니다.", LogLevel.WARN), + NOT_FOUND_ERROR(HttpStatus.NOT_FOUND, ErrorCode.E404, "잘못된 URL로 요청을 하였습니다.", LogLevel.WARN), SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, ErrorCode.E500, "An unexpected error has occurred.", LogLevel.ERROR), } \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt index e556b34..ab7157f 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt @@ -119,10 +119,10 @@ class NoticeControllerTest : ControllerTestSupport() { .param("size", "20") .contentType(APPLICATION_JSON) ) - .andExpect(status().isBadRequest) + .andExpect(status().isNotFound) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E404.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 URL로 요청을 하였습니다.")) .andExpect(jsonPath("$.error.data").isEmpty) .andExpect(jsonPath("$.data").isEmpty) } From 6493a8fb704369363506ad91a9f5417ca75757e6 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 20:45:54 +0900 Subject: [PATCH 182/223] =?UTF-8?q?fix:=20=EC=9E=98=EB=AA=BB=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=EB=90=9C=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/message/NoticeListenerTest.kt | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt index 933fe26..4dfd4f2 100644 --- a/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/message/NoticeListenerTest.kt @@ -4,32 +4,39 @@ import com.dmforu.domain.notice.Notice import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test -import org.mockito.Mockito.mock import org.mockito.Mockito.verify import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.mock.mockito.MockBean -import org.springframework.context.ApplicationEventPublisher +import org.springframework.context.ApplicationContext +import java.time.LocalDate -@SpringBootTest +@SpringBootTest(classes = [NoticeListener::class]) class NoticeListenerTest { @Autowired - private lateinit var eventPublisher: ApplicationEventPublisher + private lateinit var applicationContext: ApplicationContext @MockBean - private lateinit var messageService: MessageService + private lateinit var noticeListener: NoticeListener @DisplayName("notice 이벤트가 발생하면, 푸시 알림을 전송한다.") @Test fun onNoticeMessageSendEventHandler() { // given - val notice = mock(Notice::class.java) + val notice = Notice.of( + number = 1, + type = "대학", + date = LocalDate.of(2024, 10, 1), + title = "제목", + author = "작성자", + url = "http://test.com", + ) // when - eventPublisher.publishEvent(notice) + applicationContext.publishEvent(notice) // then - verify(messageService).sendNoticeMessage(notice) + verify(noticeListener).onNoticeMessageSendEventHandler(notice) } } \ No newline at end of file From f85a3dc217b265a17a7fe90616ac3d38d82c38a0 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 20:48:08 +0900 Subject: [PATCH 183/223] =?UTF-8?q?fix:=20ApiApplicationTests=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/api/ApiApplicationTests.kt | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 dmforu-api/src/test/kotlin/com/dmforu/api/ApiApplicationTests.kt diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/ApiApplicationTests.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/ApiApplicationTests.kt deleted file mode 100644 index 32df85a..0000000 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/ApiApplicationTests.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.dmforu.api - -import org.junit.jupiter.api.Test -import org.springframework.boot.test.context.SpringBootTest - -@SpringBootTest -class ApiApplicationTests { - - @Test - fun contextLoads() { - } - -} \ No newline at end of file From acdd79ae667d0ff4a72f2a85fbf804f982d596c9 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 20:58:49 +0900 Subject: [PATCH 184/223] =?UTF-8?q?fix:=20mongo=20module=20Build=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=8B=A4=ED=8C=A8=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/storage/db/mongo/MongoApplicationTest.kt | 6 ------ .../kotlin/com/dmforu/storage/db/mongo/MongoTestSupport.kt | 6 +++++- 2 files changed, 5 insertions(+), 7 deletions(-) delete mode 100644 dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoApplicationTest.kt diff --git a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoApplicationTest.kt b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoApplicationTest.kt deleted file mode 100644 index a4f5433..0000000 --- a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoApplicationTest.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.dmforu.storage.db.mongo - -import org.springframework.boot.autoconfigure.SpringBootApplication - -@SpringBootApplication -class MongoApplicationTest \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoTestSupport.kt b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoTestSupport.kt index 09ced75..f83e274 100644 --- a/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoTestSupport.kt +++ b/dmforu-infrastructure/storage/mongo/src/test/kotlin/com/dmforu/storage/db/mongo/MongoTestSupport.kt @@ -1,13 +1,17 @@ package com.dmforu.storage.db.mongo import com.dmforu.storage.db.mongo.config.MongoConfig +import com.dmforu.storage.db.mongo.diet.DietEntityRepositoryTest +import com.dmforu.storage.db.mongo.schedule.ScheduleEntityMongoRepositoryTest +import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.test.context.SpringBootTest import org.springframework.context.annotation.Import import org.springframework.test.context.ActiveProfiles import org.springframework.test.context.TestPropertySource @TestPropertySource(properties = ["spring.config.location = src/main/resources/mongo.yml"]) -@SpringBootTest(classes = [MongoApplicationTest::class]) +@SpringBootTest(classes = [ScheduleEntityMongoRepositoryTest::class, DietEntityRepositoryTest::class]) +@SpringBootApplication @Import(MongoConfig::class) @ActiveProfiles("test") class MongoTestSupport \ No newline at end of file From 242822e7f04c1e6467f35f933c4ab3a5dc88410e Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 31 Oct 2024 21:11:24 +0900 Subject: [PATCH 185/223] =?UTF-8?q?chore:=20CI=20=EC=A4=91=20yml=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EC=9D=84=20=EB=94=94=EC=BD=94=EB=94=A9=20=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af2adf6..ba72e36 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: - name: make mysql.yml run: | touch ./mysql.yml - echo "${{ secrets.MYSQL }}" > ./mysql.yml + echo "${{ secrets.MYSQL }}" | base64 --decode > ./mysql.yml working-directory: ./dmforu-infrastructure/storage/mysql/src/main/resources - name: Create MongoDB resources directory @@ -39,7 +39,7 @@ jobs: - name: make mongo.yml run: | touch ./mongo.yml - echo "${{ secrets.MONGO }}" > ./mongo.yml + echo "${{ secrets.MONGO }}" | base64 --decode > ./mongo.yml working-directory: ./dmforu-infrastructure/storage/mongo/src/main/resources - name: Create Firebase key resources directory From 4c02d4bf4a7704f1c4808dfdaa218122861e963e Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 1 Nov 2024 19:55:27 +0900 Subject: [PATCH 186/223] =?UTF-8?q?refactor:=20Multicast=20Message=20Conve?= =?UTF-8?q?rter=EB=A5=BC=20Object=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=A1=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/fcm/FirebaseMessageSender.kt | 4 +- ...Converter.kt => MulticastMessageMapper.kt} | 6 +-- .../dmforu/fcm/FirebaseMessageSenderTest.kt | 40 ++++++++++--------- 3 files changed, 24 insertions(+), 26 deletions(-) rename dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/{FirebaseMessageConverter.kt => MulticastMessageMapper.kt} (73%) diff --git a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt index 64da353..0a68132 100644 --- a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt +++ b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageSender.kt @@ -2,19 +2,17 @@ package com.dmforu.fcm import com.dmforu.domain.message.MessageSender import com.dmforu.domain.message.NoticeMessage -import com.google.firebase.FirebaseApp import com.google.firebase.messaging.FirebaseMessaging import org.springframework.stereotype.Component @Component internal class FirebaseMessageSender( - private val firebaseMessageConverter: FirebaseMessageConverter, private val firebaseMessaging: FirebaseMessaging, ) : MessageSender { override fun sendNoticeMessage(message: NoticeMessage, tokens: List) { - val firebaseMessage = firebaseMessageConverter.buildMessageToNotice(message, tokens) + val firebaseMessage = MulticastMessageMapper.mapToMulticastMessage(message, tokens) firebaseMessaging.sendEachForMulticast(firebaseMessage) } diff --git a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/MulticastMessageMapper.kt similarity index 73% rename from dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt rename to dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/MulticastMessageMapper.kt index 56fa160..3241920 100644 --- a/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/FirebaseMessageConverter.kt +++ b/dmforu-infrastructure/fcm/src/main/kotlin/com/dmforu/fcm/MulticastMessageMapper.kt @@ -3,12 +3,10 @@ package com.dmforu.fcm import com.dmforu.domain.message.NoticeMessage import com.google.firebase.messaging.MulticastMessage import com.google.firebase.messaging.Notification -import org.springframework.stereotype.Component -@Component -internal class FirebaseMessageConverter { +internal object MulticastMessageMapper { - fun buildMessageToNotice(message: NoticeMessage, tokens: List): MulticastMessage { + fun mapToMulticastMessage(message: NoticeMessage, tokens: List): MulticastMessage { val notification = Notification.builder() .setTitle(message.title) .setBody(message.body) diff --git a/dmforu-infrastructure/fcm/src/test/kotlin/com/dmforu/fcm/FirebaseMessageSenderTest.kt b/dmforu-infrastructure/fcm/src/test/kotlin/com/dmforu/fcm/FirebaseMessageSenderTest.kt index d4d2fbf..1754866 100644 --- a/dmforu-infrastructure/fcm/src/test/kotlin/com/dmforu/fcm/FirebaseMessageSenderTest.kt +++ b/dmforu-infrastructure/fcm/src/test/kotlin/com/dmforu/fcm/FirebaseMessageSenderTest.kt @@ -1,48 +1,50 @@ package com.dmforu.fcm import com.dmforu.domain.message.NoticeMessage +import com.dmforu.domain.notice.Notice import com.google.firebase.messaging.FirebaseMessaging import com.google.firebase.messaging.MulticastMessage -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.BDDMockito.given -import org.mockito.InjectMocks -import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.Mockito.verify -import org.mockito.junit.jupiter.MockitoExtension -import org.mockito.kotlin.eq +import org.mockito.kotlin.any +import org.mockito.kotlin.given +import java.time.LocalDate -@ExtendWith(MockitoExtension::class) class FirebaseMessageSenderTest { - @Mock - private lateinit var firebaseMessageConverter: FirebaseMessageConverter - - @Mock private lateinit var firebaseMessaging: FirebaseMessaging - @InjectMocks private lateinit var messageSender: FirebaseMessageSender + @BeforeEach + fun setUp() { + firebaseMessaging = mock() + messageSender = FirebaseMessageSender(firebaseMessaging) + } + @DisplayName("공지를 푸시 알림으로 전송한다.") @Test fun sendNoticeMessage() { // given - val message = mock(NoticeMessage::class.java) - val multicastMessage = mock(MulticastMessage::class.java) + val notice = Notice.of( + number = 1, + type = "대학", + date = LocalDate.now(), + title = "공지사항입니다.", + author = "관리자", + url = "https://www.test.com" + ) + val message = NoticeMessage.createDepartmentNoticeMessage(notice) val tokens = listOf("토큰1", "토큰2") - given(firebaseMessageConverter.buildMessageToNotice(eq(message), eq(tokens))).willReturn(multicastMessage) - // when messageSender.sendNoticeMessage(message, tokens) // then - verify(firebaseMessageConverter).buildMessageToNotice(message, tokens) - verify(firebaseMessaging).sendEachForMulticast(multicastMessage) + verify(firebaseMessaging).sendEachForMulticast(any()) } } \ No newline at end of file From 7b79d67a97d1c72b6a32e11c3c9d79be849ab78b Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Fri, 1 Nov 2024 20:41:28 +0900 Subject: [PATCH 187/223] =?UTF-8?q?chore:=20jacoco=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=EC=9D=84=20=EB=A7=8C=EB=93=A4=EC=96=B4=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EB=AA=A8=EC=95=84=EC=84=9C=20=EB=B3=BC=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-support/jacoco/build.gradle.kts | 8 ++++++++ settings.gradle.kts | 3 +++ 2 files changed, 11 insertions(+) create mode 100644 dmforu-support/jacoco/build.gradle.kts diff --git a/dmforu-support/jacoco/build.gradle.kts b/dmforu-support/jacoco/build.gradle.kts new file mode 100644 index 0000000..95d37a0 --- /dev/null +++ b/dmforu-support/jacoco/build.gradle.kts @@ -0,0 +1,8 @@ +plugins { + id("jacoco-report-aggregation") +} + +dependencies { + jacocoAggregation(project(":dmforu-api")) + jacocoAggregation(project(":dmforu-admin")) +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 4c00d08..72994a1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,9 +5,12 @@ include( "dmforu-admin", "dmforu-domain", "dmforu-crawling", + "dmforu-infrastructure:fcm", "dmforu-infrastructure:storage:mysql", "dmforu-infrastructure:storage:mongo", + + "dmforu-support:jacoco" ) pluginManagement { From 26d48f47f311d773fc9c2ae5ab9c596b402cc00e Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 2 Nov 2024 04:36:34 +0900 Subject: [PATCH 188/223] =?UTF-8?q?fix:=20Jacoco=20=EB=A6=AC=ED=8F=AC?= =?UTF-8?q?=ED=8A=B8=EC=97=90=20=EC=98=88=EC=99=B8=EA=B0=80=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=EB=90=98=EC=A7=80=20=EC=95=8A=EC=95=98=EB=8D=98=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-support/jacoco/build.gradle.kts | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/dmforu-support/jacoco/build.gradle.kts b/dmforu-support/jacoco/build.gradle.kts index 95d37a0..59d2e91 100644 --- a/dmforu-support/jacoco/build.gradle.kts +++ b/dmforu-support/jacoco/build.gradle.kts @@ -5,4 +5,40 @@ plugins { dependencies { jacocoAggregation(project(":dmforu-api")) jacocoAggregation(project(":dmforu-admin")) +} + +tasks.testCodeCoverageReport { + reports { + csv.required = true + xml.required = false + } + classDirectories.setFrom( + files( + listOf( + project(":dmforu-api"), + project(":dmforu-admin"), + project(":dmforu-domain"), + project(":dmforu-crawling"), + + project(":dmforu-infrastructure:fcm"), + project(":dmforu-infrastructure:storage:mysql"), + project(":dmforu-infrastructure:storage:mongo"), + ).map { + it.fileTree("${it.buildDir}/classes/kotlin/main") { + exclude( + "**/*Application*", + "**/*Config*", + "**/*Dto*", + "**/*Error*", + "**/*Request*", + "**/*Response*", + "**/*Interceptor*", + "**/*Exception*", + "**/*TestSupport*" + ) + } + + } + ) + ) } \ No newline at end of file From 267cbb10fe8b2c5fd20cde1ec7958aa1460b1813 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 2 Nov 2024 17:16:13 +0900 Subject: [PATCH 189/223] =?UTF-8?q?chore:=20CodeCov=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=90=EB=8F=99=ED=99=94=20CI=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 9 +++++++-- dmforu-support/jacoco/build.gradle.kts | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba72e36..94e578b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: CI +name: CI Auto Test on: push: @@ -66,5 +66,10 @@ jobs: - name: Test uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 with: - arguments: test + arguments: testCodeCoverageReport + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: '**/jacoco/build/reports/jacoco/testCodeCoverageReport/testCodeCoverageReport.xml' \ No newline at end of file diff --git a/dmforu-support/jacoco/build.gradle.kts b/dmforu-support/jacoco/build.gradle.kts index 59d2e91..ca27057 100644 --- a/dmforu-support/jacoco/build.gradle.kts +++ b/dmforu-support/jacoco/build.gradle.kts @@ -9,8 +9,8 @@ dependencies { tasks.testCodeCoverageReport { reports { - csv.required = true - xml.required = false + csv.required = false + xml.required = true } classDirectories.setFrom( files( From 0ae00482ed39f4d742536bb18cb25a0b4928db79 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 2 Nov 2024 17:45:09 +0900 Subject: [PATCH 190/223] =?UTF-8?q?CodeCov=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=BB=A4=EB=B2=84=EB=A6=AC=EC=A7=80=EA=B0=80=20PR=20Comment?= =?UTF-8?q?=EC=97=90=20=EC=A0=95=EC=83=81=EC=A0=81=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=8B=AC=EB=A6=AC=EB=8A=94=EC=A7=80=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 94e578b..9e1f82f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,6 @@ on: permissions: contents: read - jobs: build: From 556df605fe0579618cf56f37c6c27d2fe08fc30e Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 2 Nov 2024 17:52:26 +0900 Subject: [PATCH 191/223] =?UTF-8?q?chore:=20CodeCov=20comment=EB=A5=BC=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20yml=20=ED=8C=8C=EC=9D=BC=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- codecov.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..1949577 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,10 @@ +codecov: + require_ci_to_pass: yes + +comment: + layout: "reach,diff,flags,files,footer" + behavior: default + require_changes: false + branches: + - develop + - main \ No newline at end of file From 77239e559afbb090d1f168b28456425228dd8c9a Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 2 Nov 2024 21:26:01 +0900 Subject: [PATCH 192/223] Git Webhook Deploy Test --- build.gradle.kts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f79b8c0..9f00018 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -86,5 +86,4 @@ subprojects { ) ) } - -} +} \ No newline at end of file From 054af6bcb95e4734ae962ea567b03a3e953cfd50 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sat, 2 Nov 2024 21:27:42 +0900 Subject: [PATCH 193/223] Revert "Git Webhook Deploy Test" --- build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9f00018..f79b8c0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -86,4 +86,5 @@ subprojects { ) ) } -} \ No newline at end of file + +} From 937441680aa48f0b5582a6aa12c2c4c91c5797f2 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 3 Nov 2024 23:32:39 +0900 Subject: [PATCH 194/223] =?UTF-8?q?rename:=20Configuration=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20Config=EB=A1=9C=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{ApplicationConfiguration.kt => ApplicationConfig.kt} | 2 +- .../{ApplicationConfiguration.kt => ApplicationConfig.kt} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename dmforu-admin/src/main/kotlin/com/dmforu/admin/config/{ApplicationConfiguration.kt => ApplicationConfig.kt} (98%) rename dmforu-api/src/main/kotlin/com/dmforu/api/config/{ApplicationConfiguration.kt => ApplicationConfig.kt} (98%) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfig.kt similarity index 98% rename from dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt rename to dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfig.kt index 5fb5058..ec43021 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfiguration.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/config/ApplicationConfig.kt @@ -18,7 +18,7 @@ import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Scope @Configuration -class ApplicationConfiguration { +class ApplicationConfig { @Bean fun subscribeReader(subscribeRepository: SubscribeRepository): SubscribeReader { diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfiguration.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfig.kt similarity index 98% rename from dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfiguration.kt rename to dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfig.kt index ed8fe25..696c95b 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfiguration.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/config/ApplicationConfig.kt @@ -11,7 +11,7 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration -class ApplicationConfiguration { +class ApplicationConfig { @Bean fun subscribeReader(subscribeRepository: SubscribeRepository): SubscribeReader { From f3de4bb4117ff79eba833913a58e58dd5975286c Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 4 Nov 2024 04:18:47 +0900 Subject: [PATCH 195/223] =?UTF-8?q?refactor:=20WebApplication=EC=9D=84=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/admin/AdminApplication.kt | 6 +- nohup.out | 154 ++++++++++++++++++ 2 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 nohup.out diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt index ab56d95..d3a33f8 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt @@ -1,6 +1,8 @@ package com.dmforu.admin +import org.springframework.boot.WebApplicationType import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.builder.SpringApplicationBuilder import org.springframework.boot.runApplication import org.springframework.scheduling.annotation.EnableScheduling @@ -16,5 +18,7 @@ import org.springframework.scheduling.annotation.EnableScheduling class AdminApplication fun main(args: Array) { - runApplication(*args) + SpringApplicationBuilder(AdminApplication::class.java) + .web(WebApplicationType.NONE) + .run(*args) } diff --git a/nohup.out b/nohup.out new file mode 100644 index 0000000..3e65188 --- /dev/null +++ b/nohup.out @@ -0,0 +1,154 @@ + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + + :: Spring Boot :: (v3.3.4) + +2024-11-04T03:32:24.334+09:00 INFO 57048 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : Starting AdminApplicationKt v1.2.0 using Java 17.0.11 with PID 57048 (/Users/weeds2577/DMU-BackEnd/dmforu-admin/build/libs/dmforu-admin-1.2.0.jar started by weeds2577 in /Users/weeds2577/DMU-BackEnd) +2024-11-04T03:32:24.336+09:00 INFO 57048 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : The following 1 profile is active: "local" +2024-11-04T03:32:24.730+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode +2024-11-04T03:32:24.730+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data MongoDB repositories in DEFAULT mode. +2024-11-04T03:32:24.753+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 20 ms. Found 2 MongoDB repository interfaces. +2024-11-04T03:32:24.757+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode +2024-11-04T03:32:24.757+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. +2024-11-04T03:32:24.766+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 6 ms. Found 2 JPA repository interfaces. +2024-11-04T03:32:25.259+09:00 INFO 57048 --- [dmforu-admin] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2024-11-04T03:32:25.269+09:00 INFO 57048 --- [dmforu-admin] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2024-11-04T03:32:25.269+09:00 INFO 57048 --- [dmforu-admin] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.30] +2024-11-04T03:32:25.301+09:00 INFO 57048 --- [dmforu-admin] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2024-11-04T03:32:25.302+09:00 INFO 57048 --- [dmforu-admin] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 933 ms +2024-11-04T03:32:25.403+09:00 INFO 57048 --- [dmforu-admin] [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] +2024-11-04T03:32:25.449+09:00 INFO 57048 --- [dmforu-admin] [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.5.3.Final +2024-11-04T03:32:25.483+09:00 INFO 57048 --- [dmforu-admin] [ main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled +2024-11-04T03:32:25.720+09:00 INFO 57048 --- [dmforu-admin] [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer +2024-11-04T03:32:25.767+09:00 INFO 57048 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... +2024-11-04T03:32:26.018+09:00 INFO 57048 --- [dmforu-admin] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@510e4d79 +2024-11-04T03:32:26.019+09:00 INFO 57048 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. +2024-11-04T03:32:26.065+09:00 WARN 57048 --- [dmforu-admin] [ main] org.hibernate.orm.deprecation : HHH90000025: MySQLDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default) +2024-11-04T03:32:26.732+09:00 INFO 57048 --- [dmforu-admin] [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) +2024-11-04T03:32:26.734+09:00 INFO 57048 --- [dmforu-admin] [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' +2024-11-04T03:32:27.013+09:00 INFO 57048 --- [dmforu-admin] [ main] o.s.d.j.r.query.QueryEnhancerFactory : Hibernate is in classpath; If applicable, HQL parser will be used. +2024-11-04T03:32:27.418+09:00 INFO 57048 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-02.qlvx9.mongodb.net:27017 to client view of cluster +2024-11-04T03:32:27.436+09:00 INFO 57048 --- [dmforu-admin] [ main] org.mongodb.driver.client : MongoClient with metadata {"application": {"name": "dmforu-test"}, "driver": {"name": "mongo-java-driver|sync", "version": "5.0.1"}, "os": {"type": "Darwin", "name": "Mac OS X", "architecture": "aarch64", "version": "14.2.1"}, "platform": "Java/Oracle Corporation/17.0.11+7-LTS-207"} created with settings MongoClientSettings{readPreference=primary, writeConcern=WriteConcern{w=majority, wTimeout=null ms, journal=null}, retryWrites=true, retryReads=true, readConcern=ReadConcern{level=null}, credential=MongoCredential{mechanism=null, userName='weeds2577', source='admin', password=, mechanismProperties=}, transportSettings=null, commandListeners=[], codecRegistry=ProvidersCodecRegistry{codecProviders=[ProvidersCodecRegistry{codecProviders=[ValueCodecProvider{}, BsonValueCodecProvider{}, DBRefCodecProvider{}, DBObjectCodecProvider{}, DocumentCodecProvider{}, CollectionCodecProvider{}, IterableCodecProvider{}, MapCodecProvider{}, GeoJsonCodecProvider{}, GridFSFileCodecProvider{}, Jsr310CodecProvider{}, JsonObjectCodecProvider{}, BsonCodecProvider{}, EnumCodecProvider{}, com.mongodb.client.model.mql.ExpressionCodecProvider@508863eb, com.mongodb.Jep395RecordCodecProvider@7d8802cf, com.mongodb.KotlinCodecProvider@2f7af3d0]}, ProvidersCodecRegistry{codecProviders=[org.bson.codecs.pojo.PojoCodecProvider@494775f1]}]}, loggerSettings=LoggerSettings{maxDocumentLength=1000}, clusterSettings={hosts=[127.0.0.1:27017], srvHost=dmforu-test.qlvx9.mongodb.net, srvServiceName=mongodb, mode=MULTIPLE, requiredClusterType=REPLICA_SET, requiredReplicaSetName='atlas-m6kxjp-shard-0', serverSelector='null', clusterListeners='[]', serverSelectionTimeout='30000 ms', localThreshold='15 ms'}, socketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=0, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, heartbeatSocketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=10000, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, connectionPoolSettings=ConnectionPoolSettings{maxSize=100, minSize=0, maxWaitTimeMS=120000, maxConnectionLifeTimeMS=0, maxConnectionIdleTimeMS=0, maintenanceInitialDelayMS=0, maintenanceFrequencyMS=60000, connectionPoolListeners=[], maxConnecting=2}, serverSettings=ServerSettings{heartbeatFrequencyMS=10000, minHeartbeatFrequencyMS=500, serverListeners='[]', serverMonitorListeners='[]'}, sslSettings=SslSettings{enabled=true, invalidHostNameAllowed=false, context=null}, applicationName='dmforu-test', compressorList=[], uuidRepresentation=UNSPECIFIED, serverApi=null, autoEncryptionSettings=null, dnsClient=null, inetAddressResolver=null, contextProvider=null} +2024-11-04T03:32:27.461+09:00 INFO 57048 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-00.qlvx9.mongodb.net:27017 to client view of cluster +2024-11-04T03:32:27.463+09:00 INFO 57048 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-01.qlvx9.mongodb.net:27017 to client view of cluster +2024-11-04T03:32:27.708+09:00 WARN 57048 --- [dmforu-admin] [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning +2024-11-04T03:32:27.863+09:00 INFO 57048 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=248497500, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az2'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=9, topologyVersion=TopologyVersion{processId=67220b6eb3ac540c1b3d2884, counter=3}, lastWriteDate=Mon Nov 04 03:32:27 KST 2024, lastUpdateTimeNanos=880874715381000} +2024-11-04T03:32:27.863+09:00 INFO 57048 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-00.qlvx9.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=248497333, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-00.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az1'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=9, topologyVersion=TopologyVersion{processId=67220a16b5fcab00b1d9f81a, counter=4}, lastWriteDate=Mon Nov 04 03:32:27 KST 2024, lastUpdateTimeNanos=880874715381000} +2024-11-04T03:32:27.863+09:00 INFO 57048 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=247061792, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az3'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=7fffffff00000000000000aa, setVersion=9, topologyVersion=TopologyVersion{processId=67220879494685dc7d977f3a, counter=6}, lastWriteDate=Mon Nov 04 03:32:27 KST 2024, lastUpdateTimeNanos=880874715381000} +2024-11-04T03:32:27.867+09:00 INFO 57048 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Discovered replica set primary dmforu-test-shard-00-01.qlvx9.mongodb.net:27017 with max election id 7fffffff00000000000000aa and max set version 9 +2024-11-04T03:32:27.936+09:00 WARN 57048 --- [dmforu-admin] [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'webServerStartStop' +2024-11-04T03:32:27.965+09:00 INFO 57048 --- [dmforu-admin] [ main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' +2024-11-04T03:32:27.966+09:00 INFO 57048 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... +2024-11-04T03:32:27.969+09:00 INFO 57048 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. +2024-11-04T03:32:27.982+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.b.a.l.ConditionEvaluationReportLogger : + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2024-11-04T03:32:27.992+09:00 ERROR 57048 --- [dmforu-admin] [ main] o.s.b.d.LoggingFailureAnalysisReporter : + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +Web server failed to start. Port 8080 was already in use. + +Action: + +Identify and stop the process that's listening on port 8080 or configure this application to listen on another port. + + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + + :: Spring Boot :: (v3.3.4) + +2024-11-04T03:33:20.395+09:00 INFO 57287 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : Starting AdminApplicationKt v1.2.0 using Java 17.0.11 with PID 57287 (/Users/weeds2577/DMU-BackEnd/dmforu-admin/build/libs/dmforu-admin-1.2.0.jar started by weeds2577 in /Users/weeds2577/DMU-BackEnd) +2024-11-04T03:33:20.398+09:00 INFO 57287 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : The following 1 profile is active: "local" +2024-11-04T03:33:20.780+09:00 INFO 57287 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode +2024-11-04T03:33:20.780+09:00 INFO 57287 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data MongoDB repositories in DEFAULT mode. +2024-11-04T03:33:20.805+09:00 INFO 57287 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 22 ms. Found 2 MongoDB repository interfaces. +2024-11-04T03:33:20.809+09:00 INFO 57287 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode +2024-11-04T03:33:20.809+09:00 INFO 57287 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. +2024-11-04T03:33:20.817+09:00 INFO 57287 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 7 ms. Found 2 JPA repository interfaces. +2024-11-04T03:33:21.320+09:00 INFO 57287 --- [dmforu-admin] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2024-11-04T03:33:21.331+09:00 INFO 57287 --- [dmforu-admin] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2024-11-04T03:33:21.331+09:00 INFO 57287 --- [dmforu-admin] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.30] +2024-11-04T03:33:21.362+09:00 INFO 57287 --- [dmforu-admin] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2024-11-04T03:33:21.362+09:00 INFO 57287 --- [dmforu-admin] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 931 ms +2024-11-04T03:33:21.472+09:00 INFO 57287 --- [dmforu-admin] [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] +2024-11-04T03:33:21.519+09:00 INFO 57287 --- [dmforu-admin] [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.5.3.Final +2024-11-04T03:33:21.550+09:00 INFO 57287 --- [dmforu-admin] [ main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled +2024-11-04T03:33:21.790+09:00 INFO 57287 --- [dmforu-admin] [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer +2024-11-04T03:33:21.812+09:00 INFO 57287 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... +2024-11-04T03:33:21.992+09:00 INFO 57287 --- [dmforu-admin] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@1a819901 +2024-11-04T03:33:21.992+09:00 INFO 57287 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. +2024-11-04T03:33:22.026+09:00 WARN 57287 --- [dmforu-admin] [ main] org.hibernate.orm.deprecation : HHH90000025: MySQLDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default) +2024-11-04T03:33:22.644+09:00 INFO 57287 --- [dmforu-admin] [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) +2024-11-04T03:33:22.646+09:00 INFO 57287 --- [dmforu-admin] [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' +2024-11-04T03:33:22.889+09:00 INFO 57287 --- [dmforu-admin] [ main] o.s.d.j.r.query.QueryEnhancerFactory : Hibernate is in classpath; If applicable, HQL parser will be used. +2024-11-04T03:33:23.347+09:00 INFO 57287 --- [dmforu-admin] [ main] org.mongodb.driver.client : MongoClient with metadata {"application": {"name": "dmforu-test"}, "driver": {"name": "mongo-java-driver|sync", "version": "5.0.1"}, "os": {"type": "Darwin", "name": "Mac OS X", "architecture": "aarch64", "version": "14.2.1"}, "platform": "Java/Oracle Corporation/17.0.11+7-LTS-207"} created with settings MongoClientSettings{readPreference=primary, writeConcern=WriteConcern{w=majority, wTimeout=null ms, journal=null}, retryWrites=true, retryReads=true, readConcern=ReadConcern{level=null}, credential=MongoCredential{mechanism=null, userName='weeds2577', source='admin', password=, mechanismProperties=}, transportSettings=null, commandListeners=[], codecRegistry=ProvidersCodecRegistry{codecProviders=[ProvidersCodecRegistry{codecProviders=[ValueCodecProvider{}, BsonValueCodecProvider{}, DBRefCodecProvider{}, DBObjectCodecProvider{}, DocumentCodecProvider{}, CollectionCodecProvider{}, IterableCodecProvider{}, MapCodecProvider{}, GeoJsonCodecProvider{}, GridFSFileCodecProvider{}, Jsr310CodecProvider{}, JsonObjectCodecProvider{}, BsonCodecProvider{}, EnumCodecProvider{}, com.mongodb.client.model.mql.ExpressionCodecProvider@1ffcb4bb, com.mongodb.Jep395RecordCodecProvider@6d66a248, com.mongodb.KotlinCodecProvider@29617475]}, ProvidersCodecRegistry{codecProviders=[org.bson.codecs.pojo.PojoCodecProvider@4f9871a2]}]}, loggerSettings=LoggerSettings{maxDocumentLength=1000}, clusterSettings={hosts=[127.0.0.1:27017], srvHost=dmforu-test.qlvx9.mongodb.net, srvServiceName=mongodb, mode=MULTIPLE, requiredClusterType=REPLICA_SET, requiredReplicaSetName='atlas-m6kxjp-shard-0', serverSelector='null', clusterListeners='[]', serverSelectionTimeout='30000 ms', localThreshold='15 ms'}, socketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=0, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, heartbeatSocketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=10000, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, connectionPoolSettings=ConnectionPoolSettings{maxSize=100, minSize=0, maxWaitTimeMS=120000, maxConnectionLifeTimeMS=0, maxConnectionIdleTimeMS=0, maintenanceInitialDelayMS=0, maintenanceFrequencyMS=60000, connectionPoolListeners=[], maxConnecting=2}, serverSettings=ServerSettings{heartbeatFrequencyMS=10000, minHeartbeatFrequencyMS=500, serverListeners='[]', serverMonitorListeners='[]'}, sslSettings=SslSettings{enabled=true, invalidHostNameAllowed=false, context=null}, applicationName='dmforu-test', compressorList=[], uuidRepresentation=UNSPECIFIED, serverApi=null, autoEncryptionSettings=null, dnsClient=null, inetAddressResolver=null, contextProvider=null} +2024-11-04T03:33:23.418+09:00 INFO 57287 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-02.qlvx9.mongodb.net:27017 to client view of cluster +2024-11-04T03:33:23.438+09:00 INFO 57287 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-00.qlvx9.mongodb.net:27017 to client view of cluster +2024-11-04T03:33:23.440+09:00 INFO 57287 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-01.qlvx9.mongodb.net:27017 to client view of cluster +2024-11-04T03:33:23.612+09:00 WARN 57287 --- [dmforu-admin] [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning +2024-11-04T03:33:23.639+09:00 INFO 57287 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-00.qlvx9.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=126787167, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-00.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az1'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=9, topologyVersion=TopologyVersion{processId=67220a16b5fcab00b1d9f81a, counter=4}, lastWriteDate=Mon Nov 04 03:33:23 KST 2024, lastUpdateTimeNanos=880930494020875} +2024-11-04T03:33:23.639+09:00 INFO 57287 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=126732208, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az3'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=7fffffff00000000000000aa, setVersion=9, topologyVersion=TopologyVersion{processId=67220879494685dc7d977f3a, counter=6}, lastWriteDate=Mon Nov 04 03:33:23 KST 2024, lastUpdateTimeNanos=880930494028541} +2024-11-04T03:33:23.639+09:00 INFO 57287 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=126829083, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az2'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=9, topologyVersion=TopologyVersion{processId=67220b6eb3ac540c1b3d2884, counter=3}, lastWriteDate=Mon Nov 04 03:33:23 KST 2024, lastUpdateTimeNanos=880930494054750} +2024-11-04T03:33:23.642+09:00 INFO 57287 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Discovered replica set primary dmforu-test-shard-00-01.qlvx9.mongodb.net:27017 with max election id 7fffffff00000000000000aa and max set version 9 +2024-11-04T03:33:23.842+09:00 INFO 57287 --- [dmforu-admin] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' +2024-11-04T03:33:23.853+09:00 INFO 57287 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : Started AdminApplicationKt in 3.737 seconds (process running for 4.033) + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + + :: Spring Boot :: (v3.3.4) + +2024-11-04T03:42:00.711+09:00 INFO 57805 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : Starting AdminApplicationKt v1.2.0 using Java 17.0.11 with PID 57805 (/Users/weeds2577/DMU-BackEnd/dmforu-admin/build/libs/dmforu-admin-1.2.0.jar started by weeds2577 in /Users/weeds2577/DMU-BackEnd) +2024-11-04T03:42:00.713+09:00 INFO 57805 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : The following 1 profile is active: "local" +2024-11-04T03:42:01.123+09:00 INFO 57805 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode +2024-11-04T03:42:01.124+09:00 INFO 57805 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data MongoDB repositories in DEFAULT mode. +2024-11-04T03:42:01.150+09:00 INFO 57805 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 23 ms. Found 2 MongoDB repository interfaces. +2024-11-04T03:42:01.154+09:00 INFO 57805 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode +2024-11-04T03:42:01.155+09:00 INFO 57805 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. +2024-11-04T03:42:01.164+09:00 INFO 57805 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 7 ms. Found 2 JPA repository interfaces. +2024-11-04T03:42:01.687+09:00 INFO 57805 --- [dmforu-admin] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2024-11-04T03:42:01.698+09:00 INFO 57805 --- [dmforu-admin] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2024-11-04T03:42:01.698+09:00 INFO 57805 --- [dmforu-admin] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.30] +2024-11-04T03:42:01.730+09:00 INFO 57805 --- [dmforu-admin] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2024-11-04T03:42:01.731+09:00 INFO 57805 --- [dmforu-admin] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 983 ms +2024-11-04T03:42:01.846+09:00 INFO 57805 --- [dmforu-admin] [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] +2024-11-04T03:42:01.901+09:00 INFO 57805 --- [dmforu-admin] [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.5.3.Final +2024-11-04T03:42:01.932+09:00 INFO 57805 --- [dmforu-admin] [ main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled +2024-11-04T03:42:02.189+09:00 INFO 57805 --- [dmforu-admin] [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer +2024-11-04T03:42:02.215+09:00 INFO 57805 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... +2024-11-04T03:42:02.427+09:00 INFO 57805 --- [dmforu-admin] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@287ad0da +2024-11-04T03:42:02.428+09:00 INFO 57805 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. +2024-11-04T03:42:02.464+09:00 WARN 57805 --- [dmforu-admin] [ main] org.hibernate.orm.deprecation : HHH90000025: MySQLDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default) +2024-11-04T03:42:03.075+09:00 INFO 57805 --- [dmforu-admin] [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) +2024-11-04T03:42:03.077+09:00 INFO 57805 --- [dmforu-admin] [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' +2024-11-04T03:42:03.350+09:00 INFO 57805 --- [dmforu-admin] [ main] o.s.d.j.r.query.QueryEnhancerFactory : Hibernate is in classpath; If applicable, HQL parser will be used. +2024-11-04T03:42:03.757+09:00 INFO 57805 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-02.qlvx9.mongodb.net:27017 to client view of cluster +2024-11-04T03:42:03.775+09:00 INFO 57805 --- [dmforu-admin] [ main] org.mongodb.driver.client : MongoClient with metadata {"application": {"name": "dmforu-test"}, "driver": {"name": "mongo-java-driver|sync", "version": "5.0.1"}, "os": {"type": "Darwin", "name": "Mac OS X", "architecture": "aarch64", "version": "14.2.1"}, "platform": "Java/Oracle Corporation/17.0.11+7-LTS-207"} created with settings MongoClientSettings{readPreference=primary, writeConcern=WriteConcern{w=majority, wTimeout=null ms, journal=null}, retryWrites=true, retryReads=true, readConcern=ReadConcern{level=null}, credential=MongoCredential{mechanism=null, userName='weeds2577', source='admin', password=, mechanismProperties=}, transportSettings=null, commandListeners=[], codecRegistry=ProvidersCodecRegistry{codecProviders=[ProvidersCodecRegistry{codecProviders=[ValueCodecProvider{}, BsonValueCodecProvider{}, DBRefCodecProvider{}, DBObjectCodecProvider{}, DocumentCodecProvider{}, CollectionCodecProvider{}, IterableCodecProvider{}, MapCodecProvider{}, GeoJsonCodecProvider{}, GridFSFileCodecProvider{}, Jsr310CodecProvider{}, JsonObjectCodecProvider{}, BsonCodecProvider{}, EnumCodecProvider{}, com.mongodb.client.model.mql.ExpressionCodecProvider@7f5a5ef3, com.mongodb.Jep395RecordCodecProvider@4c53ce60, com.mongodb.KotlinCodecProvider@3d1b6816]}, ProvidersCodecRegistry{codecProviders=[org.bson.codecs.pojo.PojoCodecProvider@508863eb]}]}, loggerSettings=LoggerSettings{maxDocumentLength=1000}, clusterSettings={hosts=[127.0.0.1:27017], srvHost=dmforu-test.qlvx9.mongodb.net, srvServiceName=mongodb, mode=MULTIPLE, requiredClusterType=REPLICA_SET, requiredReplicaSetName='atlas-m6kxjp-shard-0', serverSelector='null', clusterListeners='[]', serverSelectionTimeout='30000 ms', localThreshold='15 ms'}, socketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=0, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, heartbeatSocketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=10000, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, connectionPoolSettings=ConnectionPoolSettings{maxSize=100, minSize=0, maxWaitTimeMS=120000, maxConnectionLifeTimeMS=0, maxConnectionIdleTimeMS=0, maintenanceInitialDelayMS=0, maintenanceFrequencyMS=60000, connectionPoolListeners=[], maxConnecting=2}, serverSettings=ServerSettings{heartbeatFrequencyMS=10000, minHeartbeatFrequencyMS=500, serverListeners='[]', serverMonitorListeners='[]'}, sslSettings=SslSettings{enabled=true, invalidHostNameAllowed=false, context=null}, applicationName='dmforu-test', compressorList=[], uuidRepresentation=UNSPECIFIED, serverApi=null, autoEncryptionSettings=null, dnsClient=null, inetAddressResolver=null, contextProvider=null} +2024-11-04T03:42:03.789+09:00 INFO 57805 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-00.qlvx9.mongodb.net:27017 to client view of cluster +2024-11-04T03:42:03.790+09:00 INFO 57805 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-01.qlvx9.mongodb.net:27017 to client view of cluster +2024-11-04T03:42:04.040+09:00 WARN 57805 --- [dmforu-admin] [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning +2024-11-04T03:42:04.292+09:00 INFO 57805 --- [dmforu-admin] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' +2024-11-04T03:42:04.301+09:00 INFO 57805 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=452648500, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az2'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=9, topologyVersion=TopologyVersion{processId=67220b6eb3ac540c1b3d2884, counter=3}, lastWriteDate=Mon Nov 04 03:42:04 KST 2024, lastUpdateTimeNanos=881451174170083} +2024-11-04T03:42:04.302+09:00 INFO 57805 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=452632125, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az3'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=7fffffff00000000000000aa, setVersion=9, topologyVersion=TopologyVersion{processId=67220879494685dc7d977f3a, counter=6}, lastWriteDate=Mon Nov 04 03:42:04 KST 2024, lastUpdateTimeNanos=881451174170083} +2024-11-04T03:42:04.307+09:00 INFO 57805 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Discovered replica set primary dmforu-test-shard-00-01.qlvx9.mongodb.net:27017 with max election id 7fffffff00000000000000aa and max set version 9 +2024-11-04T03:42:04.308+09:00 INFO 57805 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : Started AdminApplicationKt in 3.892 seconds (process running for 4.302) +2024-11-04T03:42:04.311+09:00 INFO 57805 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-00.qlvx9.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=55025791, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-00.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az1'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=9, topologyVersion=TopologyVersion{processId=67220a16b5fcab00b1d9f81a, counter=4}, lastWriteDate=Mon Nov 04 03:42:04 KST 2024, lastUpdateTimeNanos=881451184974083} From c3b26f3d77ec3d5612d1d481f78c2b255c4a2070 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:54:22 +0900 Subject: [PATCH 196/223] =?UTF-8?q?refactor:=20number=20=EA=B0=92=EC=9D=B4?= =?UTF-8?q?=20=EC=88=AB=EC=9E=90=EA=B0=80=20=EC=95=84=EB=8B=8C=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=ED=8C=A8=EC=8A=A4=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/crawling/parser/DepartmentNoticeParser.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt index 68f25cb..0afb9f5 100644 --- a/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt +++ b/dmforu-crawling/src/main/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParser.kt @@ -24,7 +24,7 @@ class DepartmentNoticeParser( val document = htmlLoader.get(generateSearchUrl()) return document.select(".board-table tbody tr") - .map { row -> parseRow(row) } + .mapNotNull { row -> parseRow(row) } .toList() } @@ -33,8 +33,8 @@ class DepartmentNoticeParser( this.major = major } - private fun parseRow(row: Element): Notice { - val number = row.select(".td-num").text().toInt() + private fun parseRow(row: Element): Notice? { + val number = row.select(".td-num").text().toIntOrNull() ?: return null val title = row.select(".td-subject a").text() val author = row.select(".td-write").text() val url = generateUrlFromSearch(row.select(".td-subject a").attr("href")) From bdd9f941ecfd95d4bb4fc130cbe797cbf25f9f24 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:55:07 +0900 Subject: [PATCH 197/223] =?UTF-8?q?refactor:=20Mongo=EC=9D=98=20=ED=8A=B8?= =?UTF-8?q?=EB=9E=9C=EC=9E=AD=EC=85=98=EC=9D=84=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EC=A4=91=EB=8B=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/storage/db/mongo/config/MongoConfig.kt | 8 ++++---- .../dmforu/storage/db/mongo/diet/DietEntityRepository.kt | 2 +- .../storage/db/mongo/schedule/ScheduleEntityRepository.kt | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/config/MongoConfig.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/config/MongoConfig.kt index a9824e4..b55df76 100644 --- a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/config/MongoConfig.kt +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/config/MongoConfig.kt @@ -44,9 +44,9 @@ internal class MongoConfig( return MongoTemplate(mongoClient(), database) } - @Bean - fun transactionManager(mongoDatabaseFactory: MongoDatabaseFactory): MongoTransactionManager{ - return MongoTransactionManager(mongoDatabaseFactory) - } +// @Bean +// fun transactionManager(mongoDatabaseFactory: MongoDatabaseFactory): MongoTransactionManager{ +// return MongoTransactionManager(mongoDatabaseFactory) +// } } diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepository.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepository.kt index 51cdc9e..94de41c 100644 --- a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepository.kt +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/diet/DietEntityRepository.kt @@ -10,7 +10,7 @@ internal class DietEntityRepository( private val dietRepository: DietMongoRepository, ) : DietRepository { - @Transactional +// @Transactional override fun write(diets: List) { dietRepository.deleteAll() dietRepository.save(DietMapper.mapToEntity(diets)) diff --git a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityRepository.kt b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityRepository.kt index 4b4f094..dbd4430 100644 --- a/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityRepository.kt +++ b/dmforu-infrastructure/storage/mongo/src/main/kotlin/com/dmforu/storage/db/mongo/schedule/ScheduleEntityRepository.kt @@ -10,7 +10,7 @@ internal class ScheduleEntityRepository( private val scheduleMongoRepository: ScheduleMongoRepository ) : ScheduleRepository { - @Transactional +// @Transactional override fun write(schedules: List) { scheduleMongoRepository.deleteAll() scheduleMongoRepository.save(ScheduleMapper.mapToEntity(schedules)) From 841ac9c18bbe0f3f6ac246787d3c57c7f3ec308a Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 4 Nov 2024 21:31:24 +0900 Subject: [PATCH 198/223] =?UTF-8?q?fix:=20time=20zone=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/dmforu/admin/AdminApplication.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt index d3a33f8..b088460 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt @@ -3,8 +3,8 @@ package com.dmforu.admin import org.springframework.boot.WebApplicationType import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.builder.SpringApplicationBuilder -import org.springframework.boot.runApplication import org.springframework.scheduling.annotation.EnableScheduling +import java.util.* @SpringBootApplication( scanBasePackages = [ @@ -18,6 +18,7 @@ import org.springframework.scheduling.annotation.EnableScheduling class AdminApplication fun main(args: Array) { + TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul")) SpringApplicationBuilder(AdminApplication::class.java) .web(WebApplicationType.NONE) .run(*args) From 0329cd0b6b03246202e7bcf8d3bd09e672ad595b Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 4 Nov 2024 23:29:10 +0900 Subject: [PATCH 199/223] =?UTF-8?q?refactor:=20ApiResponse=20=EB=82=B4?= =?UTF-8?q?=EB=B6=80=EC=97=90=20=EC=84=B1=EA=B3=B5=EA=B3=BC=20=EC=8B=A4?= =?UTF-8?q?=ED=8C=A8=EA=B0=80=20=EA=B0=99=EC=9D=B4=20=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=EB=B6=80=EB=B6=84=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/ApiControllerAdvice.kt | 13 +-- .../api/support/response/ApiResponse.kt | 18 ++-- .../api/controller/v1/DietControllerTest.kt | 1 - .../api/controller/v1/NoticeControllerTest.kt | 69 ++++++--------- .../controller/v1/ScheduleControllerTest.kt | 1 - .../controller/v1/SubscribeControllerTest.kt | 84 ++++++++----------- 6 files changed, 78 insertions(+), 108 deletions(-) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt index 29b70ce..90a7672 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt @@ -1,6 +1,7 @@ package com.dmforu.api.controller import com.dmforu.api.support.error.AppException +import com.dmforu.api.support.error.ErrorMessage import com.dmforu.api.support.error.ErrorType import com.dmforu.api.support.response.ApiResponse import org.slf4j.Logger @@ -19,7 +20,7 @@ class ApiControllerAdvice { private val log: Logger = LoggerFactory.getLogger(javaClass) @ExceptionHandler(AppException::class) - fun handleAppException(e: AppException): ResponseEntity> { + fun handleAppException(e: AppException): ResponseEntity> { when (e.errorType.logLevel) { LogLevel.ERROR -> log.error("AppException : {}", e.message, e) LogLevel.WARN -> log.warn("AppException : {}", e.message, e) @@ -29,29 +30,29 @@ class ApiControllerAdvice { } @ExceptionHandler(NoHandlerFoundException::class) - fun handleNoResourceFoundException(e: NoHandlerFoundException): ResponseEntity> { + fun handleNoResourceFoundException(e: NoHandlerFoundException): ResponseEntity> { return ResponseEntity(ApiResponse.error(ErrorType.NOT_FOUND_ERROR), ErrorType.NOT_FOUND_ERROR.status) } @ExceptionHandler(NoResourceFoundException::class) - fun handleNoResourceFoundException(e: NoResourceFoundException): ResponseEntity> { + fun handleNoResourceFoundException(e: NoResourceFoundException): ResponseEntity> { return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) } @ExceptionHandler(MethodArgumentNotValidException::class) - fun handleRequestBodyException(e: MethodArgumentNotValidException): ResponseEntity> { + fun handleRequestBodyException(e: MethodArgumentNotValidException): ResponseEntity> { log.error("MethodArgumentNotValidException : {}", e.message, e) return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR, e.fieldError?.defaultMessage), ErrorType.BAD_REQUEST_ERROR.status) } @ExceptionHandler(MissingServletRequestParameterException::class) - fun handleRequestParamException(e: MissingServletRequestParameterException): ResponseEntity> { + fun handleRequestParamException(e: MissingServletRequestParameterException): ResponseEntity> { log.error("RequestParamException : {}", e.message, e) return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) } @ExceptionHandler(Exception::class) - fun handleException(e: Exception): ResponseEntity> { + fun handleException(e: Exception): ResponseEntity> { log.error("Exception : {}", e.message, e) return ResponseEntity(ApiResponse.error(ErrorType.SERVER_ERROR), ErrorType.SERVER_ERROR.status) } diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ApiResponse.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ApiResponse.kt index b231570..25d1c73 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ApiResponse.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ApiResponse.kt @@ -6,23 +6,27 @@ import com.dmforu.api.support.error.ErrorType data class ApiResponse private constructor( val result: ResultType, val data: T? = null, - val error: ErrorMessage? = null, +// val error: ErrorMessage? = null, ) { companion object { fun success(): ApiResponse { - return ApiResponse(ResultType.SUCCESS, null, null) + return ApiResponse(ResultType.SUCCESS, null) } fun create(): ApiResponse { - return ApiResponse(ResultType.CREATE, null, null) + return ApiResponse(ResultType.CREATE, null) } - fun success(data: S): ApiResponse { - return ApiResponse(ResultType.SUCCESS, data, null) + fun error(error: ErrorType, errorData: Any? = null): ApiResponse { + return ApiResponse(ResultType.ERROR, ErrorMessage(error, errorData)) } - fun error(error: ErrorType, errorData: Any? = null): ApiResponse { - return ApiResponse(ResultType.ERROR, null, ErrorMessage(error, errorData)) + fun success(data: S): ApiResponse { + return ApiResponse(ResultType.SUCCESS, data) } + +// fun error(error: ErrorType, errorData: S): ApiResponse { +// return ApiResponse(ResultType.ERROR, ErrorMessage(error, errorData)) +// } } } diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt index 819d893..c3a4e49 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt @@ -22,6 +22,5 @@ class DietControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) - .andExpect(jsonPath("$.error").isEmpty) } } \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt index ab7157f..1735c7c 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt @@ -31,7 +31,6 @@ class NoticeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) - .andExpect(jsonPath("$.error").isEmpty) } @DisplayName("학과 공지를 불러온다.") @@ -51,7 +50,6 @@ class NoticeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) - .andExpect(jsonPath("$.error").isEmpty) } @DisplayName("학과 공지를 불러올 때, 학과는 필수 값이다.") @@ -65,10 +63,9 @@ class NoticeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").isEmpty) - .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").isEmpty) } @@ -89,7 +86,6 @@ class NoticeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) - .andExpect(jsonPath("$.error").isEmpty) } @DisplayName("공지를 검색할 때, 학과는 필수 값이다.") @@ -103,10 +99,9 @@ class NoticeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").isEmpty) - .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").isEmpty) } @DisplayName("공지를 검색할 때, 검색어는 필수 값이다. ") @@ -121,10 +116,9 @@ class NoticeControllerTest : ControllerTestSupport() { ) .andExpect(status().isNotFound) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E404.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 URL로 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").isEmpty) - .andExpect(jsonPath("$.data").isEmpty) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E404.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 URL로 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").isEmpty) } @DisplayName("공지를 불러올 때, 페이지네이션 값이 빠져있다면 페이지 1, 사이즈 20으로 자동 설정된다.") @@ -143,7 +137,6 @@ class NoticeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) - .andExpect(jsonPath("$.error").isEmpty) mockMvc.perform( get("/api/v1/notice/department") @@ -153,7 +146,6 @@ class NoticeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) - .andExpect(jsonPath("$.error").isEmpty) mockMvc.perform( get("/api/v1/notice/공지사항") @@ -163,7 +155,6 @@ class NoticeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) - .andExpect(jsonPath("$.error").isEmpty) } @DisplayName("공지를 불러올 때, 페이지의 값은 1이상이어야 한다.") @@ -183,10 +174,9 @@ class NoticeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("페이지는 1이상이어야 합니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("페이지는 1이상이어야 합니다.")) mockMvc.perform( get("/api/v1/notice/department") @@ -197,10 +187,9 @@ class NoticeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("페이지는 1이상이어야 합니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("페이지는 1이상이어야 합니다.")) mockMvc.perform( get("/api/v1/notice/공지사항") @@ -211,10 +200,9 @@ class NoticeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("페이지는 1이상이어야 합니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("페이지는 1이상이어야 합니다.")) } @DisplayName("공지를 불러올 때, 사이즈의 값은 1이상이어야 한다.") @@ -234,10 +222,9 @@ class NoticeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("사이즈는 1이상이어야 합니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("사이즈는 1이상이어야 합니다.")) mockMvc.perform( get("/api/v1/notice/department") @@ -248,10 +235,9 @@ class NoticeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("사이즈는 1이상이어야 합니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("사이즈는 1이상이어야 합니다.")) mockMvc.perform( get("/api/v1/notice/공지사항") @@ -262,9 +248,8 @@ class NoticeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("사이즈는 1이상이어야 합니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("사이즈는 1이상이어야 합니다.")) } } \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt index 959577b..d4e3f77 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt @@ -27,6 +27,5 @@ class ScheduleControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) - .andExpect(jsonPath("$.error").isEmpty) } } diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt index 9bdfdd5..e387353 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt @@ -38,7 +38,6 @@ class SubscribeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.CREATE.name)) .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error").isEmpty) } @DisplayName("구독을 생성할 때, 토큰은 필수 값이다.") @@ -61,10 +60,9 @@ class SubscribeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("토큰은 필수입니다.")) } @DisplayName("구독을 생성할 때, 학과는 필수 값이다.") @@ -87,10 +85,9 @@ class SubscribeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("학과는 필수입니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("학과는 필수입니다.")) } @DisplayName("구독을 생성할 때, 키워드는 필수 값이 아니다.") @@ -114,7 +111,6 @@ class SubscribeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.CREATE.name)) .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error").isEmpty) } @DisplayName("구독을 생성할 때, 학과 구독 상태는 필수 값이다.") @@ -137,10 +133,9 @@ class SubscribeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("학과 구독 상태는 필수입니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("학과 구독 상태는 필수입니다.")) } @DisplayName("구독을 생성할 때, 키워드 구독 상태는 필수 값이다.") @@ -163,10 +158,9 @@ class SubscribeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("키워드 구독 상태는 필수입니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("키워드 구독 상태는 필수입니다.")) } @DisplayName("구독 키워드를 업데이트한다.") @@ -187,7 +181,6 @@ class SubscribeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error").isEmpty) } @DisplayName("구독 키워드를 업데이트할 때, 토큰은 필수 값이다.") @@ -207,10 +200,9 @@ class SubscribeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("토큰은 필수입니다.")) } @DisplayName("구독 키워드를 업데이트할 때, 키워드는 필수 값이 아니다. - 키워드를 전부 지워버릴 수 있기 때문") @@ -231,7 +223,6 @@ class SubscribeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error").isEmpty) } @DisplayName("키워드 알림 상태를 변경한다.") @@ -252,7 +243,6 @@ class SubscribeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error").isEmpty) } @DisplayName("키워드 알림 상태를 변경할 때, 토큰은 필수 값이다.") @@ -272,10 +262,9 @@ class SubscribeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("토큰은 필수입니다.")) } @DisplayName("키워드 알림 상태를 변경할 때, 구독 상태는 필수 값이다.") @@ -295,10 +284,9 @@ class SubscribeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("구독 상태는 필수입니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("구독 상태는 필수입니다.")) } @DisplayName("구독 학과를 업데이트한다.") @@ -319,7 +307,6 @@ class SubscribeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error").isEmpty) } @DisplayName("구독 학과를 업데이트할 때, 토큰은 필수 값이다.") @@ -339,10 +326,9 @@ class SubscribeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("토큰은 필수입니다.")) } @DisplayName("구독 학과를 업데이트할 때, 학과는 필수 값이다.") @@ -362,10 +348,9 @@ class SubscribeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("학과는 필수입니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("학과는 필수입니다.")) } @DisplayName("학과 알림 상태를 변경한다.") @@ -386,7 +371,6 @@ class SubscribeControllerTest : ControllerTestSupport() { .andExpect(status().isOk()) .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error").isEmpty) } @DisplayName("학과 알림 상태를 변경할 때, 토큰은 필수 값이다.") @@ -406,10 +390,9 @@ class SubscribeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("토큰은 필수입니다.")) } @DisplayName("키워드 알림 상태를 변경할 때, 구독 상태 필수 값이다.") @@ -429,9 +412,8 @@ class SubscribeControllerTest : ControllerTestSupport() { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data").isEmpty) - .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.error.data").value("구독 상태는 필수입니다.")) + .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.data.data").value("구독 상태는 필수입니다.")) } } From d9306f5722729ccd4cfd2f136c0bdd5ee0f6cc99 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 00:09:09 +0900 Subject: [PATCH 200/223] =?UTF-8?q?refactor:=20ApiResponse=EB=A5=BC=20Erro?= =?UTF-8?q?rResponse=EC=99=80=20SuccessResponse=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/ApiControllerAdvice.kt | 13 +- .../api/controller/v1/DietController.kt | 3 +- .../api/controller/v1/NoticeController.kt | 7 +- .../api/controller/v1/ScheduleController.kt | 3 +- .../api/controller/v1/SubscribeController.kt | 23 ++-- .../api/support/response/ApiResponse.kt | 31 +---- .../api/support/response/ErrorResponse.kt | 17 +++ .../dmforu/api/support/response/ResultType.kt | 7 -- .../api/support/response/SuccessResponse.kt | 21 ++++ .../api/controller/v1/DietControllerTest.kt | 2 - .../api/controller/v1/NoticeControllerTest.kt | 70 +++++------ .../controller/v1/ScheduleControllerTest.kt | 2 - .../controller/v1/SubscribeControllerTest.kt | 113 ++++++++---------- 13 files changed, 141 insertions(+), 171 deletions(-) create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ErrorResponse.kt delete mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ResultType.kt create mode 100644 dmforu-api/src/main/kotlin/com/dmforu/api/support/response/SuccessResponse.kt diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt index 90a7672..7306ff1 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt @@ -4,6 +4,7 @@ import com.dmforu.api.support.error.AppException import com.dmforu.api.support.error.ErrorMessage import com.dmforu.api.support.error.ErrorType import com.dmforu.api.support.response.ApiResponse +import com.dmforu.api.support.response.ErrorResponse import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.boot.logging.LogLevel @@ -26,34 +27,34 @@ class ApiControllerAdvice { LogLevel.WARN -> log.warn("AppException : {}", e.message, e) else -> log.info("AppException : {}", e.message, e) } - return ResponseEntity(ApiResponse.error(e.errorType, e.data), e.errorType.status) + return ResponseEntity(ErrorResponse.error(e.errorType, e.data), e.errorType.status) } @ExceptionHandler(NoHandlerFoundException::class) fun handleNoResourceFoundException(e: NoHandlerFoundException): ResponseEntity> { - return ResponseEntity(ApiResponse.error(ErrorType.NOT_FOUND_ERROR), ErrorType.NOT_FOUND_ERROR.status) + return ResponseEntity(ErrorResponse.error(ErrorType.NOT_FOUND_ERROR), ErrorType.NOT_FOUND_ERROR.status) } @ExceptionHandler(NoResourceFoundException::class) fun handleNoResourceFoundException(e: NoResourceFoundException): ResponseEntity> { - return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) + return ResponseEntity(ErrorResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) } @ExceptionHandler(MethodArgumentNotValidException::class) fun handleRequestBodyException(e: MethodArgumentNotValidException): ResponseEntity> { log.error("MethodArgumentNotValidException : {}", e.message, e) - return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR, e.fieldError?.defaultMessage), ErrorType.BAD_REQUEST_ERROR.status) + return ResponseEntity(ErrorResponse.error(ErrorType.BAD_REQUEST_ERROR, e.fieldError?.defaultMessage), ErrorType.BAD_REQUEST_ERROR.status) } @ExceptionHandler(MissingServletRequestParameterException::class) fun handleRequestParamException(e: MissingServletRequestParameterException): ResponseEntity> { log.error("RequestParamException : {}", e.message, e) - return ResponseEntity(ApiResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) + return ResponseEntity(ErrorResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) } @ExceptionHandler(Exception::class) fun handleException(e: Exception): ResponseEntity> { log.error("Exception : {}", e.message, e) - return ResponseEntity(ApiResponse.error(ErrorType.SERVER_ERROR), ErrorType.SERVER_ERROR.status) + return ResponseEntity(ErrorResponse.error(ErrorType.SERVER_ERROR), ErrorType.SERVER_ERROR.status) } } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt index ab1115a..2481deb 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/DietController.kt @@ -1,6 +1,7 @@ package com.dmforu.api.controller.v1 import com.dmforu.api.support.response.ApiResponse +import com.dmforu.api.support.response.SuccessResponse import com.dmforu.domain.diet.Diet import com.dmforu.domain.diet.DietReader import io.swagger.v3.oas.annotations.Operation @@ -19,6 +20,6 @@ class DietController( ) @GetMapping("/api/v1/cafeteria") fun readDiet(): ApiResponse> { - return ApiResponse.success(dietReader.read()) + return SuccessResponse.success(dietReader.read()) } } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt index 1d6cb39..696b955 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/NoticeController.kt @@ -3,6 +3,7 @@ package com.dmforu.api.controller.v1 import com.dmforu.api.controller.v1.request.PaginationRequest import com.dmforu.api.controller.v1.response.NoticeResponse import com.dmforu.api.support.response.ApiResponse +import com.dmforu.api.support.response.SuccessResponse import com.dmforu.domain.notice.NoticeReader import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag @@ -27,7 +28,7 @@ class NoticeController( page = paginationRequest.page, size = paginationRequest.size ).map { NoticeResponse.form(it) } - return ApiResponse.success(universityNotices) + return SuccessResponse.success(universityNotices) } @Operation( @@ -45,7 +46,7 @@ class NoticeController( page = paginationRequest.page, size = paginationRequest.size ).map { NoticeResponse.form(it) } - return ApiResponse.success(departmentNotices) + return SuccessResponse.success(departmentNotices) } @Operation( @@ -64,6 +65,6 @@ class NoticeController( page = paginationRequest.page, size = paginationRequest.size ).map { NoticeResponse.form(it) } - return ApiResponse.success(notices) + return SuccessResponse.success(notices) } } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt index e222aab..d3d0eeb 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/ScheduleController.kt @@ -1,6 +1,7 @@ package com.dmforu.api.controller.v1 import com.dmforu.api.support.response.ApiResponse +import com.dmforu.api.support.response.SuccessResponse import com.dmforu.domain.schedule.Schedule import com.dmforu.domain.schedule.ScheduleReader import io.swagger.v3.oas.annotations.Operation @@ -19,6 +20,6 @@ class ScheduleController( description = "현재년도를 기준으로 작년부터 내년 2월까지의 학사일정을 출력한다." ) fun raedSchedule(): ApiResponse> { - return ApiResponse.success(scheduleReader.read()) + return SuccessResponse.success(scheduleReader.read()) } } \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt index 143bec6..c6d0ce3 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/v1/SubscribeController.kt @@ -2,11 +2,14 @@ package com.dmforu.api.controller.v1 import com.dmforu.api.controller.v1.request.* import com.dmforu.api.support.response.ApiResponse +import com.dmforu.api.support.response.SuccessResponse import com.dmforu.domain.subscribe.SubscribeUpdater import com.dmforu.domain.subscribe.SubscribeWriter import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag import jakarta.validation.Valid +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PatchMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody @@ -20,43 +23,43 @@ class SubscribeController( ) { @Operation(summary = "최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") @PostMapping("/api/v1/subscribe/registration") - fun initSubscribe(@Valid @RequestBody request: RegisterSubscribeRequest): ApiResponse { + fun initSubscribe(@Valid @RequestBody request: RegisterSubscribeRequest): ResponseEntity> { subscribeWriter.write(request.toSubscribe()) - return ApiResponse.create() + return ResponseEntity(SuccessResponse.create(), HttpStatus.CREATED) } @Operation(summary = "키워드 수정 API", description = "알림 키워드를 수정한다.") @PatchMapping("/api/v1/subscribe/keywords") - fun updateSubscribeKeywords(@Valid @RequestBody request: UpdateSubscribeKeywordsRequest): ApiResponse { + fun updateSubscribeKeywords(@Valid @RequestBody request: UpdateSubscribeKeywordsRequest): ResponseEntity> { subscribeUpdater.updateKeywords(token = request.token!!, keywords = request.keywords) - return ApiResponse.success() + return ResponseEntity(SuccessResponse.success(), HttpStatus.NO_CONTENT) } @Operation(summary = "키워드 알림 상태 변경 API", description = "키워드 알림 상태를 변경한다.") @PatchMapping("/api/v1/subscribe/keyword/status") - fun updateSubscribeKeywordStatus(@Valid @RequestBody request: UpdateSubscribeStatusRequest): ApiResponse { + fun updateSubscribeKeywordStatus(@Valid @RequestBody request: UpdateSubscribeStatusRequest): ResponseEntity> { subscribeUpdater.updateKeywordSubscribeStatus( token = request.token!!, keywordSubscribeStatus = request.subscribeStatus!! ) - return ApiResponse.success() + return ResponseEntity(SuccessResponse.success(), HttpStatus.NO_CONTENT) } @Operation(summary = "학과 수정 API", description = "학과 정보를 수정한다.") @PatchMapping("/api/v1/subscribe/department") - fun updateSubscribeDepartment(@Valid @RequestBody request: UpdateSubscribeDepartmentRequest): ApiResponse { + fun updateSubscribeDepartment(@Valid @RequestBody request: UpdateSubscribeDepartmentRequest): ResponseEntity> { subscribeUpdater.updateDepartment(token = request.token, department = request.department) - return ApiResponse.success() + return ResponseEntity(SuccessResponse.success(), HttpStatus.NO_CONTENT) } @Operation(summary = "학과 알림 상태 변경 API", description = "학과 알림 상태를 변경한다.") @PatchMapping("/api/v1/subscribe/department/status") - fun updateSubscribeDepartmentStatus(@Valid @RequestBody request: UpdateSubscribeStatusRequest): ApiResponse { + fun updateSubscribeDepartmentStatus(@Valid @RequestBody request: UpdateSubscribeStatusRequest): ResponseEntity> { subscribeUpdater.updateDepartmentSubscribeStatus( token = request.token!!, departmentSubscribeStatus = request.subscribeStatus!! ) - return ApiResponse.success() + return ResponseEntity(SuccessResponse.success(), HttpStatus.NO_CONTENT) } } diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ApiResponse.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ApiResponse.kt index 25d1c73..c0858e5 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ApiResponse.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ApiResponse.kt @@ -1,32 +1,3 @@ package com.dmforu.api.support.response -import com.dmforu.api.support.error.ErrorMessage -import com.dmforu.api.support.error.ErrorType - -data class ApiResponse private constructor( - val result: ResultType, - val data: T? = null, -// val error: ErrorMessage? = null, -) { - companion object { - fun success(): ApiResponse { - return ApiResponse(ResultType.SUCCESS, null) - } - - fun create(): ApiResponse { - return ApiResponse(ResultType.CREATE, null) - } - - fun error(error: ErrorType, errorData: Any? = null): ApiResponse { - return ApiResponse(ResultType.ERROR, ErrorMessage(error, errorData)) - } - - fun success(data: S): ApiResponse { - return ApiResponse(ResultType.SUCCESS, data) - } - -// fun error(error: ErrorType, errorData: S): ApiResponse { -// return ApiResponse(ResultType.ERROR, ErrorMessage(error, errorData)) -// } - } -} +sealed class ApiResponse diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ErrorResponse.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ErrorResponse.kt new file mode 100644 index 0000000..849ceed --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ErrorResponse.kt @@ -0,0 +1,17 @@ +package com.dmforu.api.support.response + +import com.dmforu.api.support.error.ErrorMessage +import com.dmforu.api.support.error.ErrorType + +class ErrorResponse private constructor( + val error: T, +) : ApiResponse() { + companion object { + + fun error(error: ErrorType, errorData: Any? = null): ErrorResponse { + return ErrorResponse(ErrorMessage(error, errorData)) + } + + } + +} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ResultType.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ResultType.kt deleted file mode 100644 index 8a98ec5..0000000 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/ResultType.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.dmforu.api.support.response - -enum class ResultType { - SUCCESS, - CREATE, - ERROR, -} \ No newline at end of file diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/SuccessResponse.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/SuccessResponse.kt new file mode 100644 index 0000000..7ed54f1 --- /dev/null +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/support/response/SuccessResponse.kt @@ -0,0 +1,21 @@ +package com.dmforu.api.support.response + +data class SuccessResponse private constructor( + val data: T? = null, +) : ApiResponse() { + companion object { + fun success(): ApiResponse { + return SuccessResponse("요청이 정상적으로 처리되었습니다.") + } + + fun create(): ApiResponse { + return SuccessResponse("정상적으로 생성되었습니다.") + } + + fun success(data: S): SuccessResponse { + return SuccessResponse(data) + } + + } + +} \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt index c3a4e49..033c1c9 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/DietControllerTest.kt @@ -1,7 +1,6 @@ package com.dmforu.api.controller.v1 import com.dmforu.api.ControllerTestSupport -import com.dmforu.api.support.response.ResultType import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test @@ -20,7 +19,6 @@ class DietControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) } } \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt index 1735c7c..1445e8c 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/NoticeControllerTest.kt @@ -2,7 +2,6 @@ package com.dmforu.api.controller.v1 import com.dmforu.api.ControllerTestSupport import com.dmforu.api.support.error.ErrorCode -import com.dmforu.api.support.response.ResultType import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.mockito.ArgumentMatchers.anyInt @@ -29,7 +28,6 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) } @@ -48,7 +46,6 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) } @@ -62,10 +59,9 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").isEmpty) } @@ -84,7 +80,6 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) } @@ -98,10 +93,9 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").isEmpty) } @DisplayName("공지를 검색할 때, 검색어는 필수 값이다. ") @@ -115,10 +109,9 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isNotFound) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E404.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 URL로 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").isEmpty) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E404.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 URL로 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").isEmpty) } @DisplayName("공지를 불러올 때, 페이지네이션 값이 빠져있다면 페이지 1, 사이즈 20으로 자동 설정된다.") @@ -135,7 +128,6 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) mockMvc.perform( @@ -144,7 +136,6 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) mockMvc.perform( @@ -153,7 +144,6 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) } @@ -173,10 +163,9 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("페이지는 1이상이어야 합니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("페이지는 1이상이어야 합니다.")) mockMvc.perform( get("/api/v1/notice/department") @@ -186,10 +175,9 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("페이지는 1이상이어야 합니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("페이지는 1이상이어야 합니다.")) mockMvc.perform( get("/api/v1/notice/공지사항") @@ -199,10 +187,9 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("페이지는 1이상이어야 합니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("페이지는 1이상이어야 합니다.")) } @DisplayName("공지를 불러올 때, 사이즈의 값은 1이상이어야 한다.") @@ -221,10 +208,9 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("사이즈는 1이상이어야 합니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("사이즈는 1이상이어야 합니다.")) mockMvc.perform( get("/api/v1/notice/department") @@ -234,10 +220,9 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("사이즈는 1이상이어야 합니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("사이즈는 1이상이어야 합니다.")) mockMvc.perform( get("/api/v1/notice/공지사항") @@ -247,9 +232,8 @@ class NoticeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("사이즈는 1이상이어야 합니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("사이즈는 1이상이어야 합니다.")) } } \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt index d4e3f77..6d49954 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt @@ -1,7 +1,6 @@ package com.dmforu.api.controller.v1 import com.dmforu.api.ControllerTestSupport -import com.dmforu.api.support.response.ResultType import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test @@ -25,7 +24,6 @@ class ScheduleControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) .andExpect(jsonPath("$.data").isArray) } } diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt index e387353..0d0e8ae 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/SubscribeControllerTest.kt @@ -6,7 +6,6 @@ import com.dmforu.api.controller.v1.request.UpdateSubscribeDepartmentRequest import com.dmforu.api.controller.v1.request.UpdateSubscribeKeywordsRequest import com.dmforu.api.controller.v1.request.UpdateSubscribeStatusRequest import com.dmforu.api.support.error.ErrorCode -import com.dmforu.api.support.response.ResultType import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.springframework.http.MediaType.APPLICATION_JSON @@ -35,9 +34,8 @@ class SubscribeControllerTest : ControllerTestSupport() { .content(objectMapper.writeValueAsString(request)) .contentType(APPLICATION_JSON) ) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.CREATE.name)) - .andExpect(jsonPath("$.data").isEmpty) + .andExpect(status().isCreated) + .andExpect(jsonPath("$.data").value("정상적으로 생성되었습니다.")) } @DisplayName("구독을 생성할 때, 토큰은 필수 값이다.") @@ -59,10 +57,9 @@ class SubscribeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("토큰은 필수입니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) } @DisplayName("구독을 생성할 때, 학과는 필수 값이다.") @@ -84,10 +81,9 @@ class SubscribeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("학과는 필수입니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("학과는 필수입니다.")) } @DisplayName("구독을 생성할 때, 키워드는 필수 값이 아니다.") @@ -108,9 +104,8 @@ class SubscribeControllerTest : ControllerTestSupport() { .content(objectMapper.writeValueAsString(request)) .contentType(APPLICATION_JSON) ) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.CREATE.name)) - .andExpect(jsonPath("$.data").isEmpty) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.data").value("정상적으로 생성되었습니다.")) } @DisplayName("구독을 생성할 때, 학과 구독 상태는 필수 값이다.") @@ -132,10 +127,9 @@ class SubscribeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("학과 구독 상태는 필수입니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("학과 구독 상태는 필수입니다.")) } @DisplayName("구독을 생성할 때, 키워드 구독 상태는 필수 값이다.") @@ -157,10 +151,9 @@ class SubscribeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("키워드 구독 상태는 필수입니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("키워드 구독 상태는 필수입니다.")) } @DisplayName("구독 키워드를 업데이트한다.") @@ -178,9 +171,8 @@ class SubscribeControllerTest : ControllerTestSupport() { .content(objectMapper.writeValueAsString(request)) .contentType(APPLICATION_JSON) ) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) - .andExpect(jsonPath("$.data").isEmpty) + .andExpect(status().isNoContent()) + .andExpect(jsonPath("$.data").value("요청이 정상적으로 처리되었습니다.")) } @DisplayName("구독 키워드를 업데이트할 때, 토큰은 필수 값이다.") @@ -199,10 +191,9 @@ class SubscribeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("토큰은 필수입니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) } @DisplayName("구독 키워드를 업데이트할 때, 키워드는 필수 값이 아니다. - 키워드를 전부 지워버릴 수 있기 때문") @@ -220,9 +211,8 @@ class SubscribeControllerTest : ControllerTestSupport() { .content(objectMapper.writeValueAsString(request)) .contentType(APPLICATION_JSON) ) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) - .andExpect(jsonPath("$.data").isEmpty) + .andExpect(status().isNoContent()) + .andExpect(jsonPath("$.data").value("요청이 정상적으로 처리되었습니다.")) } @DisplayName("키워드 알림 상태를 변경한다.") @@ -240,9 +230,8 @@ class SubscribeControllerTest : ControllerTestSupport() { .content(objectMapper.writeValueAsString(request)) .contentType(APPLICATION_JSON) ) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) - .andExpect(jsonPath("$.data").isEmpty) + .andExpect(status().isNoContent()) + .andExpect(jsonPath("$.data").value("요청이 정상적으로 처리되었습니다.")) } @DisplayName("키워드 알림 상태를 변경할 때, 토큰은 필수 값이다.") @@ -261,10 +250,9 @@ class SubscribeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("토큰은 필수입니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) } @DisplayName("키워드 알림 상태를 변경할 때, 구독 상태는 필수 값이다.") @@ -283,10 +271,9 @@ class SubscribeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("구독 상태는 필수입니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("구독 상태는 필수입니다.")) } @DisplayName("구독 학과를 업데이트한다.") @@ -304,9 +291,8 @@ class SubscribeControllerTest : ControllerTestSupport() { .content(objectMapper.writeValueAsString(request)) .contentType(APPLICATION_JSON) ) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) - .andExpect(jsonPath("$.data").isEmpty) + .andExpect(status().isNoContent()) + .andExpect(jsonPath("$.data").value("요청이 정상적으로 처리되었습니다.")) } @DisplayName("구독 학과를 업데이트할 때, 토큰은 필수 값이다.") @@ -325,10 +311,9 @@ class SubscribeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("토큰은 필수입니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) } @DisplayName("구독 학과를 업데이트할 때, 학과는 필수 값이다.") @@ -347,10 +332,9 @@ class SubscribeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("학과는 필수입니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("학과는 필수입니다.")) } @DisplayName("학과 알림 상태를 변경한다.") @@ -368,9 +352,8 @@ class SubscribeControllerTest : ControllerTestSupport() { .content(objectMapper.writeValueAsString(request)) .contentType(APPLICATION_JSON) ) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.result").value(ResultType.SUCCESS.name)) - .andExpect(jsonPath("$.data").isEmpty) + .andExpect(status().isNoContent()) + .andExpect(jsonPath("$.data").value("요청이 정상적으로 처리되었습니다.")) } @DisplayName("학과 알림 상태를 변경할 때, 토큰은 필수 값이다.") @@ -389,10 +372,9 @@ class SubscribeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("토큰은 필수입니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("토큰은 필수입니다.")) } @DisplayName("키워드 알림 상태를 변경할 때, 구독 상태 필수 값이다.") @@ -411,9 +393,8 @@ class SubscribeControllerTest : ControllerTestSupport() { .contentType(APPLICATION_JSON) ) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.result").value(ResultType.ERROR.name)) - .andExpect(jsonPath("$.data.code").value(ErrorCode.E400.name)) - .andExpect(jsonPath("$.data.message").value("잘못된 요청을 하였습니다.")) - .andExpect(jsonPath("$.data.data").value("구독 상태는 필수입니다.")) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").value("구독 상태는 필수입니다.")) } } From de43fbb22a2177cf9480e22e6a278f46d8e06c6c Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:12:53 +0900 Subject: [PATCH 201/223] =?UTF-8?q?chore:=20jacoco=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=BB=A4=EB=B2=84=EB=A6=AC=EC=A7=80=20=EC=A0=9C?= =?UTF-8?q?=EC=99=B8=20=ED=8F=B4=EB=8D=94=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 2 ++ dmforu-support/jacoco/build.gradle.kts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index f79b8c0..448770a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -75,6 +75,8 @@ subprojects { "**/*Config*", "**/*Dto*", "**/*Error*", + "**/request/**", + "**/response/**", "**/*Request*", "**/*Response*", "**/*Interceptor*", diff --git a/dmforu-support/jacoco/build.gradle.kts b/dmforu-support/jacoco/build.gradle.kts index ca27057..294caa8 100644 --- a/dmforu-support/jacoco/build.gradle.kts +++ b/dmforu-support/jacoco/build.gradle.kts @@ -30,6 +30,8 @@ tasks.testCodeCoverageReport { "**/*Config*", "**/*Dto*", "**/*Error*", + "**/request/**", + "**/response/**", "**/*Request*", "**/*Response*", "**/*Interceptor*", From 1f5e0f0630ccea10b8e84ef799a22bd48c13ef7e Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 02:37:46 +0900 Subject: [PATCH 202/223] =?UTF-8?q?test:=20Diet,=20Schedule=20Crawling=20S?= =?UTF-8?q?ervice=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crawling/DietCrawlingServiceTest.kt | 45 +++++++++++++++++++ .../crawling/ScheduleCrawlingServiceTest.kt | 45 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingServiceTest.kt create mode 100644 dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingServiceTest.kt diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingServiceTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingServiceTest.kt new file mode 100644 index 0000000..7167370 --- /dev/null +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/DietCrawlingServiceTest.kt @@ -0,0 +1,45 @@ +package com.dmforu.admin.scheduler.crawling + +import com.dmforu.crawling.parser.DietParser +import com.dmforu.domain.diet.Diet +import com.dmforu.domain.diet.DietWriter +import com.dmforu.domain.schedule.Schedule +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any + +@ExtendWith(MockitoExtension::class) +class DietCrawlingServiceTest { + + @Mock + private lateinit var dietParser: DietParser + + @Mock + private lateinit var dietWriter: DietWriter + + @InjectMocks + private lateinit var dietCrawlingService: DietCrawlingService + + @DisplayName("새로운 식단표를 덮어쓴다.") + @Test + fun updateToRecentSchedule() { + // given + val parseResult: List = mock() + given(dietParser.parse()).willReturn(parseResult) + + // when + dietCrawlingService.updateToRecentDiet() + + // then + verify(dietParser).parse() + verify(dietWriter).overwrite(any()) + + } +} \ No newline at end of file diff --git a/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingServiceTest.kt b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingServiceTest.kt new file mode 100644 index 0000000..d3491d4 --- /dev/null +++ b/dmforu-admin/src/test/kotlin/com/dmforu/admin/scheduler/crawling/ScheduleCrawlingServiceTest.kt @@ -0,0 +1,45 @@ +package com.dmforu.admin.scheduler.crawling + +import com.dmforu.crawling.parser.ScheduleParser +import com.dmforu.domain.schedule.Schedule +import com.dmforu.domain.schedule.ScheduleWriter +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.BDDMockito.given +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any + +@ExtendWith(MockitoExtension::class) +class ScheduleCrawlingServiceTest { + + @Mock + private lateinit var scheduleParser: ScheduleParser + + @Mock + private lateinit var scheduleWriter: ScheduleWriter + + @InjectMocks + private lateinit var scheduleCrawlingService: ScheduleCrawlingService + + @DisplayName("새로운 학사 일정을 덮어쓴다.") + @Test + fun updateToRecentSchedule() { + // given + val parseResult: List = mock() + given(scheduleParser.parse(any())).willReturn(parseResult) + + // when + scheduleCrawlingService.updateToRecentSchedule() + + // then + verify(scheduleParser).parse(any()) + verify(scheduleWriter).overwrite(any()) + + } +} \ No newline at end of file From c566e88511af3f95879af4d56f4f33407c967efa Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 02:49:04 +0900 Subject: [PATCH 203/223] =?UTF-8?q?refactor:=20No=20Resource=20Found=20Exc?= =?UTF-8?q?eption=20Handler=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt index 7306ff1..3e78949 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/ApiControllerAdvice.kt @@ -35,11 +35,6 @@ class ApiControllerAdvice { return ResponseEntity(ErrorResponse.error(ErrorType.NOT_FOUND_ERROR), ErrorType.NOT_FOUND_ERROR.status) } - @ExceptionHandler(NoResourceFoundException::class) - fun handleNoResourceFoundException(e: NoResourceFoundException): ResponseEntity> { - return ResponseEntity(ErrorResponse.error(ErrorType.BAD_REQUEST_ERROR), ErrorType.BAD_REQUEST_ERROR.status) - } - @ExceptionHandler(MethodArgumentNotValidException::class) fun handleRequestBodyException(e: MethodArgumentNotValidException): ResponseEntity> { log.error("MethodArgumentNotValidException : {}", e.message, e) From ca603521dd7253184d0c727279f042a3fc0f38ca Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 03:11:57 +0900 Subject: [PATCH 204/223] =?UTF-8?q?rename:=20=EC=9E=98=EB=AA=BB=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=EB=90=9C=20DisplayName=20=EB=B0=8F=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/api/controller/v1/ScheduleControllerTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt index 6d49954..027035f 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/v1/ScheduleControllerTest.kt @@ -12,9 +12,9 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status class ScheduleControllerTest : ControllerTestSupport() { - @DisplayName("식단을 불러온다.") + @DisplayName("학사 일정을 불러온다.") @Test - fun readDiet() { + fun readSchedule() { // given given(scheduleReader.read()).willReturn(listOf()) From 18d20dee4e396268c65590e656a933b5fc86d9ed Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 03:32:41 +0900 Subject: [PATCH 205/223] =?UTF-8?q?test:=20=EA=B5=AC=EB=B2=84=EC=A0=84=20A?= =?UTF-8?q?PI=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/api/OldControllerTestSupport.kt | 47 ++++++ .../controller/old/OldDietControllerTest.kt | 25 +++ .../controller/old/OldNoticeControllerTest.kt | 150 ++++++++++++++++++ .../old/OldScheduleControllerTest.kt | 29 ++++ .../old/OldSubscribeControllerTest.kt | 108 +++++++++++++ 5 files changed, 359 insertions(+) create mode 100644 dmforu-api/src/test/kotlin/com/dmforu/api/OldControllerTestSupport.kt create mode 100644 dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldDietControllerTest.kt create mode 100644 dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldNoticeControllerTest.kt create mode 100644 dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldScheduleControllerTest.kt create mode 100644 dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldSubscribeControllerTest.kt diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/OldControllerTestSupport.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/OldControllerTestSupport.kt new file mode 100644 index 0000000..91e8355 --- /dev/null +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/OldControllerTestSupport.kt @@ -0,0 +1,47 @@ +package com.dmforu.api + +import com.dmforu.api.controller.old.OldDietController +import com.dmforu.api.controller.old.OldNoticeController +import com.dmforu.api.controller.old.OldScheduleController +import com.dmforu.api.controller.old.OldSubscribeController +import com.dmforu.api.controller.v1.DietController +import com.dmforu.api.controller.v1.NoticeController +import com.dmforu.api.controller.v1.ScheduleController +import com.dmforu.api.controller.v1.SubscribeController +import com.dmforu.domain.diet.DietReader +import com.dmforu.domain.notice.NoticeReader +import com.dmforu.domain.schedule.ScheduleReader +import com.dmforu.domain.subscribe.OldSubscribeUpdater +import com.dmforu.domain.subscribe.SubscribeReader +import com.dmforu.domain.subscribe.SubscribeUpdater +import com.dmforu.domain.subscribe.SubscribeWriter +import com.fasterxml.jackson.databind.ObjectMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.test.web.servlet.MockMvc + +@WebMvcTest(controllers = [OldDietController::class, OldNoticeController::class, OldScheduleController::class, OldSubscribeController::class]) +abstract class OldControllerTestSupport { + + @Autowired + protected lateinit var mockMvc: MockMvc + + @Autowired + protected lateinit var objectMapper: ObjectMapper + + @MockBean + protected lateinit var dietReader: DietReader + + @MockBean + protected lateinit var noticeReader: NoticeReader + + @MockBean + protected lateinit var scheduleReader: ScheduleReader + + @MockBean + protected lateinit var subscribeWriter: SubscribeWriter + + @MockBean + protected lateinit var subscribeUpdater: OldSubscribeUpdater +} diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldDietControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldDietControllerTest.kt new file mode 100644 index 0000000..f35a6aa --- /dev/null +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldDietControllerTest.kt @@ -0,0 +1,25 @@ +package com.dmforu.api.controller.old + +import com.dmforu.api.OldControllerTestSupport +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.springframework.http.MediaType.APPLICATION_JSON +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status + +class OldDietControllerTest : OldControllerTestSupport() { + + @DisplayName("식단을 불러온다.") + @Test + fun readDiet() { + mockMvc.perform( + get("/api/v1/dmu/cafeteria") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray) + } + +} \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldNoticeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldNoticeControllerTest.kt new file mode 100644 index 0000000..3261fe7 --- /dev/null +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldNoticeControllerTest.kt @@ -0,0 +1,150 @@ +package com.dmforu.api.controller.old + +import com.dmforu.api.OldControllerTestSupport +import com.dmforu.api.support.error.ErrorCode +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyString +import org.mockito.BDDMockito.given +import org.springframework.http.MediaType.APPLICATION_JSON +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status + +class OldNoticeControllerTest : OldControllerTestSupport() { + + @DisplayName("대학 공지를 불러온다.") + @Test + fun getUniversityNotice() { + // given + given(noticeReader.readUniversityNotice(anyInt(), anyInt())).willReturn(listOf()) + + // when then + mockMvc.perform( + get("/api/v1/dmu/notice/universityNotice") + .param("page", "1") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray) + } + + @DisplayName("학과 공지를 불러온다.") + @Test + fun getDepartmentNotice() { + // given + given(noticeReader.readDepartmentNotice(anyString(), anyInt(), anyInt())).willReturn(listOf()) + + // when then + mockMvc.perform( + get("/api/v1/dmu/departmentNotice/{department}", "컴퓨터소프트웨어공학과") + .param("page", "1") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray) + } + + @DisplayName("학과 공지를 불러올 때, 학과는 필수 값이다.") + @Test + fun getDepartmentNoticeWhenDepartmentIsEmpty() { + mockMvc.perform( + get("/api/v1/dmu/departmentNotice/") + .param("page", "1") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isNotFound) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E404.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 URL로 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").isEmpty) + } + + + @DisplayName("공지를 검색한다.") + @Test + fun getNoticeByKeyword() { + // given + given(noticeReader.searchNotice(anyString(), anyString(), anyInt(), anyInt())).willReturn(listOf()) + + // when then + mockMvc.perform( + get("/api/v1/dmu/notice/{searchWord}", "검색어") + .param("department", "컴퓨터소프트웨어공학과") + .param("page", "1") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray) + } + + @DisplayName("공지를 검색할 때, 학과는 필수 값이다.") + @Test + fun getNoticeByKeywordWhen() { + mockMvc.perform( + get("/api/v1/dmu/notice/{searchWord}", "검색어") + .param("page", "1") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E400.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").isEmpty) + } + + @DisplayName("공지를 검색할 때, 검색어는 필수 값이다. ") + @Test + fun getNoticeByKeywordWhenPathValueIsEmpty() { + mockMvc.perform( + get("/api/v1/dmu/notice/") + .param("department", "컴퓨터소프트웨어공학과") + .param("page", "1") + .param("size", "20") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isNotFound) + .andExpect(jsonPath("$.error.code").value(ErrorCode.E404.name)) + .andExpect(jsonPath("$.error.message").value("잘못된 URL로 요청을 하였습니다.")) + .andExpect(jsonPath("$.error.data").isEmpty) + } + + @DisplayName("공지를 불러올 때, 페이지네이션 값이 빠져있다면 페이지 1, 사이즈 20으로 자동 설정된다.") + @Test + fun getNoticeWithoutPagination() { + // given + given(noticeReader.readUniversityNotice(anyInt(), anyInt())).willReturn(listOf()) + given(noticeReader.readDepartmentNotice(anyString(), anyInt(), anyInt())).willReturn(listOf()) + given(noticeReader.searchNotice(anyString(), anyString(), anyInt(), anyInt())).willReturn(listOf()) + + // when then + mockMvc.perform( + get("/api/v1/dmu/notice/universityNotice") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray) + + mockMvc.perform( + get("/api/v1/dmu/notice/departmentNotice") + .param("department", "컴퓨터소프트웨어공학과") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray) + + mockMvc.perform( + get("/api/v1/dmu/notice/{searchWord}", "검색어") + .param("department", "컴퓨터소프트웨어공학과") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray) + } + +} \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldScheduleControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldScheduleControllerTest.kt new file mode 100644 index 0000000..6f155fe --- /dev/null +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldScheduleControllerTest.kt @@ -0,0 +1,29 @@ +package com.dmforu.api.controller.old + +import com.dmforu.api.OldControllerTestSupport +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.mockito.BDDMockito.given +import org.springframework.http.MediaType.APPLICATION_JSON +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status + +class OldScheduleControllerTest : OldControllerTestSupport() { + + @DisplayName("학사 일정을 불러온다.") + @Test + fun readSchedule() { + // given + given(scheduleReader.read()).willReturn(listOf()) + + // when // then + mockMvc.perform( + get("/api/v1/dmu/schedule") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray) + } +} \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldSubscribeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldSubscribeControllerTest.kt new file mode 100644 index 0000000..d70f634 --- /dev/null +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldSubscribeControllerTest.kt @@ -0,0 +1,108 @@ +package com.dmforu.api.controller.old + +import com.dmforu.api.OldControllerTestSupport +import com.dmforu.api.controller.old.request.OldDepartmentRequest +import com.dmforu.api.controller.old.request.OldKeywordsSubscribeRequest +import com.dmforu.api.controller.old.request.OldRegisterSubscribeRequest +import com.dmforu.api.controller.old.request.OldTokenRequest +import com.dmforu.api.controller.v1.request.RegisterSubscribeRequest +import org.junit.jupiter.api.Test + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.springframework.http.MediaType.APPLICATION_JSON +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status + +class OldSubscribeControllerTest : OldControllerTestSupport() { + + @DisplayName("구독을 생성한다.") + @Test + fun tokenSubscribe() { + // given + val request = OldRegisterSubscribeRequest( + token = "0001", + department = "컴퓨터소프트웨어공학과", + topic = listOf("학사") + ) + + // when // then + mockMvc.perform( + post("/token/v1/dmu/initToken") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk) + } + + @DisplayName("학과를 업데이트하며, 학과 구독 상태를 구독으로 변경한다.") + @Test + fun departmentSubscribe() { + // given + val request = OldDepartmentRequest( + token = "0001", + department = "컴퓨터소프트웨어공학과", + ) + + // when // then + mockMvc.perform( + post("/department/v1/dmu/updateDepartment") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk) + } + + @DisplayName("학과 구독 상태를 취소로 변경한다.") + @Test + fun departmentUnsubscribe() { + // given + val request = OldTokenRequest( + token = "0001" + ) + + // when // then + mockMvc.perform( + post("/department/v1/dmu/deleteDepartment") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk) + } + + @DisplayName("키워드를 업데이트하며, 키워드 구독 상태를 구독으로 변경한다.") + @Test + fun keywordsSubscribe() { + // given + val request = OldKeywordsSubscribeRequest( + token = "0001", + topics = listOf("학사") + ) + + // when // then + mockMvc.perform( + post("/token/v1/dmu/updateTopic") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk) + } + + @DisplayName("키워드 구독 상태를 취소로 변경한다.") + @Test + fun keywordsUnsubscribe() { + // given + val request = OldTokenRequest( + token = "0001" + ) + + // when // then + mockMvc.perform( + post("/token/v1/dmu/deleteTopic") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk) + } +} \ No newline at end of file From 5e6e16a28e172c93b82ac1ea173186379419fc45 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 16:01:50 +0900 Subject: [PATCH 206/223] =?UTF-8?q?rename:=20=EC=9E=98=EB=AA=BB=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=EB=90=9C=20DisplayName=20=EB=B0=8F=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/crawling/parser/DepartmentNoticeParserTest.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParserTest.kt b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParserTest.kt index b326796..1e7edd5 100644 --- a/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParserTest.kt +++ b/dmforu-crawling/src/test/kotlin/com/dmforu/crawling/parser/DepartmentNoticeParserTest.kt @@ -25,7 +25,7 @@ class DepartmentNoticeParserTest { @InjectMocks private lateinit var parser: DepartmentNoticeParser - @DisplayName("") + @DisplayName("학과 공지사항 목록을 파싱할 수 있다.") @Test fun parse() { // given @@ -77,6 +77,7 @@ class DepartmentNoticeParserTest { } + @DisplayName("학과 공지사항 목록을 파싱할 때, 공지사항 주소가 잘못되어 있는 경우 예외를 발생시킨다.") @Test fun parseWhenUrlInvalid() { // given From 40e3a5bb348889144dda3db1e086291a389df9ac Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 16:02:23 +0900 Subject: [PATCH 207/223] =?UTF-8?q?test:=20mysql=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=ED=99=98=EA=B2=BD=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dmforu/storage/db/mysql/MysqlIntegrationTest.kt | 11 +++++++++++ .../db/mysql/notice/NoticeEntityRepositoryTest.kt | 7 +++---- .../db/mysql/notice/NoticeJpaRepositoryTest.kt | 12 ++++++++---- .../mysql/subscribe/SubscribeEntityRepositoryTest.kt | 6 ++---- .../db/mysql/subscribe/SubscribeJpaRepositoryTest.kt | 11 ++++++++--- 5 files changed, 32 insertions(+), 15 deletions(-) create mode 100644 dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/MysqlIntegrationTest.kt diff --git a/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/MysqlIntegrationTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/MysqlIntegrationTest.kt new file mode 100644 index 0000000..041ebce --- /dev/null +++ b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/MysqlIntegrationTest.kt @@ -0,0 +1,11 @@ +package com.dmforu.storage.db.mysql + +import com.dmforu.storage.db.mysql.config.MysqlJpaConfig +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.context.annotation.Import +import org.springframework.test.context.ActiveProfiles + +@ActiveProfiles("test") +@SpringBootTest(classes = [MysqlApplicationTest::class]) +@Import(MysqlJpaConfig::class) +abstract class MysqlIntegrationTest {} \ No newline at end of file diff --git a/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt index 8001994..f79dd95 100644 --- a/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt +++ b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeEntityRepositoryTest.kt @@ -2,6 +2,7 @@ package com.dmforu.storage.db.mysql.notice import com.dmforu.domain.notice.Notice import com.dmforu.storage.db.mysql.MysqlApplicationTest +import com.dmforu.storage.db.mysql.MysqlIntegrationTest import com.dmforu.storage.db.mysql.config.MysqlJpaConfig import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.tuple @@ -14,10 +15,8 @@ import org.springframework.context.annotation.Import import org.springframework.test.context.ActiveProfiles import java.time.LocalDate -@ActiveProfiles("test") -@SpringBootTest(classes = [MysqlApplicationTest::class]) -@Import(MysqlJpaConfig::class) -class NoticeEntityRepositoryTest { + +class NoticeEntityRepositoryTest : MysqlIntegrationTest() { @Autowired private lateinit var noticeRepository: NoticeJpaRepository diff --git a/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt index 2f2e4c5..dc37ccd 100644 --- a/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt +++ b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/notice/NoticeJpaRepositoryTest.kt @@ -1,9 +1,11 @@ package com.dmforu.storage.db.mysql.notice import com.dmforu.domain.notice.Notice +import com.dmforu.storage.db.mysql.MysqlIntegrationTest import com.dmforu.storage.db.mysql.config.MysqlJpaConfig import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.tuple +import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -14,10 +16,12 @@ import org.springframework.data.domain.Sort import org.springframework.test.context.ActiveProfiles import java.time.LocalDate -@ActiveProfiles("test") -@DataJpaTest -@Import(MysqlJpaConfig::class) -class NoticeJpaRepositoryTest { +class NoticeJpaRepositoryTest : MysqlIntegrationTest() { + + @AfterEach + fun tearDown() { + noticeRepository.deleteAllInBatch() + } @Autowired private lateinit var noticeRepository: NoticeJpaRepository diff --git a/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt index 6c05a9a..8ac418a 100644 --- a/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt +++ b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeEntityRepositoryTest.kt @@ -3,6 +3,7 @@ package com.dmforu.storage.db.mysql.subscribe import com.dmforu.domain.subscribe.Subscribe import com.dmforu.storage.db.mysql.config.MysqlJpaConfig import com.dmforu.storage.db.mysql.MysqlApplicationTest +import com.dmforu.storage.db.mysql.MysqlIntegrationTest import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.tuple import org.junit.jupiter.api.AfterEach @@ -13,10 +14,7 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.context.annotation.Import import org.springframework.test.context.ActiveProfiles -@ActiveProfiles("test") -@SpringBootTest(classes = [MysqlApplicationTest::class]) -@Import(MysqlJpaConfig::class) -class SubscribeEntityRepositoryTest { +class SubscribeEntityRepositoryTest : MysqlIntegrationTest(){ @Autowired private lateinit var subscribeRepository: SubscribeJpaRepository diff --git a/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt index 1da9b9f..ded7f60 100644 --- a/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt +++ b/dmforu-infrastructure/storage/mysql/src/test/kotlin/com/dmforu/storage/db/mysql/subscribe/SubscribeJpaRepositoryTest.kt @@ -1,19 +1,24 @@ package com.dmforu.storage.db.mysql.subscribe import com.dmforu.domain.subscribe.Subscribe +import com.dmforu.storage.db.mysql.MysqlIntegrationTest import com.dmforu.storage.db.mysql.config.MysqlJpaConfig import com.dmforu.storage.db.mysql.subscribe.SubscribeEntity import com.dmforu.storage.db.mysql.subscribe.SubscribeJpaRepository import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest import org.springframework.context.annotation.Import -@DataJpaTest -@Import(MysqlJpaConfig::class) -class SubscribeJpaRepositoryTest { +class SubscribeJpaRepositoryTest : MysqlIntegrationTest() { + + @AfterEach + fun tearDown() { + subscribeRepository.deleteAllInBatch() + } @Autowired private lateinit var subscribeRepository: SubscribeJpaRepository From 8b2e606f98039cbb9002ec4a3df0ef50cc4f8391 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 16:02:52 +0900 Subject: [PATCH 208/223] =?UTF-8?q?test:=20mock=20=EC=88=98=EB=8F=99=20?= =?UTF-8?q?=EC=A3=BC=EC=9E=85=EC=97=90=EC=84=9C=20=EC=95=A0=EB=84=88?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dmforu/fcm/FirebaseMessageSenderTest.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dmforu-infrastructure/fcm/src/test/kotlin/com/dmforu/fcm/FirebaseMessageSenderTest.kt b/dmforu-infrastructure/fcm/src/test/kotlin/com/dmforu/fcm/FirebaseMessageSenderTest.kt index 1754866..5d095a6 100644 --- a/dmforu-infrastructure/fcm/src/test/kotlin/com/dmforu/fcm/FirebaseMessageSenderTest.kt +++ b/dmforu-infrastructure/fcm/src/test/kotlin/com/dmforu/fcm/FirebaseMessageSenderTest.kt @@ -7,25 +7,26 @@ import com.google.firebase.messaging.MulticastMessage import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.Mockito.verify +import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any import org.mockito.kotlin.given import java.time.LocalDate +@ExtendWith(MockitoExtension::class) class FirebaseMessageSenderTest { + @Mock private lateinit var firebaseMessaging: FirebaseMessaging + @InjectMocks private lateinit var messageSender: FirebaseMessageSender - @BeforeEach - fun setUp() { - firebaseMessaging = mock() - messageSender = FirebaseMessageSender(firebaseMessaging) - } - @DisplayName("공지를 푸시 알림으로 전송한다.") @Test fun sendNoticeMessage() { From a9a899f3ea6b2dc2cf92527c5caf07e09707d613 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 16:10:32 +0900 Subject: [PATCH 209/223] =?UTF-8?q?test:=20api=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=ED=99=98=EA=B2=BD=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/old/OldSubscribeController.kt | 10 ++-- .../com/dmforu/api/ControllerTestSupport.kt | 14 +++++- .../dmforu/api/OldControllerTestSupport.kt | 47 ------------------- .../controller/old/OldDietControllerTest.kt | 4 +- .../controller/old/OldNoticeControllerTest.kt | 4 +- .../old/OldScheduleControllerTest.kt | 4 +- .../old/OldSubscribeControllerTest.kt | 6 +-- 7 files changed, 26 insertions(+), 63 deletions(-) delete mode 100644 dmforu-api/src/test/kotlin/com/dmforu/api/OldControllerTestSupport.kt diff --git a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldSubscribeController.kt b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldSubscribeController.kt index c919818..4576ae1 100644 --- a/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldSubscribeController.kt +++ b/dmforu-api/src/main/kotlin/com/dmforu/api/controller/old/OldSubscribeController.kt @@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.RestController @RestController class OldSubscribeController( private val subscribeWriter: SubscribeWriter, - private val subscribeUpdater: OldSubscribeUpdater, + private val oldSubscribeUpdater: OldSubscribeUpdater, ) { @Operation(summary = "[구버전] 최초 Token 등록 API", description = "애플리케이션 최초 실행시 Token과 학과, 키워드를 등록한다.") @PostMapping("/token/v1/dmu/initToken") @@ -29,28 +29,28 @@ class OldSubscribeController( @Operation(summary = "[구버전] 학사 알림 구독", description = "학사 알림을 받도록 설정한다.") @PostMapping("/department/v1/dmu/updateDepartment") fun oldDepartmentSubscribe(@RequestBody departmentRequest: OldDepartmentRequest): ResponseEntity { - subscribeUpdater.subscribeDepartment(token = departmentRequest.token, department = departmentRequest.department) + oldSubscribeUpdater.subscribeDepartment(token = departmentRequest.token, department = departmentRequest.department) return ResponseEntity.ok().build() } @Operation(summary = "[구버전] 학사 알림 구독해제", description = "학사 알림을 받지 않도록 설정한다.") @PostMapping("/department/v1/dmu/deleteDepartment") fun oldDepartmentUnsubscribe(@RequestBody tokenRequest: OldTokenRequest): ResponseEntity { - subscribeUpdater.unsubscribeDepartment(token = tokenRequest.token) + oldSubscribeUpdater.unsubscribeDepartment(token = tokenRequest.token) return ResponseEntity.ok().build() } @Operation(summary = "[구버전] 키워드 알림 구독", description = "키워드 알림을 받도록 설정한다.") @PostMapping("/token/v1/dmu/updateTopic") fun oldKeywordsSubscribe(@RequestBody keywordsRequest: OldKeywordsSubscribeRequest): ResponseEntity { - subscribeUpdater.subscribeKeywords(token = keywordsRequest.token, keywords = keywordsRequest.topics) + oldSubscribeUpdater.subscribeKeywords(token = keywordsRequest.token, keywords = keywordsRequest.topics) return ResponseEntity.ok().build() } @Operation(summary = "[구버전] 키워드 알림 구독해제", description = "키워드 알림을 받지 않도록 설정한다.") @PostMapping("/token/v1/dmu/deleteTopic") fun oldKeywordsUnsubscribe(@RequestBody tokenRequest: OldTokenRequest): ResponseEntity { - subscribeUpdater.unsubscribeKeywords(token = tokenRequest.token) + oldSubscribeUpdater.unsubscribeKeywords(token = tokenRequest.token) return ResponseEntity.ok().build() } } \ No newline at end of file diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/ControllerTestSupport.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/ControllerTestSupport.kt index f774bcf..4f578c5 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/ControllerTestSupport.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/ControllerTestSupport.kt @@ -1,5 +1,9 @@ package com.dmforu.api +import com.dmforu.api.controller.old.OldDietController +import com.dmforu.api.controller.old.OldNoticeController +import com.dmforu.api.controller.old.OldScheduleController +import com.dmforu.api.controller.old.OldSubscribeController import com.dmforu.api.controller.v1.DietController import com.dmforu.api.controller.v1.NoticeController import com.dmforu.api.controller.v1.ScheduleController @@ -7,6 +11,7 @@ import com.dmforu.api.controller.v1.SubscribeController import com.dmforu.domain.diet.DietReader import com.dmforu.domain.notice.NoticeReader import com.dmforu.domain.schedule.ScheduleReader +import com.dmforu.domain.subscribe.OldSubscribeUpdater import com.dmforu.domain.subscribe.SubscribeUpdater import com.dmforu.domain.subscribe.SubscribeWriter import com.fasterxml.jackson.databind.ObjectMapper @@ -15,7 +20,12 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.test.web.servlet.MockMvc -@WebMvcTest(controllers = [DietController::class, NoticeController::class, ScheduleController::class, SubscribeController::class]) +@WebMvcTest( + controllers = [ + DietController::class, NoticeController::class, ScheduleController::class, SubscribeController::class, + OldDietController::class, OldNoticeController::class, OldScheduleController::class, OldSubscribeController::class + ] +) abstract class ControllerTestSupport { @Autowired @@ -39,6 +49,8 @@ abstract class ControllerTestSupport { @MockBean protected lateinit var subscribeWriter: SubscribeWriter + @MockBean + protected lateinit var oldSubscribeUpdater: OldSubscribeUpdater } diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/OldControllerTestSupport.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/OldControllerTestSupport.kt deleted file mode 100644 index 91e8355..0000000 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/OldControllerTestSupport.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.dmforu.api - -import com.dmforu.api.controller.old.OldDietController -import com.dmforu.api.controller.old.OldNoticeController -import com.dmforu.api.controller.old.OldScheduleController -import com.dmforu.api.controller.old.OldSubscribeController -import com.dmforu.api.controller.v1.DietController -import com.dmforu.api.controller.v1.NoticeController -import com.dmforu.api.controller.v1.ScheduleController -import com.dmforu.api.controller.v1.SubscribeController -import com.dmforu.domain.diet.DietReader -import com.dmforu.domain.notice.NoticeReader -import com.dmforu.domain.schedule.ScheduleReader -import com.dmforu.domain.subscribe.OldSubscribeUpdater -import com.dmforu.domain.subscribe.SubscribeReader -import com.dmforu.domain.subscribe.SubscribeUpdater -import com.dmforu.domain.subscribe.SubscribeWriter -import com.fasterxml.jackson.databind.ObjectMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest -import org.springframework.boot.test.mock.mockito.MockBean -import org.springframework.test.web.servlet.MockMvc - -@WebMvcTest(controllers = [OldDietController::class, OldNoticeController::class, OldScheduleController::class, OldSubscribeController::class]) -abstract class OldControllerTestSupport { - - @Autowired - protected lateinit var mockMvc: MockMvc - - @Autowired - protected lateinit var objectMapper: ObjectMapper - - @MockBean - protected lateinit var dietReader: DietReader - - @MockBean - protected lateinit var noticeReader: NoticeReader - - @MockBean - protected lateinit var scheduleReader: ScheduleReader - - @MockBean - protected lateinit var subscribeWriter: SubscribeWriter - - @MockBean - protected lateinit var subscribeUpdater: OldSubscribeUpdater -} diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldDietControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldDietControllerTest.kt index f35a6aa..465bd4e 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldDietControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldDietControllerTest.kt @@ -1,6 +1,6 @@ package com.dmforu.api.controller.old -import com.dmforu.api.OldControllerTestSupport +import com.dmforu.api.ControllerTestSupport import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test @@ -9,7 +9,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -class OldDietControllerTest : OldControllerTestSupport() { +class OldDietControllerTest : ControllerTestSupport() { @DisplayName("식단을 불러온다.") @Test diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldNoticeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldNoticeControllerTest.kt index 3261fe7..90b0777 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldNoticeControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldNoticeControllerTest.kt @@ -1,6 +1,6 @@ package com.dmforu.api.controller.old -import com.dmforu.api.OldControllerTestSupport +import com.dmforu.api.ControllerTestSupport import com.dmforu.api.support.error.ErrorCode import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName @@ -13,7 +13,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -class OldNoticeControllerTest : OldControllerTestSupport() { +class OldNoticeControllerTest : ControllerTestSupport() { @DisplayName("대학 공지를 불러온다.") @Test diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldScheduleControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldScheduleControllerTest.kt index 6f155fe..4456435 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldScheduleControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldScheduleControllerTest.kt @@ -1,6 +1,6 @@ package com.dmforu.api.controller.old -import com.dmforu.api.OldControllerTestSupport +import com.dmforu.api.ControllerTestSupport import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test @@ -10,7 +10,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -class OldScheduleControllerTest : OldControllerTestSupport() { +class OldScheduleControllerTest : ControllerTestSupport() { @DisplayName("학사 일정을 불러온다.") @Test diff --git a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldSubscribeControllerTest.kt b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldSubscribeControllerTest.kt index d70f634..e9dfa6a 100644 --- a/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldSubscribeControllerTest.kt +++ b/dmforu-api/src/test/kotlin/com/dmforu/api/controller/old/OldSubscribeControllerTest.kt @@ -1,21 +1,19 @@ package com.dmforu.api.controller.old -import com.dmforu.api.OldControllerTestSupport +import com.dmforu.api.ControllerTestSupport import com.dmforu.api.controller.old.request.OldDepartmentRequest import com.dmforu.api.controller.old.request.OldKeywordsSubscribeRequest import com.dmforu.api.controller.old.request.OldRegisterSubscribeRequest import com.dmforu.api.controller.old.request.OldTokenRequest -import com.dmforu.api.controller.v1.request.RegisterSubscribeRequest import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.springframework.http.MediaType.APPLICATION_JSON import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -class OldSubscribeControllerTest : OldControllerTestSupport() { +class OldSubscribeControllerTest : ControllerTestSupport() { @DisplayName("구독을 생성한다.") @Test From 6fd16ce4cb21704209904a4abfbdf0ab6e395bca Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 21:53:33 +0900 Subject: [PATCH 210/223] =?UTF-8?q?rename:=20nohup=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nohup.out | 154 ------------------------------------------------------ 1 file changed, 154 deletions(-) delete mode 100644 nohup.out diff --git a/nohup.out b/nohup.out deleted file mode 100644 index 3e65188..0000000 --- a/nohup.out +++ /dev/null @@ -1,154 +0,0 @@ - - . ____ _ __ _ _ - /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ -( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ - \\/ ___)| |_)| | | | | || (_| | ) ) ) ) - ' |____| .__|_| |_|_| |_\__, | / / / / - =========|_|==============|___/=/_/_/_/ - - :: Spring Boot :: (v3.3.4) - -2024-11-04T03:32:24.334+09:00 INFO 57048 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : Starting AdminApplicationKt v1.2.0 using Java 17.0.11 with PID 57048 (/Users/weeds2577/DMU-BackEnd/dmforu-admin/build/libs/dmforu-admin-1.2.0.jar started by weeds2577 in /Users/weeds2577/DMU-BackEnd) -2024-11-04T03:32:24.336+09:00 INFO 57048 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : The following 1 profile is active: "local" -2024-11-04T03:32:24.730+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode -2024-11-04T03:32:24.730+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data MongoDB repositories in DEFAULT mode. -2024-11-04T03:32:24.753+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 20 ms. Found 2 MongoDB repository interfaces. -2024-11-04T03:32:24.757+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode -2024-11-04T03:32:24.757+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. -2024-11-04T03:32:24.766+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 6 ms. Found 2 JPA repository interfaces. -2024-11-04T03:32:25.259+09:00 INFO 57048 --- [dmforu-admin] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) -2024-11-04T03:32:25.269+09:00 INFO 57048 --- [dmforu-admin] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] -2024-11-04T03:32:25.269+09:00 INFO 57048 --- [dmforu-admin] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.30] -2024-11-04T03:32:25.301+09:00 INFO 57048 --- [dmforu-admin] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext -2024-11-04T03:32:25.302+09:00 INFO 57048 --- [dmforu-admin] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 933 ms -2024-11-04T03:32:25.403+09:00 INFO 57048 --- [dmforu-admin] [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] -2024-11-04T03:32:25.449+09:00 INFO 57048 --- [dmforu-admin] [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.5.3.Final -2024-11-04T03:32:25.483+09:00 INFO 57048 --- [dmforu-admin] [ main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled -2024-11-04T03:32:25.720+09:00 INFO 57048 --- [dmforu-admin] [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer -2024-11-04T03:32:25.767+09:00 INFO 57048 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... -2024-11-04T03:32:26.018+09:00 INFO 57048 --- [dmforu-admin] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@510e4d79 -2024-11-04T03:32:26.019+09:00 INFO 57048 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. -2024-11-04T03:32:26.065+09:00 WARN 57048 --- [dmforu-admin] [ main] org.hibernate.orm.deprecation : HHH90000025: MySQLDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default) -2024-11-04T03:32:26.732+09:00 INFO 57048 --- [dmforu-admin] [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) -2024-11-04T03:32:26.734+09:00 INFO 57048 --- [dmforu-admin] [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' -2024-11-04T03:32:27.013+09:00 INFO 57048 --- [dmforu-admin] [ main] o.s.d.j.r.query.QueryEnhancerFactory : Hibernate is in classpath; If applicable, HQL parser will be used. -2024-11-04T03:32:27.418+09:00 INFO 57048 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-02.qlvx9.mongodb.net:27017 to client view of cluster -2024-11-04T03:32:27.436+09:00 INFO 57048 --- [dmforu-admin] [ main] org.mongodb.driver.client : MongoClient with metadata {"application": {"name": "dmforu-test"}, "driver": {"name": "mongo-java-driver|sync", "version": "5.0.1"}, "os": {"type": "Darwin", "name": "Mac OS X", "architecture": "aarch64", "version": "14.2.1"}, "platform": "Java/Oracle Corporation/17.0.11+7-LTS-207"} created with settings MongoClientSettings{readPreference=primary, writeConcern=WriteConcern{w=majority, wTimeout=null ms, journal=null}, retryWrites=true, retryReads=true, readConcern=ReadConcern{level=null}, credential=MongoCredential{mechanism=null, userName='weeds2577', source='admin', password=, mechanismProperties=}, transportSettings=null, commandListeners=[], codecRegistry=ProvidersCodecRegistry{codecProviders=[ProvidersCodecRegistry{codecProviders=[ValueCodecProvider{}, BsonValueCodecProvider{}, DBRefCodecProvider{}, DBObjectCodecProvider{}, DocumentCodecProvider{}, CollectionCodecProvider{}, IterableCodecProvider{}, MapCodecProvider{}, GeoJsonCodecProvider{}, GridFSFileCodecProvider{}, Jsr310CodecProvider{}, JsonObjectCodecProvider{}, BsonCodecProvider{}, EnumCodecProvider{}, com.mongodb.client.model.mql.ExpressionCodecProvider@508863eb, com.mongodb.Jep395RecordCodecProvider@7d8802cf, com.mongodb.KotlinCodecProvider@2f7af3d0]}, ProvidersCodecRegistry{codecProviders=[org.bson.codecs.pojo.PojoCodecProvider@494775f1]}]}, loggerSettings=LoggerSettings{maxDocumentLength=1000}, clusterSettings={hosts=[127.0.0.1:27017], srvHost=dmforu-test.qlvx9.mongodb.net, srvServiceName=mongodb, mode=MULTIPLE, requiredClusterType=REPLICA_SET, requiredReplicaSetName='atlas-m6kxjp-shard-0', serverSelector='null', clusterListeners='[]', serverSelectionTimeout='30000 ms', localThreshold='15 ms'}, socketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=0, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, heartbeatSocketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=10000, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, connectionPoolSettings=ConnectionPoolSettings{maxSize=100, minSize=0, maxWaitTimeMS=120000, maxConnectionLifeTimeMS=0, maxConnectionIdleTimeMS=0, maintenanceInitialDelayMS=0, maintenanceFrequencyMS=60000, connectionPoolListeners=[], maxConnecting=2}, serverSettings=ServerSettings{heartbeatFrequencyMS=10000, minHeartbeatFrequencyMS=500, serverListeners='[]', serverMonitorListeners='[]'}, sslSettings=SslSettings{enabled=true, invalidHostNameAllowed=false, context=null}, applicationName='dmforu-test', compressorList=[], uuidRepresentation=UNSPECIFIED, serverApi=null, autoEncryptionSettings=null, dnsClient=null, inetAddressResolver=null, contextProvider=null} -2024-11-04T03:32:27.461+09:00 INFO 57048 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-00.qlvx9.mongodb.net:27017 to client view of cluster -2024-11-04T03:32:27.463+09:00 INFO 57048 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-01.qlvx9.mongodb.net:27017 to client view of cluster -2024-11-04T03:32:27.708+09:00 WARN 57048 --- [dmforu-admin] [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning -2024-11-04T03:32:27.863+09:00 INFO 57048 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=248497500, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az2'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=9, topologyVersion=TopologyVersion{processId=67220b6eb3ac540c1b3d2884, counter=3}, lastWriteDate=Mon Nov 04 03:32:27 KST 2024, lastUpdateTimeNanos=880874715381000} -2024-11-04T03:32:27.863+09:00 INFO 57048 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-00.qlvx9.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=248497333, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-00.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az1'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=9, topologyVersion=TopologyVersion{processId=67220a16b5fcab00b1d9f81a, counter=4}, lastWriteDate=Mon Nov 04 03:32:27 KST 2024, lastUpdateTimeNanos=880874715381000} -2024-11-04T03:32:27.863+09:00 INFO 57048 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=247061792, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az3'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=7fffffff00000000000000aa, setVersion=9, topologyVersion=TopologyVersion{processId=67220879494685dc7d977f3a, counter=6}, lastWriteDate=Mon Nov 04 03:32:27 KST 2024, lastUpdateTimeNanos=880874715381000} -2024-11-04T03:32:27.867+09:00 INFO 57048 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Discovered replica set primary dmforu-test-shard-00-01.qlvx9.mongodb.net:27017 with max election id 7fffffff00000000000000aa and max set version 9 -2024-11-04T03:32:27.936+09:00 WARN 57048 --- [dmforu-admin] [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'webServerStartStop' -2024-11-04T03:32:27.965+09:00 INFO 57048 --- [dmforu-admin] [ main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' -2024-11-04T03:32:27.966+09:00 INFO 57048 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... -2024-11-04T03:32:27.969+09:00 INFO 57048 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. -2024-11-04T03:32:27.982+09:00 INFO 57048 --- [dmforu-admin] [ main] .s.b.a.l.ConditionEvaluationReportLogger : - -Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. -2024-11-04T03:32:27.992+09:00 ERROR 57048 --- [dmforu-admin] [ main] o.s.b.d.LoggingFailureAnalysisReporter : - -*************************** -APPLICATION FAILED TO START -*************************** - -Description: - -Web server failed to start. Port 8080 was already in use. - -Action: - -Identify and stop the process that's listening on port 8080 or configure this application to listen on another port. - - - . ____ _ __ _ _ - /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ -( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ - \\/ ___)| |_)| | | | | || (_| | ) ) ) ) - ' |____| .__|_| |_|_| |_\__, | / / / / - =========|_|==============|___/=/_/_/_/ - - :: Spring Boot :: (v3.3.4) - -2024-11-04T03:33:20.395+09:00 INFO 57287 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : Starting AdminApplicationKt v1.2.0 using Java 17.0.11 with PID 57287 (/Users/weeds2577/DMU-BackEnd/dmforu-admin/build/libs/dmforu-admin-1.2.0.jar started by weeds2577 in /Users/weeds2577/DMU-BackEnd) -2024-11-04T03:33:20.398+09:00 INFO 57287 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : The following 1 profile is active: "local" -2024-11-04T03:33:20.780+09:00 INFO 57287 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode -2024-11-04T03:33:20.780+09:00 INFO 57287 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data MongoDB repositories in DEFAULT mode. -2024-11-04T03:33:20.805+09:00 INFO 57287 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 22 ms. Found 2 MongoDB repository interfaces. -2024-11-04T03:33:20.809+09:00 INFO 57287 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode -2024-11-04T03:33:20.809+09:00 INFO 57287 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. -2024-11-04T03:33:20.817+09:00 INFO 57287 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 7 ms. Found 2 JPA repository interfaces. -2024-11-04T03:33:21.320+09:00 INFO 57287 --- [dmforu-admin] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) -2024-11-04T03:33:21.331+09:00 INFO 57287 --- [dmforu-admin] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] -2024-11-04T03:33:21.331+09:00 INFO 57287 --- [dmforu-admin] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.30] -2024-11-04T03:33:21.362+09:00 INFO 57287 --- [dmforu-admin] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext -2024-11-04T03:33:21.362+09:00 INFO 57287 --- [dmforu-admin] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 931 ms -2024-11-04T03:33:21.472+09:00 INFO 57287 --- [dmforu-admin] [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] -2024-11-04T03:33:21.519+09:00 INFO 57287 --- [dmforu-admin] [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.5.3.Final -2024-11-04T03:33:21.550+09:00 INFO 57287 --- [dmforu-admin] [ main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled -2024-11-04T03:33:21.790+09:00 INFO 57287 --- [dmforu-admin] [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer -2024-11-04T03:33:21.812+09:00 INFO 57287 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... -2024-11-04T03:33:21.992+09:00 INFO 57287 --- [dmforu-admin] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@1a819901 -2024-11-04T03:33:21.992+09:00 INFO 57287 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. -2024-11-04T03:33:22.026+09:00 WARN 57287 --- [dmforu-admin] [ main] org.hibernate.orm.deprecation : HHH90000025: MySQLDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default) -2024-11-04T03:33:22.644+09:00 INFO 57287 --- [dmforu-admin] [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) -2024-11-04T03:33:22.646+09:00 INFO 57287 --- [dmforu-admin] [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' -2024-11-04T03:33:22.889+09:00 INFO 57287 --- [dmforu-admin] [ main] o.s.d.j.r.query.QueryEnhancerFactory : Hibernate is in classpath; If applicable, HQL parser will be used. -2024-11-04T03:33:23.347+09:00 INFO 57287 --- [dmforu-admin] [ main] org.mongodb.driver.client : MongoClient with metadata {"application": {"name": "dmforu-test"}, "driver": {"name": "mongo-java-driver|sync", "version": "5.0.1"}, "os": {"type": "Darwin", "name": "Mac OS X", "architecture": "aarch64", "version": "14.2.1"}, "platform": "Java/Oracle Corporation/17.0.11+7-LTS-207"} created with settings MongoClientSettings{readPreference=primary, writeConcern=WriteConcern{w=majority, wTimeout=null ms, journal=null}, retryWrites=true, retryReads=true, readConcern=ReadConcern{level=null}, credential=MongoCredential{mechanism=null, userName='weeds2577', source='admin', password=, mechanismProperties=}, transportSettings=null, commandListeners=[], codecRegistry=ProvidersCodecRegistry{codecProviders=[ProvidersCodecRegistry{codecProviders=[ValueCodecProvider{}, BsonValueCodecProvider{}, DBRefCodecProvider{}, DBObjectCodecProvider{}, DocumentCodecProvider{}, CollectionCodecProvider{}, IterableCodecProvider{}, MapCodecProvider{}, GeoJsonCodecProvider{}, GridFSFileCodecProvider{}, Jsr310CodecProvider{}, JsonObjectCodecProvider{}, BsonCodecProvider{}, EnumCodecProvider{}, com.mongodb.client.model.mql.ExpressionCodecProvider@1ffcb4bb, com.mongodb.Jep395RecordCodecProvider@6d66a248, com.mongodb.KotlinCodecProvider@29617475]}, ProvidersCodecRegistry{codecProviders=[org.bson.codecs.pojo.PojoCodecProvider@4f9871a2]}]}, loggerSettings=LoggerSettings{maxDocumentLength=1000}, clusterSettings={hosts=[127.0.0.1:27017], srvHost=dmforu-test.qlvx9.mongodb.net, srvServiceName=mongodb, mode=MULTIPLE, requiredClusterType=REPLICA_SET, requiredReplicaSetName='atlas-m6kxjp-shard-0', serverSelector='null', clusterListeners='[]', serverSelectionTimeout='30000 ms', localThreshold='15 ms'}, socketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=0, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, heartbeatSocketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=10000, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, connectionPoolSettings=ConnectionPoolSettings{maxSize=100, minSize=0, maxWaitTimeMS=120000, maxConnectionLifeTimeMS=0, maxConnectionIdleTimeMS=0, maintenanceInitialDelayMS=0, maintenanceFrequencyMS=60000, connectionPoolListeners=[], maxConnecting=2}, serverSettings=ServerSettings{heartbeatFrequencyMS=10000, minHeartbeatFrequencyMS=500, serverListeners='[]', serverMonitorListeners='[]'}, sslSettings=SslSettings{enabled=true, invalidHostNameAllowed=false, context=null}, applicationName='dmforu-test', compressorList=[], uuidRepresentation=UNSPECIFIED, serverApi=null, autoEncryptionSettings=null, dnsClient=null, inetAddressResolver=null, contextProvider=null} -2024-11-04T03:33:23.418+09:00 INFO 57287 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-02.qlvx9.mongodb.net:27017 to client view of cluster -2024-11-04T03:33:23.438+09:00 INFO 57287 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-00.qlvx9.mongodb.net:27017 to client view of cluster -2024-11-04T03:33:23.440+09:00 INFO 57287 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-01.qlvx9.mongodb.net:27017 to client view of cluster -2024-11-04T03:33:23.612+09:00 WARN 57287 --- [dmforu-admin] [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning -2024-11-04T03:33:23.639+09:00 INFO 57287 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-00.qlvx9.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=126787167, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-00.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az1'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=9, topologyVersion=TopologyVersion{processId=67220a16b5fcab00b1d9f81a, counter=4}, lastWriteDate=Mon Nov 04 03:33:23 KST 2024, lastUpdateTimeNanos=880930494020875} -2024-11-04T03:33:23.639+09:00 INFO 57287 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=126732208, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az3'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=7fffffff00000000000000aa, setVersion=9, topologyVersion=TopologyVersion{processId=67220879494685dc7d977f3a, counter=6}, lastWriteDate=Mon Nov 04 03:33:23 KST 2024, lastUpdateTimeNanos=880930494028541} -2024-11-04T03:33:23.639+09:00 INFO 57287 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=126829083, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az2'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=9, topologyVersion=TopologyVersion{processId=67220b6eb3ac540c1b3d2884, counter=3}, lastWriteDate=Mon Nov 04 03:33:23 KST 2024, lastUpdateTimeNanos=880930494054750} -2024-11-04T03:33:23.642+09:00 INFO 57287 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Discovered replica set primary dmforu-test-shard-00-01.qlvx9.mongodb.net:27017 with max election id 7fffffff00000000000000aa and max set version 9 -2024-11-04T03:33:23.842+09:00 INFO 57287 --- [dmforu-admin] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' -2024-11-04T03:33:23.853+09:00 INFO 57287 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : Started AdminApplicationKt in 3.737 seconds (process running for 4.033) - - . ____ _ __ _ _ - /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ -( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ - \\/ ___)| |_)| | | | | || (_| | ) ) ) ) - ' |____| .__|_| |_|_| |_\__, | / / / / - =========|_|==============|___/=/_/_/_/ - - :: Spring Boot :: (v3.3.4) - -2024-11-04T03:42:00.711+09:00 INFO 57805 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : Starting AdminApplicationKt v1.2.0 using Java 17.0.11 with PID 57805 (/Users/weeds2577/DMU-BackEnd/dmforu-admin/build/libs/dmforu-admin-1.2.0.jar started by weeds2577 in /Users/weeds2577/DMU-BackEnd) -2024-11-04T03:42:00.713+09:00 INFO 57805 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : The following 1 profile is active: "local" -2024-11-04T03:42:01.123+09:00 INFO 57805 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode -2024-11-04T03:42:01.124+09:00 INFO 57805 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data MongoDB repositories in DEFAULT mode. -2024-11-04T03:42:01.150+09:00 INFO 57805 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 23 ms. Found 2 MongoDB repository interfaces. -2024-11-04T03:42:01.154+09:00 INFO 57805 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode -2024-11-04T03:42:01.155+09:00 INFO 57805 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. -2024-11-04T03:42:01.164+09:00 INFO 57805 --- [dmforu-admin] [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 7 ms. Found 2 JPA repository interfaces. -2024-11-04T03:42:01.687+09:00 INFO 57805 --- [dmforu-admin] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) -2024-11-04T03:42:01.698+09:00 INFO 57805 --- [dmforu-admin] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] -2024-11-04T03:42:01.698+09:00 INFO 57805 --- [dmforu-admin] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.30] -2024-11-04T03:42:01.730+09:00 INFO 57805 --- [dmforu-admin] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext -2024-11-04T03:42:01.731+09:00 INFO 57805 --- [dmforu-admin] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 983 ms -2024-11-04T03:42:01.846+09:00 INFO 57805 --- [dmforu-admin] [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] -2024-11-04T03:42:01.901+09:00 INFO 57805 --- [dmforu-admin] [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.5.3.Final -2024-11-04T03:42:01.932+09:00 INFO 57805 --- [dmforu-admin] [ main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled -2024-11-04T03:42:02.189+09:00 INFO 57805 --- [dmforu-admin] [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer -2024-11-04T03:42:02.215+09:00 INFO 57805 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... -2024-11-04T03:42:02.427+09:00 INFO 57805 --- [dmforu-admin] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@287ad0da -2024-11-04T03:42:02.428+09:00 INFO 57805 --- [dmforu-admin] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. -2024-11-04T03:42:02.464+09:00 WARN 57805 --- [dmforu-admin] [ main] org.hibernate.orm.deprecation : HHH90000025: MySQLDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default) -2024-11-04T03:42:03.075+09:00 INFO 57805 --- [dmforu-admin] [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) -2024-11-04T03:42:03.077+09:00 INFO 57805 --- [dmforu-admin] [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' -2024-11-04T03:42:03.350+09:00 INFO 57805 --- [dmforu-admin] [ main] o.s.d.j.r.query.QueryEnhancerFactory : Hibernate is in classpath; If applicable, HQL parser will be used. -2024-11-04T03:42:03.757+09:00 INFO 57805 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-02.qlvx9.mongodb.net:27017 to client view of cluster -2024-11-04T03:42:03.775+09:00 INFO 57805 --- [dmforu-admin] [ main] org.mongodb.driver.client : MongoClient with metadata {"application": {"name": "dmforu-test"}, "driver": {"name": "mongo-java-driver|sync", "version": "5.0.1"}, "os": {"type": "Darwin", "name": "Mac OS X", "architecture": "aarch64", "version": "14.2.1"}, "platform": "Java/Oracle Corporation/17.0.11+7-LTS-207"} created with settings MongoClientSettings{readPreference=primary, writeConcern=WriteConcern{w=majority, wTimeout=null ms, journal=null}, retryWrites=true, retryReads=true, readConcern=ReadConcern{level=null}, credential=MongoCredential{mechanism=null, userName='weeds2577', source='admin', password=, mechanismProperties=}, transportSettings=null, commandListeners=[], codecRegistry=ProvidersCodecRegistry{codecProviders=[ProvidersCodecRegistry{codecProviders=[ValueCodecProvider{}, BsonValueCodecProvider{}, DBRefCodecProvider{}, DBObjectCodecProvider{}, DocumentCodecProvider{}, CollectionCodecProvider{}, IterableCodecProvider{}, MapCodecProvider{}, GeoJsonCodecProvider{}, GridFSFileCodecProvider{}, Jsr310CodecProvider{}, JsonObjectCodecProvider{}, BsonCodecProvider{}, EnumCodecProvider{}, com.mongodb.client.model.mql.ExpressionCodecProvider@7f5a5ef3, com.mongodb.Jep395RecordCodecProvider@4c53ce60, com.mongodb.KotlinCodecProvider@3d1b6816]}, ProvidersCodecRegistry{codecProviders=[org.bson.codecs.pojo.PojoCodecProvider@508863eb]}]}, loggerSettings=LoggerSettings{maxDocumentLength=1000}, clusterSettings={hosts=[127.0.0.1:27017], srvHost=dmforu-test.qlvx9.mongodb.net, srvServiceName=mongodb, mode=MULTIPLE, requiredClusterType=REPLICA_SET, requiredReplicaSetName='atlas-m6kxjp-shard-0', serverSelector='null', clusterListeners='[]', serverSelectionTimeout='30000 ms', localThreshold='15 ms'}, socketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=0, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, heartbeatSocketSettings=SocketSettings{connectTimeoutMS=10000, readTimeoutMS=10000, receiveBufferSize=0, proxySettings=ProxySettings{host=null, port=null, username=null, password=null}}, connectionPoolSettings=ConnectionPoolSettings{maxSize=100, minSize=0, maxWaitTimeMS=120000, maxConnectionLifeTimeMS=0, maxConnectionIdleTimeMS=0, maintenanceInitialDelayMS=0, maintenanceFrequencyMS=60000, connectionPoolListeners=[], maxConnecting=2}, serverSettings=ServerSettings{heartbeatFrequencyMS=10000, minHeartbeatFrequencyMS=500, serverListeners='[]', serverMonitorListeners='[]'}, sslSettings=SslSettings{enabled=true, invalidHostNameAllowed=false, context=null}, applicationName='dmforu-test', compressorList=[], uuidRepresentation=UNSPECIFIED, serverApi=null, autoEncryptionSettings=null, dnsClient=null, inetAddressResolver=null, contextProvider=null} -2024-11-04T03:42:03.789+09:00 INFO 57805 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-00.qlvx9.mongodb.net:27017 to client view of cluster -2024-11-04T03:42:03.790+09:00 INFO 57805 --- [dmforu-admin] [vx9.mongodb.net] org.mongodb.driver.cluster : Adding discovered server dmforu-test-shard-00-01.qlvx9.mongodb.net:27017 to client view of cluster -2024-11-04T03:42:04.040+09:00 WARN 57805 --- [dmforu-admin] [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning -2024-11-04T03:42:04.292+09:00 INFO 57805 --- [dmforu-admin] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' -2024-11-04T03:42:04.301+09:00 INFO 57805 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=452648500, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az2'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=9, topologyVersion=TopologyVersion{processId=67220b6eb3ac540c1b3d2884, counter=3}, lastWriteDate=Mon Nov 04 03:42:04 KST 2024, lastUpdateTimeNanos=881451174170083} -2024-11-04T03:42:04.302+09:00 INFO 57805 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=452632125, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az3'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=7fffffff00000000000000aa, setVersion=9, topologyVersion=TopologyVersion{processId=67220879494685dc7d977f3a, counter=6}, lastWriteDate=Mon Nov 04 03:42:04 KST 2024, lastUpdateTimeNanos=881451174170083} -2024-11-04T03:42:04.307+09:00 INFO 57805 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Discovered replica set primary dmforu-test-shard-00-01.qlvx9.mongodb.net:27017 with max election id 7fffffff00000000000000aa and max set version 9 -2024-11-04T03:42:04.308+09:00 INFO 57805 --- [dmforu-admin] [ main] com.dmforu.admin.AdminApplicationKt : Started AdminApplicationKt in 3.892 seconds (process running for 4.302) -2024-11-04T03:42:04.311+09:00 INFO 57805 --- [dmforu-admin] [ngodb.net:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dmforu-test-shard-00-00.qlvx9.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=21, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=55025791, setName='atlas-m6kxjp-shard-0', canonicalAddress=dmforu-test-shard-00-00.qlvx9.mongodb.net:27017, hosts=[dmforu-test-shard-00-01.qlvx9.mongodb.net:27017, dmforu-test-shard-00-02.qlvx9.mongodb.net:27017, dmforu-test-shard-00-00.qlvx9.mongodb.net:27017], passives=[], arbiters=[], primary='dmforu-test-shard-00-01.qlvx9.mongodb.net:27017', tagSet=TagSet{[Tag{name='availabilityZone', value='apne2-az1'}, Tag{name='diskState', value='READY'}, Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='AP_NORTHEAST_2'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=9, topologyVersion=TopologyVersion{processId=67220a16b5fcab00b1d9f81a, counter=4}, lastWriteDate=Mon Nov 04 03:42:04 KST 2024, lastUpdateTimeNanos=881451184974083} From 188f4ea10e2d5523591795b101040a9838ffba37 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 23:29:25 +0900 Subject: [PATCH 211/223] =?UTF-8?q?chore:=20monitoring=20=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/src/main/resources/application.yml | 1 + dmforu-api/src/main/resources/application.yml | 1 + dmforu-support/monitoring/build.gradle.kts | 5 +++++ .../monitoring/src/main/resources/monitoring.yml | 11 +++++++++++ settings.gradle.kts | 3 ++- 5 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 dmforu-support/monitoring/build.gradle.kts create mode 100644 dmforu-support/monitoring/src/main/resources/monitoring.yml diff --git a/dmforu-admin/src/main/resources/application.yml b/dmforu-admin/src/main/resources/application.yml index bd28647..c658322 100644 --- a/dmforu-admin/src/main/resources/application.yml +++ b/dmforu-admin/src/main/resources/application.yml @@ -6,6 +6,7 @@ spring: import: - mysql.yml - mongo.yml + - monitoring.yml spring.lifecycle.timeout-per-shutdown-phase: 30s server.shutdown: graceful diff --git a/dmforu-api/src/main/resources/application.yml b/dmforu-api/src/main/resources/application.yml index 76c1df4..2a91a4a 100644 --- a/dmforu-api/src/main/resources/application.yml +++ b/dmforu-api/src/main/resources/application.yml @@ -6,6 +6,7 @@ spring: import: - mysql.yml - mongo.yml + - monitoring.yml web.resources.add-mappings: false spring-doc: diff --git a/dmforu-support/monitoring/build.gradle.kts b/dmforu-support/monitoring/build.gradle.kts new file mode 100644 index 0000000..e4daa82 --- /dev/null +++ b/dmforu-support/monitoring/build.gradle.kts @@ -0,0 +1,5 @@ +dependencies { + implementation("org.springframework.boot:spring-boot-starter-actuator") + + runtimeOnly("io.micrometer:micrometer-registry-prometheus") +} \ No newline at end of file diff --git a/dmforu-support/monitoring/src/main/resources/monitoring.yml b/dmforu-support/monitoring/src/main/resources/monitoring.yml new file mode 100644 index 0000000..1687053 --- /dev/null +++ b/dmforu-support/monitoring/src/main/resources/monitoring.yml @@ -0,0 +1,11 @@ +management: + endpoint: + metrics: + enabled: true + prometheus: + enabled: true + + endpoints: + web: + exposure: + include: health, info, metrics, prometheus diff --git a/settings.gradle.kts b/settings.gradle.kts index 72994a1..5c804bc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,7 +10,8 @@ include( "dmforu-infrastructure:storage:mysql", "dmforu-infrastructure:storage:mongo", - "dmforu-support:jacoco" + "dmforu-support:jacoco", + "dmforu-support:monitoring" ) pluginManagement { From acdf10e1a90ac04a76a50e8dd0c3fc78d02a46ba Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Tue, 5 Nov 2024 23:59:18 +0900 Subject: [PATCH 212/223] =?UTF-8?q?fix:=20monitoring=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=20api,=20admin=EC=97=90=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/build.gradle.kts | 1 + dmforu-api/build.gradle.kts | 1 + 2 files changed, 2 insertions(+) diff --git a/dmforu-admin/build.gradle.kts b/dmforu-admin/build.gradle.kts index 336669b..db20941 100644 --- a/dmforu-admin/build.gradle.kts +++ b/dmforu-admin/build.gradle.kts @@ -13,6 +13,7 @@ dependencies { runtimeOnly(project(":dmforu-infrastructure:fcm")) runtimeOnly(project(":dmforu-infrastructure:storage:mysql")) runtimeOnly(project(":dmforu-infrastructure:storage:mongo")) + runtimeOnly(project(":dmforu-support:monitoring")) testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0") } \ No newline at end of file diff --git a/dmforu-api/build.gradle.kts b/dmforu-api/build.gradle.kts index f14b99a..2401f71 100644 --- a/dmforu-api/build.gradle.kts +++ b/dmforu-api/build.gradle.kts @@ -14,6 +14,7 @@ dependencies { runtimeOnly(project(":dmforu-infrastructure:storage:mysql")) runtimeOnly(project(":dmforu-infrastructure:storage:mongo")) + runtimeOnly(project(":dmforu-support:monitoring")) testImplementation("org.springframework.boot:spring-boot-starter-validation") } \ No newline at end of file From c63287f75ae51440ea2d4c88401f3454602fc936 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 6 Nov 2024 00:46:45 +0900 Subject: [PATCH 213/223] =?UTF-8?q?fix:=20monitoring=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=20=EC=9D=98=EC=A1=B4=EC=84=B1=EC=9D=84=20runtimeOnly=EC=97=90?= =?UTF-8?q?=EC=84=9C=20implementation=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/build.gradle.kts | 2 +- dmforu-api/build.gradle.kts | 3 ++- dmforu-support/monitoring/src/main/resources/monitoring.yml | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dmforu-admin/build.gradle.kts b/dmforu-admin/build.gradle.kts index db20941..33e7224 100644 --- a/dmforu-admin/build.gradle.kts +++ b/dmforu-admin/build.gradle.kts @@ -9,11 +9,11 @@ tasks.getByName("jar") { dependencies { implementation(project(":dmforu-domain")) implementation(project(":dmforu-crawling")) + implementation(project(":dmforu-support:monitoring")) runtimeOnly(project(":dmforu-infrastructure:fcm")) runtimeOnly(project(":dmforu-infrastructure:storage:mysql")) runtimeOnly(project(":dmforu-infrastructure:storage:mongo")) - runtimeOnly(project(":dmforu-support:monitoring")) testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0") } \ No newline at end of file diff --git a/dmforu-api/build.gradle.kts b/dmforu-api/build.gradle.kts index 2401f71..d42ae16 100644 --- a/dmforu-api/build.gradle.kts +++ b/dmforu-api/build.gradle.kts @@ -8,13 +8,14 @@ tasks.getByName("jar") { dependencies { implementation(project(":dmforu-domain")) + implementation(project(":dmforu-support:monitoring")) + implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-validation") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0") runtimeOnly(project(":dmforu-infrastructure:storage:mysql")) runtimeOnly(project(":dmforu-infrastructure:storage:mongo")) - runtimeOnly(project(":dmforu-support:monitoring")) testImplementation("org.springframework.boot:spring-boot-starter-validation") } \ No newline at end of file diff --git a/dmforu-support/monitoring/src/main/resources/monitoring.yml b/dmforu-support/monitoring/src/main/resources/monitoring.yml index 1687053..c152a3f 100644 --- a/dmforu-support/monitoring/src/main/resources/monitoring.yml +++ b/dmforu-support/monitoring/src/main/resources/monitoring.yml @@ -1,4 +1,6 @@ management: + server: + port: 9292 endpoint: metrics: enabled: true From fdaed4ac4041ddacc0c478675e7a4a9bae6e80b3 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Wed, 6 Nov 2024 01:05:33 +0900 Subject: [PATCH 214/223] =?UTF-8?q?fix:=20admin=20=EB=AA=A8=EB=93=88=20act?= =?UTF-8?q?uator=20=EC=82=AC=EC=9A=A9=EC=9C=BC=EB=A1=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=95=9C=20spring-starter-web=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/build.gradle.kts | 2 ++ .../src/main/kotlin/com/dmforu/admin/AdminApplication.kt | 2 -- dmforu-admin/src/main/resources/application.yml | 1 + dmforu-support/monitoring/src/main/resources/monitoring.yml | 2 -- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dmforu-admin/build.gradle.kts b/dmforu-admin/build.gradle.kts index 33e7224..c0dff20 100644 --- a/dmforu-admin/build.gradle.kts +++ b/dmforu-admin/build.gradle.kts @@ -11,6 +11,8 @@ dependencies { implementation(project(":dmforu-crawling")) implementation(project(":dmforu-support:monitoring")) + implementation("org.springframework.boot:spring-boot-starter-web") + runtimeOnly(project(":dmforu-infrastructure:fcm")) runtimeOnly(project(":dmforu-infrastructure:storage:mysql")) runtimeOnly(project(":dmforu-infrastructure:storage:mongo")) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt index b088460..ca6d4be 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt @@ -1,6 +1,5 @@ package com.dmforu.admin -import org.springframework.boot.WebApplicationType import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.builder.SpringApplicationBuilder import org.springframework.scheduling.annotation.EnableScheduling @@ -20,6 +19,5 @@ class AdminApplication fun main(args: Array) { TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul")) SpringApplicationBuilder(AdminApplication::class.java) - .web(WebApplicationType.NONE) .run(*args) } diff --git a/dmforu-admin/src/main/resources/application.yml b/dmforu-admin/src/main/resources/application.yml index c658322..ec5181b 100644 --- a/dmforu-admin/src/main/resources/application.yml +++ b/dmforu-admin/src/main/resources/application.yml @@ -7,6 +7,7 @@ spring: - mysql.yml - mongo.yml - monitoring.yml + web.resources.add-mappings: false spring.lifecycle.timeout-per-shutdown-phase: 30s server.shutdown: graceful diff --git a/dmforu-support/monitoring/src/main/resources/monitoring.yml b/dmforu-support/monitoring/src/main/resources/monitoring.yml index c152a3f..1687053 100644 --- a/dmforu-support/monitoring/src/main/resources/monitoring.yml +++ b/dmforu-support/monitoring/src/main/resources/monitoring.yml @@ -1,6 +1,4 @@ management: - server: - port: 9292 endpoint: metrics: enabled: true From d77a422b0d0ccd8f88513d3dd9999877e2542414 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Thu, 7 Nov 2024 19:23:32 +0900 Subject: [PATCH 215/223] =?UTF-8?q?docs:=20README.md=20=EC=95=84=ED=82=A4?= =?UTF-8?q?=ED=85=8D=EC=B2=98=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..999cbb3 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# DMU-BackEnd +동양미래대학교 홈페이지의 정보들을 활용하여 더 나은 편리성을 제공하기 위해 만들어진 API 서버입니다.
+ + +## 아키텍처 +### Infrastructure +DMforU 아키텍처 + +### API Project +DMforU 아키텍처 + +### Admin Project +DMforU 아키텍처 + From e72b75b73b7d92ff86bcffdc9b05679c423ee2fc Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:14:41 +0900 Subject: [PATCH 216/223] =?UTF-8?q?feat:=20SQS=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-infrastructure/sqs/build.gradle.kts | 9 +++++++++ settings.gradle.kts | 1 + 2 files changed, 10 insertions(+) create mode 100644 dmforu-infrastructure/sqs/build.gradle.kts diff --git a/dmforu-infrastructure/sqs/build.gradle.kts b/dmforu-infrastructure/sqs/build.gradle.kts new file mode 100644 index 0000000..79719ae --- /dev/null +++ b/dmforu-infrastructure/sqs/build.gradle.kts @@ -0,0 +1,9 @@ +dependencies { + compileOnly(project(":dmforu-domain")) + + implementation(enforcedPlatform("software.amazon.awssdk:bom:2.21.20")) + implementation("software.amazon.awssdk:sqs") + + testImplementation(project(":dmforu-domain")) + testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0") +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 5c804bc..08752ba 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,6 +6,7 @@ include( "dmforu-domain", "dmforu-crawling", + "dmforu-infrastructure:sqs", "dmforu-infrastructure:fcm", "dmforu-infrastructure:storage:mysql", "dmforu-infrastructure:storage:mongo", From b2d81d5bc02b9a1f7d7805043ddca1c23c7a86c9 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:15:30 +0900 Subject: [PATCH 217/223] =?UTF-8?q?chore:=20SQS=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20.gitignore=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bc993a8..bd151f8 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ out/ ### Configuration Settings ### **/mongo.yml **/mysql.yml +**/sqs.yml **/fire-base-key.json \ No newline at end of file From aab544ccb2879b5399aa2b5b566fb23ed7ae6a08 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:16:31 +0900 Subject: [PATCH 218/223] =?UTF-8?q?feat:=20AWS=20Config=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/com/dmforu/sqs/AWSConfig.kt | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/AWSConfig.kt diff --git a/dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/AWSConfig.kt b/dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/AWSConfig.kt new file mode 100644 index 0000000..407e6ef --- /dev/null +++ b/dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/AWSConfig.kt @@ -0,0 +1,39 @@ +package com.dmforu.sqs + +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider +import software.amazon.awssdk.regions.Region +import software.amazon.awssdk.services.sqs.SqsAsyncClient + +@Configuration +class AWSConfig( + @Value("\${cloud.aws.credentials.access-key}") + val accessKey: String, + + @Value("\${cloud.aws.credentials.secret-key}") + val secretKey: String, + + @Value("\${cloud.aws.sqs.queue.url}") + val queueUrl: String, + + @Value("\${cloud.aws.sqs.queue.message-delay-seconds}") + val messageDelaySecs: Int, +) { + + @Bean + fun sqsAsyncClient(): SqsAsyncClient { + return SqsAsyncClient.builder() + .region(Region.AP_NORTHEAST_2) + .credentialsProvider(createAwsCredentialsProvider()) + .build() + } + + private fun createAwsCredentialsProvider(): StaticCredentialsProvider { + val basicAwsCredentials = AwsBasicCredentials.create(accessKey, secretKey) + + return StaticCredentialsProvider.create(basicAwsCredentials) + } +} \ No newline at end of file From a9866ead58a9168d8b6a0d68c0aee7ef399902b3 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:17:01 +0900 Subject: [PATCH 219/223] =?UTF-8?q?feat:=20SQS=20=EB=A9=94=EC=84=B8?= =?UTF-8?q?=EC=A7=80=20=EC=A0=84=EC=86=A1=20=EB=A1=9C=EC=A7=81=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/dmforu/sqs/SqsMessageMapper.kt | 32 +++++++++++++ .../com/dmforu/sqs/SqsMessageSendException.kt | 3 ++ .../kotlin/com/dmforu/sqs/SqsMessageSender.kt | 47 +++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/SqsMessageMapper.kt create mode 100644 dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/SqsMessageSendException.kt create mode 100644 dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/SqsMessageSender.kt diff --git a/dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/SqsMessageMapper.kt b/dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/SqsMessageMapper.kt new file mode 100644 index 0000000..d89a05f --- /dev/null +++ b/dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/SqsMessageMapper.kt @@ -0,0 +1,32 @@ +package com.dmforu.sqs + +import software.amazon.awssdk.services.sqs.model.MessageAttributeValue +import software.amazon.awssdk.services.sqs.model.SendMessageRequest + +object SqsMessageMapper { + + fun createRequest(content: String, attributes: Map, queueUrl: String, delaySeconds: Int): SendMessageRequest { + return SendMessageRequest.builder() + .queueUrl(queueUrl) + .delaySeconds(delaySeconds) + .messageAttributes(attributes) + .messageBody(content) + .build() + } + + fun createAttributes( + tokens: List, + title: String, + type: String, + url: String, + ): Map { + val attributes = mutableMapOf() + + attributes["tokens"] = MessageAttributeValue.builder().stringValue(tokens.toString()).dataType("String").build() + attributes["title"] = MessageAttributeValue.builder().stringValue(title).dataType("String").build() + attributes["type"] = MessageAttributeValue.builder().stringValue(type).dataType("String").build() + attributes["url"] = MessageAttributeValue.builder().stringValue(url).dataType("String").build() + + return attributes + } +} \ No newline at end of file diff --git a/dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/SqsMessageSendException.kt b/dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/SqsMessageSendException.kt new file mode 100644 index 0000000..86d994e --- /dev/null +++ b/dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/SqsMessageSendException.kt @@ -0,0 +1,3 @@ +package com.dmforu.sqs + +class SqsMessageSendException (message: String, cause: Throwable? = null) : RuntimeException(message, cause) \ No newline at end of file diff --git a/dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/SqsMessageSender.kt b/dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/SqsMessageSender.kt new file mode 100644 index 0000000..18d0236 --- /dev/null +++ b/dmforu-infrastructure/sqs/src/main/kotlin/com/dmforu/sqs/SqsMessageSender.kt @@ -0,0 +1,47 @@ +package com.dmforu.sqs + +import com.dmforu.domain.message.MessageSender +import com.dmforu.domain.message.NoticeMessage +import com.dmforu.sqs.SqsMessageMapper.createAttributes +import com.dmforu.sqs.SqsMessageMapper.createRequest +import org.springframework.stereotype.Component +import software.amazon.awssdk.services.sqs.SqsAsyncClient +import software.amazon.awssdk.services.sqs.model.SendMessageResponse +import software.amazon.awssdk.services.sqs.model.SqsException + +@Component +class SqsMessageSender( + private val sqsAsyncClient: SqsAsyncClient, + private val awsConfig: AWSConfig, +) : MessageSender { + + override fun sendNoticeMessage(message: NoticeMessage, tokens: List) { + val attributes = createAttributes( + tokens = tokens, + title = message.title, + type = message.type, + url = message.url + ) + + val request = createRequest( + content = message.body, + attributes = attributes, + queueUrl = awsConfig.queueUrl, + delaySeconds = awsConfig.messageDelaySecs + ) + + try { + val future = sqsAsyncClient.sendMessage(request) + + future.whenComplete { sendMessageResponse: SendMessageResponse, throwable: Throwable? -> + if (throwable != null) { + throw SqsMessageSendException("[SQS Async Client] 메세지 전송에 실패하였습니다.", throwable) + } + } + } catch (sqsException: SqsException) { + throw SqsMessageSendException("[SQS] 메세지 전송에 실패하였습니다.", sqsException) + } + } + + +} \ No newline at end of file From 9b7bc5c9e4444f8b91d8ca73c9113e15c0f37021 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:18:35 +0900 Subject: [PATCH 220/223] =?UTF-8?q?refactor:=20FCM=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=EC=97=90=EC=84=9C=20SQS=20=EB=AA=A8=EB=93=88=EC=9D=84=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/build.gradle.kts | 2 +- .../src/main/kotlin/com/dmforu/admin/AdminApplication.kt | 2 +- dmforu-admin/src/main/resources/application.yml | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dmforu-admin/build.gradle.kts b/dmforu-admin/build.gradle.kts index c0dff20..c5578e8 100644 --- a/dmforu-admin/build.gradle.kts +++ b/dmforu-admin/build.gradle.kts @@ -13,7 +13,7 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-web") - runtimeOnly(project(":dmforu-infrastructure:fcm")) + runtimeOnly(project(":dmforu-infrastructure:sqs")) runtimeOnly(project(":dmforu-infrastructure:storage:mysql")) runtimeOnly(project(":dmforu-infrastructure:storage:mongo")) diff --git a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt index ca6d4be..10ecf15 100644 --- a/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt +++ b/dmforu-admin/src/main/kotlin/com/dmforu/admin/AdminApplication.kt @@ -8,7 +8,7 @@ import java.util.* @SpringBootApplication( scanBasePackages = [ "com.dmforu.admin", - "com.dmforu.fcm", + "com.dmforu.sqs", "com.dmforu.storage.db.mongo", "com.dmforu.storage.db.mysql" ] diff --git a/dmforu-admin/src/main/resources/application.yml b/dmforu-admin/src/main/resources/application.yml index ec5181b..8c832cb 100644 --- a/dmforu-admin/src/main/resources/application.yml +++ b/dmforu-admin/src/main/resources/application.yml @@ -7,6 +7,7 @@ spring: - mysql.yml - mongo.yml - monitoring.yml + - sqs.yml web.resources.add-mappings: false spring.lifecycle.timeout-per-shutdown-phase: 30s From 7ad9e51d756889262a6624fe257f7c02e382b5e3 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:43:55 +0900 Subject: [PATCH 221/223] =?UTF-8?q?chore:=20CI=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=EC=97=90=20SQS=20yml=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9e1f82f..1a254b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,12 @@ jobs: run: | mkdir -p ./dmforu-infrastructure/fcm/src/main/resources/key + - name: make sqs.yml + run: | + touch ./sqs.yml + echo "${{ secrets.SQS }}" | base64 --decode > ./sqs.yml + working-directory: ./dmforu-infrastructure/sqs/src/main/resources + - name: create JSON file run: | echo '{ From bc3695f19efb717b5704241d793e85fb94619338 Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:50:31 +0900 Subject: [PATCH 222/223] =?UTF-8?q?fix:=20SQS=20yml=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EC=9D=84=20=EC=A0=80=EC=9E=A5=ED=95=A0=20=EB=94=94=EB=9E=99?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a254b4..b22c143 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,9 +41,9 @@ jobs: echo "${{ secrets.MONGO }}" | base64 --decode > ./mongo.yml working-directory: ./dmforu-infrastructure/storage/mongo/src/main/resources - - name: Create Firebase key resources directory + - name: Create SQS resources directory run: | - mkdir -p ./dmforu-infrastructure/fcm/src/main/resources/key + mkdir -p ./dmforu-infrastructure/sqs/src/main/resources - name: make sqs.yml run: | @@ -51,6 +51,10 @@ jobs: echo "${{ secrets.SQS }}" | base64 --decode > ./sqs.yml working-directory: ./dmforu-infrastructure/sqs/src/main/resources + - name: Create Firebase key resources directory + run: | + mkdir -p ./dmforu-infrastructure/fcm/src/main/resources/key + - name: create JSON file run: | echo '{ From 178229ecd1da0ca0bdc0e6c9847bd64412a4167c Mon Sep 17 00:00:00 2001 From: GiJung <101462387+GiJungPark@users.noreply.github.com> Date: Mon, 11 Nov 2024 01:27:06 +0900 Subject: [PATCH 223/223] =?UTF-8?q?chore:=20prod=20=ED=99=98=EA=B2=BD=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmforu-admin/src/main/resources/application.yml | 6 +++++- dmforu-api/src/main/resources/application.yml | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/dmforu-admin/src/main/resources/application.yml b/dmforu-admin/src/main/resources/application.yml index 8c832cb..6766b84 100644 --- a/dmforu-admin/src/main/resources/application.yml +++ b/dmforu-admin/src/main/resources/application.yml @@ -22,4 +22,8 @@ spring.config.activate.on-profile: test --- -spring.config.activate.on-profile: dev \ No newline at end of file +spring.config.activate.on-profile: dev + + +--- +spring.config.activate.on-profile: prod \ No newline at end of file diff --git a/dmforu-api/src/main/resources/application.yml b/dmforu-api/src/main/resources/application.yml index 2a91a4a..8b67cdd 100644 --- a/dmforu-api/src/main/resources/application.yml +++ b/dmforu-api/src/main/resources/application.yml @@ -26,4 +26,8 @@ spring.config.activate.on-profile: test --- -spring.config.activate.on-profile: dev \ No newline at end of file +spring.config.activate.on-profile: dev + + +--- +spring.config.activate.on-profile: prod \ No newline at end of file