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 +)