From 525b693effae738d7b375e6623069d2306442eed Mon Sep 17 00:00:00 2001 From: pricelees Date: Thu, 4 Sep 2025 11:34:30 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9D=BC=EC=A0=95=20API=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98=20=EB=B0=8F=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/schedule/docs/ScheduleAPI.kt | 69 ++++++++++++++++++ .../schedule/web/ScheduleController.kt | 71 +++++++++++++++++++ .../roomescape/schedule/web/ScheduleDto.kt | 65 +++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 src/main/kotlin/roomescape/schedule/docs/ScheduleAPI.kt create mode 100644 src/main/kotlin/roomescape/schedule/web/ScheduleController.kt create mode 100644 src/main/kotlin/roomescape/schedule/web/ScheduleDto.kt diff --git a/src/main/kotlin/roomescape/schedule/docs/ScheduleAPI.kt b/src/main/kotlin/roomescape/schedule/docs/ScheduleAPI.kt new file mode 100644 index 00000000..579c02a5 --- /dev/null +++ b/src/main/kotlin/roomescape/schedule/docs/ScheduleAPI.kt @@ -0,0 +1,69 @@ +package roomescape.schedule.docs + +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.responses.ApiResponses +import jakarta.validation.Valid +import org.springframework.format.annotation.DateTimeFormat +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestParam +import roomescape.auth.web.support.Admin +import roomescape.auth.web.support.LoginRequired +import roomescape.common.dto.response.CommonApiResponse +import roomescape.schedule.web.* +import java.time.LocalDate + +interface ScheduleAPI { + + @LoginRequired + @Operation(summary = "입력된 날짜에 가능한 테마 목록 조회", tags = ["로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "200", description = "입력된 날짜에 가능한 테마 목록 조회", useReturnTypeSchema = true)) + fun findAvailableThemes( + @RequestParam("date") @DateTimeFormat(pattern = "yyyy-MM-dd") date: LocalDate + ): ResponseEntity> + + @LoginRequired + @Operation(summary = "입력된 날짜, 테마에 대한 모든 시간 조회", tags = ["로그인이 필요한 API"]) + @ApiResponses( + ApiResponse( + responseCode = "200", + description = "입력된 날짜, 테마에 대한 모든 시간 조회", + useReturnTypeSchema = true + ) + ) + fun findAllTime( + @RequestParam("date") @DateTimeFormat(pattern = "yyyy-MM-dd") date: LocalDate, + @RequestParam("themeId") themeId: Long + ): ResponseEntity> + + @Admin + @Operation(summary = "일정 상세 조회", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "200", description = "감사 정보를 포함하여 일정 상세 조회", useReturnTypeSchema = true)) + fun findScheduleDetail( + @PathVariable("id") id: Long + ): ResponseEntity> + + @Admin + @Operation(summary = "일정 생성", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) + fun createSchedule( + @Valid @RequestBody request: ScheduleCreateRequest + ): ResponseEntity> + + @Admin + @Operation(summary = "일정 수정", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) + fun updateSchedule( + @PathVariable("id") id: Long, + @Valid @RequestBody request: ScheduleUpdateRequest + ): ResponseEntity> + + @Admin + @Operation(summary = "일정 삭제", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "204", description = "성공", useReturnTypeSchema = true)) + fun deleteSchedule( + @PathVariable("id") id: Long + ): ResponseEntity> +} diff --git a/src/main/kotlin/roomescape/schedule/web/ScheduleController.kt b/src/main/kotlin/roomescape/schedule/web/ScheduleController.kt new file mode 100644 index 00000000..6396fe40 --- /dev/null +++ b/src/main/kotlin/roomescape/schedule/web/ScheduleController.kt @@ -0,0 +1,71 @@ +package roomescape.schedule.web + +import jakarta.validation.Valid +import org.springframework.format.annotation.DateTimeFormat +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import roomescape.common.dto.response.CommonApiResponse +import roomescape.schedule.business.ScheduleService +import roomescape.schedule.docs.ScheduleAPI +import java.time.LocalDate + +@RestController +class ScheduleController( + private val scheduleService: ScheduleService +) : ScheduleAPI { + @GetMapping("/schedules/themes") + override fun findAvailableThemes( + @RequestParam("date") @DateTimeFormat(pattern = "yyyy-MM-dd") date: LocalDate + ): ResponseEntity> { + val response = scheduleService.findThemesByDate(date) + + return ResponseEntity.ok(CommonApiResponse(response)) + } + + @GetMapping("/schedules") + override fun findAllTime( + @RequestParam("date") @DateTimeFormat(pattern = "yyyy-MM-dd") date: LocalDate, + @RequestParam("themeId") themeId: Long + ): ResponseEntity> { + val response = scheduleService.findSchedules(date, themeId) + + return ResponseEntity.ok(CommonApiResponse(response)) + } + + @GetMapping("/schedules/{id}") + override fun findScheduleDetail( + @PathVariable("id") id: Long + ): ResponseEntity> { + val response = scheduleService.findDetail(id) + + return ResponseEntity.ok(CommonApiResponse(response)) + } + + @PostMapping("/schedules") + override fun createSchedule( + @Valid @RequestBody request: ScheduleCreateRequest + ): ResponseEntity> { + val response = scheduleService.createSchedule(request) + + return ResponseEntity.ok(CommonApiResponse(response)) + } + + @PatchMapping("/schedules/{id}") + override fun updateSchedule( + @PathVariable("id") id: Long, + @Valid @RequestBody request: ScheduleUpdateRequest + ): ResponseEntity> { + scheduleService.updateSchedule(id, request) + + return ResponseEntity.ok(CommonApiResponse(Unit)) + } + + @DeleteMapping("/schedules/{id}") + override fun deleteSchedule( + @PathVariable("id") id: Long + ): ResponseEntity> { + scheduleService.deleteSchedule(id) + + return ResponseEntity.noContent().build() + } +} diff --git a/src/main/kotlin/roomescape/schedule/web/ScheduleDto.kt b/src/main/kotlin/roomescape/schedule/web/ScheduleDto.kt new file mode 100644 index 00000000..68526635 --- /dev/null +++ b/src/main/kotlin/roomescape/schedule/web/ScheduleDto.kt @@ -0,0 +1,65 @@ +package roomescape.schedule.web + +import roomescape.schedule.infrastructure.persistence.ScheduleEntity +import roomescape.schedule.infrastructure.persistence.ScheduleStatus +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime + +data class AvailableThemeIdListResponse( + val themeIds: List +) + +fun List.toThemeIdListResponse() = AvailableThemeIdListResponse(this.map { it.themeId }) + +data class ScheduleRetrieveResponse( + val id: Long, + val time: LocalTime, + val status: ScheduleStatus +) + +data class ScheduleRetrieveListResponse( + val schedules: List +) + +fun List.toRetrieveListResponse() = ScheduleRetrieveListResponse( + this.map { ScheduleRetrieveResponse(it.id, it.time, it.status) } +) + +data class ScheduleCreateRequest( + val date: LocalDate, + val time: LocalTime, + + val themeId: Long +) + +data class ScheduleCreateResponse( + val id: Long +) + +data class ScheduleUpdateRequest( + val time: LocalTime? = null, + val status: ScheduleStatus? = null +) + +data class ScheduleDetailRetrieveResponse( + val id: Long, + val date: LocalDate, + val time: LocalTime, + val status: ScheduleStatus, + val createdAt: LocalDateTime, + val createdBy: String, + val updatedAt: LocalDateTime, + val updatedBy: String, +) + +fun ScheduleEntity.toDetailRetrieveResponse(createdBy: String, updatedBy: String) = ScheduleDetailRetrieveResponse( + id = this.id, + date = this.date, + time = this.time, + status = this.status, + createdAt = this.createdAt, + createdBy = createdBy, + updatedAt = this.updatedAt, + updatedBy = updatedBy +)