-
Notifications
You must be signed in to change notification settings - Fork 1
feat: 어드민 일정 관리 API 추가 #139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a999617
95cff86
a6f7705
ed20f00
0c3ccff
52a5fa6
fad29c1
281c089
3acdd06
3aa189d
0edd363
2927757
da98a0d
3351fa5
2703369
d004db9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| package gg.agit.konect.admin.schedule.controller; | ||
|
|
||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.DeleteMapping; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.PutMapping; | ||
| import org.springframework.web.bind.annotation.RequestBody; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.PathVariable; | ||
|
|
||
| import gg.agit.konect.admin.schedule.dto.AdminScheduleCreateRequest; | ||
| import gg.agit.konect.admin.schedule.dto.AdminScheduleUpsertRequest; | ||
| import gg.agit.konect.domain.user.enums.UserRole; | ||
| import gg.agit.konect.global.auth.annotation.Auth; | ||
| import gg.agit.konect.global.auth.annotation.UserId; | ||
| import io.swagger.v3.oas.annotations.Operation; | ||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||
| import jakarta.validation.Valid; | ||
|
|
||
| @Tag(name = "(Admin) Schedule: 일정", description = "어드민 일정 API") | ||
| @RequestMapping("/admin/schedules") | ||
| @Auth(roles = {UserRole.ADMIN}) | ||
| public interface AdminScheduleApi { | ||
|
|
||
| @Operation(summary = "일정을 생성한다.", description = """ | ||
| **scheduleType (일정 구분):** | ||
| - `UNIVERSITY`: 대학교 일정 | ||
| - `CLUB`: 동아리 일정 | ||
| - `COUNCIL`: 총동아리연합회 일정 | ||
| - `DORM`: 기숙사 일정 | ||
| """) | ||
| @PostMapping | ||
| ResponseEntity<Void> createSchedule( | ||
| @Valid @RequestBody AdminScheduleCreateRequest request, | ||
| @UserId Integer userId | ||
| ); | ||
|
|
||
| @Operation(summary = "일정을 일괄 생성/수정한다.", description = """ | ||
| scheduleId가 없으면 신규 생성, 있으면 해당 일정 수정입니다. | ||
|
|
||
| **scheduleType (일정 구분):** | ||
| - `UNIVERSITY`: 대학교 일정 | ||
| - `CLUB`: 동아리 일정 | ||
| - `COUNCIL`: 총동아리연합회 일정 | ||
| - `DORM`: 기숙사 일정 | ||
| """) | ||
| @PutMapping("/batch") | ||
| ResponseEntity<Void> upsertSchedules( | ||
| @Valid @RequestBody AdminScheduleUpsertRequest request, | ||
| @UserId Integer userId | ||
| ); | ||
|
|
||
| @Operation(summary = "일정을 삭제한다.") | ||
| @DeleteMapping("/{scheduleId}") | ||
| ResponseEntity<Void> deleteSchedule( | ||
| @PathVariable Integer scheduleId, | ||
| @UserId Integer userId | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package gg.agit.konect.admin.schedule.controller; | ||
|
|
||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| import gg.agit.konect.admin.schedule.dto.AdminScheduleCreateRequest; | ||
| import gg.agit.konect.admin.schedule.dto.AdminScheduleUpsertRequest; | ||
| import gg.agit.konect.admin.schedule.service.AdminScheduleService; | ||
| import lombok.RequiredArgsConstructor; | ||
|
|
||
| @RestController | ||
| @RequiredArgsConstructor | ||
| @RequestMapping("/admin/schedules") | ||
| public class AdminScheduleController implements AdminScheduleApi { | ||
|
|
||
| private final AdminScheduleService adminScheduleService; | ||
|
|
||
| @Override | ||
| public ResponseEntity<Void> createSchedule(AdminScheduleCreateRequest request, Integer userId) { | ||
| adminScheduleService.createSchedule(request, userId); | ||
|
|
||
| return ResponseEntity.ok().build(); | ||
| } | ||
|
|
||
| @Override | ||
| public ResponseEntity<Void> upsertSchedules(AdminScheduleUpsertRequest request, Integer userId) { | ||
| adminScheduleService.upsertSchedules(request, userId); | ||
|
|
||
| return ResponseEntity.ok().build(); | ||
| } | ||
|
|
||
| @Override | ||
| public ResponseEntity<Void> deleteSchedule(Integer scheduleId, Integer userId) { | ||
| adminScheduleService.deleteSchedule(scheduleId, userId); | ||
|
|
||
| return ResponseEntity.ok().build(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package gg.agit.konect.admin.schedule.dto; | ||
|
|
||
| import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; | ||
|
|
||
| import java.time.LocalDateTime; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonFormat; | ||
|
|
||
| import gg.agit.konect.domain.schedule.model.ScheduleType; | ||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import jakarta.validation.constraints.NotBlank; | ||
| import jakarta.validation.constraints.NotNull; | ||
|
|
||
| public record AdminScheduleCreateRequest( | ||
| @NotBlank(message = "일정 제목은 필수 입력입니다.") | ||
| @Schema(description = "일정 제목", example = "동계방학", requiredMode = REQUIRED) | ||
| String title, | ||
|
|
||
| @NotNull(message = "일정 시작 일시는 필수 입력입니다.") | ||
| @Schema(description = "일정 시작 일시", example = "2025.12.22 00:00:00", requiredMode = REQUIRED) | ||
| @JsonFormat(pattern = "yyyy.MM.dd HH:mm:ss") | ||
| LocalDateTime startedAt, | ||
|
|
||
| @NotNull(message = "일정 종료 일시는 필수 입력입니다.") | ||
| @Schema(description = "일정 종료 일시", example = "2026.02.27 23:59:59", requiredMode = REQUIRED) | ||
| @JsonFormat(pattern = "yyyy.MM.dd HH:mm:ss") | ||
| LocalDateTime endedAt, | ||
|
|
||
| @NotNull(message = "일정 종류는 필수 입력입니다.") | ||
| @Schema(description = "일정 종류", example = "UNIVERSITY", requiredMode = REQUIRED) | ||
| ScheduleType scheduleType | ||
| ) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package gg.agit.konect.admin.schedule.dto; | ||
|
|
||
| import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; | ||
|
|
||
| import java.time.LocalDateTime; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonFormat; | ||
|
|
||
| import gg.agit.konect.domain.schedule.model.ScheduleType; | ||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import jakarta.validation.constraints.NotBlank; | ||
| import jakarta.validation.constraints.NotNull; | ||
|
|
||
| public record AdminScheduleUpsertItemRequest( | ||
| @Schema(description = "수정할 일정 ID (없으면 신규 생성)", example = "1") | ||
| Integer scheduleId, | ||
|
|
||
| @NotBlank(message = "일정 제목은 필수 입력입니다.") | ||
| @Schema(description = "일정 제목", example = "동계방학", requiredMode = REQUIRED) | ||
| String title, | ||
|
|
||
| @NotNull(message = "일정 시작 일시는 필수 입력입니다.") | ||
| @Schema(description = "일정 시작 일시", example = "2025.12.22 00:00:00", requiredMode = REQUIRED) | ||
| @JsonFormat(pattern = "yyyy.MM.dd HH:mm:ss") | ||
| LocalDateTime startedAt, | ||
|
|
||
| @NotNull(message = "일정 종료 일시는 필수 입력입니다.") | ||
| @Schema(description = "일정 종료 일시", example = "2026.02.27 23:59:59", requiredMode = REQUIRED) | ||
| @JsonFormat(pattern = "yyyy.MM.dd HH:mm:ss") | ||
| LocalDateTime endedAt, | ||
|
|
||
| @NotNull(message = "일정 종류는 필수 입력입니다.") | ||
| @Schema(description = "일정 종류", example = "UNIVERSITY", requiredMode = REQUIRED) | ||
| ScheduleType scheduleType | ||
| ) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package gg.agit.konect.admin.schedule.dto; | ||
|
|
||
| import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import jakarta.validation.Valid; | ||
| import jakarta.validation.constraints.NotEmpty; | ||
|
|
||
| public record AdminScheduleUpsertRequest( | ||
| @NotEmpty(message = "일정 목록은 필수 입력입니다.") | ||
| @Schema(description = "생성/수정할 일정 목록", requiredMode = REQUIRED) | ||
| List<@Valid AdminScheduleUpsertItemRequest> schedules | ||
| ) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| package gg.agit.konect.admin.schedule.service; | ||
|
|
||
| import java.time.LocalDateTime; | ||
|
|
||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| import gg.agit.konect.admin.schedule.dto.AdminScheduleCreateRequest; | ||
| import gg.agit.konect.admin.schedule.dto.AdminScheduleUpsertItemRequest; | ||
| import gg.agit.konect.admin.schedule.dto.AdminScheduleUpsertRequest; | ||
| import gg.agit.konect.domain.schedule.model.Schedule; | ||
| import gg.agit.konect.domain.schedule.model.ScheduleType; | ||
| import gg.agit.konect.domain.schedule.model.UniversitySchedule; | ||
| import gg.agit.konect.domain.schedule.repository.ScheduleRepository; | ||
| import gg.agit.konect.domain.schedule.repository.UniversityScheduleRepository; | ||
| import gg.agit.konect.domain.university.model.University; | ||
| import gg.agit.konect.domain.user.model.User; | ||
| import gg.agit.konect.domain.user.repository.UserRepository; | ||
| import lombok.RequiredArgsConstructor; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| @Transactional(readOnly = true) | ||
| public class AdminScheduleService { | ||
|
|
||
| private final UserRepository userRepository; | ||
| private final ScheduleRepository scheduleRepository; | ||
| private final UniversityScheduleRepository universityScheduleRepository; | ||
|
|
||
| @Transactional | ||
| public void createSchedule(AdminScheduleCreateRequest request, Integer userId) { | ||
| User user = userRepository.getById(userId); | ||
| University university = user.getUniversity(); | ||
|
|
||
| createUniversitySchedule( | ||
| university, | ||
| request.title(), | ||
| request.startedAt(), | ||
| request.endedAt(), | ||
| request.scheduleType() | ||
| ); | ||
| } | ||
|
|
||
| @Transactional | ||
| public void upsertSchedules(AdminScheduleUpsertRequest request, Integer userId) { | ||
| User user = userRepository.getById(userId); | ||
| University university = user.getUniversity(); | ||
|
|
||
| for (AdminScheduleUpsertItemRequest item : request.schedules()) { | ||
| if (item.scheduleId() == null) { | ||
| createUniversitySchedule( | ||
| university, | ||
| item.title(), | ||
| item.startedAt(), | ||
| item.endedAt(), | ||
| item.scheduleType() | ||
| ); | ||
| continue; | ||
| } | ||
|
|
||
| UniversitySchedule universitySchedule = universityScheduleRepository.getByIdAndUniversityId( | ||
| item.scheduleId(), | ||
| university.getId() | ||
| ); | ||
|
|
||
| universitySchedule.getSchedule().update( | ||
| item.title(), | ||
| item.startedAt(), | ||
| item.endedAt(), | ||
| item.scheduleType() | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| @Transactional | ||
| public void deleteSchedule(Integer scheduleId, Integer userId) { | ||
| User user = userRepository.getById(userId); | ||
| University university = user.getUniversity(); | ||
|
|
||
| UniversitySchedule universitySchedule = universityScheduleRepository.getByIdAndUniversityId( | ||
| scheduleId, | ||
| university.getId() | ||
| ); | ||
|
|
||
| universityScheduleRepository.delete(universitySchedule); | ||
| scheduleRepository.delete(universitySchedule.getSchedule()); | ||
|
Comment on lines
+85
to
+86
|
||
| } | ||
|
|
||
| private void createUniversitySchedule( | ||
| University university, | ||
| String title, | ||
| LocalDateTime startedAt, | ||
| LocalDateTime endedAt, | ||
| ScheduleType scheduleType | ||
| ) { | ||
| Schedule schedule = Schedule.of( | ||
| title, | ||
| startedAt, | ||
| endedAt, | ||
| scheduleType | ||
| ); | ||
|
|
||
| Schedule savedSchedule = scheduleRepository.save(schedule); | ||
|
|
||
| UniversitySchedule universitySchedule = UniversitySchedule.of( | ||
| savedSchedule, | ||
| university | ||
| ); | ||
|
|
||
| universityScheduleRepository.save(universitySchedule); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.