Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package kgu.developers.admin.schedule.application;

import kgu.developers.admin.schedule.presentation.request.ScheduleContentUpdateRequest;
import kgu.developers.admin.schedule.presentation.request.ScheduleCreateRequest;
import kgu.developers.admin.schedule.presentation.request.ScheduleUpdateRequest;
import kgu.developers.admin.schedule.presentation.response.SchedulePersistResponse;
import kgu.developers.domain.schedule.application.command.ScheduleService;
import kgu.developers.domain.schedule.application.query.ScheduleQueryService;
import kgu.developers.domain.schedule.domain.Schedule;
import kgu.developers.domain.schedule.domain.SubmissionType;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@Transactional
@RequiredArgsConstructor
public class ScheduleAdminFacade {
private final ScheduleService scheduleService;
Comment thread
dkdltm221 marked this conversation as resolved.
Outdated
private final ScheduleQueryService scheduleQueryService;

public SchedulePersistResponse createSchedule(ScheduleCreateRequest request) {
Long id = scheduleService.createSchedule(
request.submissionType(),
request.title(),
request.content(),
request.startDate(),
request.endDate()
);
return SchedulePersistResponse.from(id);
}

public void updateSchedule(Long scheduleId, ScheduleUpdateRequest request) {
Schedule schedule = scheduleQueryService.getScheduleManagement(scheduleId);
scheduleService.updateSchedule(
schedule,
request.submissionType(),
request.title(),
request.startDate(),
request.endDate()
);
}

public void updateScheduleContent(SubmissionType submissionType, ScheduleContentUpdateRequest request) {
Schedule schedule =scheduleQueryService.getBySubmissionType(submissionType);
scheduleService.updateScheduleContent(schedule,request.content());
}

public void deleteSchedule(Long scheduleId) {
scheduleService.deleteSchedule(scheduleId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package kgu.developers.admin.schedule.presentation;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
import kgu.developers.admin.schedule.presentation.request.ScheduleContentUpdateRequest;
import kgu.developers.admin.schedule.presentation.request.ScheduleCreateRequest;
import kgu.developers.admin.schedule.presentation.request.ScheduleUpdateRequest;
import kgu.developers.admin.schedule.presentation.response.SchedulePersistResponse;
import kgu.developers.domain.schedule.domain.SubmissionType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;


@Tag(name = "Schedule", description = "일정 관리 API")
public interface ScheduleAdminController {

@Operation(summary = "일정 생성 API", description = """
- Description : 이 API는 일정을 생성합니다.
- Assignee : 주윤빈
""")
@ApiResponse(
responseCode = "201",
content = @Content(schema = @Schema(implementation = SchedulePersistResponse.class)))
ResponseEntity<SchedulePersistResponse> createSchedule(
@Parameter(
description = "일정 생성 request 객체 입니다.",
required = true
)@Valid @RequestBody
ScheduleCreateRequest request
);

@Operation(summary = "일정 수정 API", description = """
- Description : 이 API는 일정을 수정합니다.
- Assignee : 주윤빈
""")
@ApiResponse(responseCode = "204")
ResponseEntity<Void> updateSchedule(
@Parameter(
description = "이 API는 제출 유형/제목/기간을 수정합니다.",
example = "1",
required = true
)@Positive @PathVariable Long scheduleId,
@Parameter(
description = "일정 수정 request 객체 입니다.",
required = true
)@Valid @RequestBody ScheduleUpdateRequest request
);

@Operation(summary = "유형별 본문 수정 API",description = """
-Description : 이 API는 제출 유형을 기준으로 본문만 수정합니다.
-Assignee : 주윤빈
""")
@ApiResponse(responseCode = "204")
ResponseEntity<Void> updateScheduleContent(
@Parameter(
description = "본문을 수정할 제출 유형입니다.",
example = "MIDTHESIS",
required = true
)@PathVariable SubmissionType submissionType,
@Parameter(description = "본문 수정 request 객체 입니다.",
required = true
)@Valid @RequestBody ScheduleContentUpdateRequest request
);

@Operation(summary = "일정 삭제 API", description = """
- Description : 이 API는 일정을 삭제합니다.
- Assignee : 주윤빈
""")
@ApiResponse(responseCode = "204")
ResponseEntity<Void> deleteSchedule(
@Parameter(
description = "삭제할 일정의 ID 입니다.",
example = "1",
required = true
)@Positive @PathVariable Long scheduleId
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package kgu.developers.admin.schedule.presentation;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
import kgu.developers.admin.schedule.application.ScheduleAdminFacade;
import kgu.developers.admin.schedule.presentation.request.ScheduleContentUpdateRequest;
import kgu.developers.admin.schedule.presentation.request.ScheduleCreateRequest;
import kgu.developers.admin.schedule.presentation.request.ScheduleUpdateRequest;
import kgu.developers.admin.schedule.presentation.response.SchedulePersistResponse;
import kgu.developers.domain.schedule.domain.SubmissionType;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import static org.springframework.http.HttpStatus.CREATED;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/admin/schedules")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public class ScheduleAdminControllerImpl implements ScheduleAdminController {
private final ScheduleAdminFacade scheduleAdminFacade;

@Override
@PostMapping
public ResponseEntity<SchedulePersistResponse> createSchedule(
@Valid @RequestBody ScheduleCreateRequest request
){
SchedulePersistResponse response = scheduleAdminFacade.createSchedule(request);
return ResponseEntity.status(CREATED).body(response);
}

@Override
@PatchMapping("/{scheduleId}")
public ResponseEntity<Void> updateSchedule(
@Positive @PathVariable Long scheduleId,
@Valid @RequestBody ScheduleUpdateRequest request
){
scheduleAdminFacade.updateSchedule(scheduleId, request);
return ResponseEntity.noContent().build();
}

@Override
@PatchMapping("/type/{submissionType}/content")
public ResponseEntity<Void> updateScheduleContent(
@PathVariable SubmissionType submissionType,
@Valid @RequestBody ScheduleContentUpdateRequest request
){
scheduleAdminFacade.updateScheduleContent(submissionType, request);
return ResponseEntity.noContent().build();
}
@Override
@DeleteMapping("/{scheduleId}")
public ResponseEntity<Void> deleteSchedule(
@Positive @PathVariable Long scheduleId
){
scheduleAdminFacade.deleteSchedule(scheduleId);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package kgu.developers.admin.schedule.presentation.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

public record ScheduleContentUpdateRequest(
@Schema(description = "일정 내용", example = "매학기 개강 후 2주 이내에 신청서를 작성하여 접수해야합니다.",requiredMode = REQUIRED)
@NotBlank
String content
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package kgu.developers.admin.schedule.presentation.request;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
import kgu.developers.domain.schedule.domain.SubmissionType;

import java.time.LocalDateTime;

public record ScheduleCreateRequest(
@Schema(description = "제출 유형", example = "SUBMITTED", requiredMode = REQUIRED)
@NotNull SubmissionType submissionType,

@Schema(description = "일정 제목", example = "중간논문 제출 안내",requiredMode = REQUIRED)
@NotBlank @Size(max=100,message = "일정 제목은 100자 이내여야 합니다.") String title,

@Schema(description = "일정 내용", example = "매학기 개강 후 2주 이내에 신청서를 작성하여 접수해야합니다.",requiredMode = REQUIRED)
@NotBlank String content,

@Schema(description = "시작 일시", example = "2025-04-15T00:00:00", requiredMode = REQUIRED)
@NotNull LocalDateTime startDate,

@Schema(description = "종료 일시", example = "2025-12-31T23:59:59", requiredMode = REQUIRED)
@NotNull LocalDateTime endDate
) {
@AssertTrue(message = "종료 일시는 시작 일시 이후여야 합니다.")
public boolean isValidDateRange() {
if (startDate ==null || endDate == null) {
return true;
}
return !endDate.isBefore(startDate);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package kgu.developers.admin.schedule.presentation.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
import kgu.developers.domain.schedule.domain.SubmissionType;

import java.time.LocalDateTime;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

public record ScheduleUpdateRequest(
@Schema(description = "제출 유형", example = "SUBMITTED", requiredMode = REQUIRED)
@NotNull
SubmissionType submissionType,

@Schema(description = "일정 제목", example = "중간논문 제출 안내",requiredMode = REQUIRED)
@NotBlank @Size(max=100,message = "일정 제목은 100자 이내여야 합니다.")
String title,


@Schema(description = "시작 일시", example = "2025-04-15T00:00:00", requiredMode = REQUIRED)
@NotNull
LocalDateTime startDate,

@Schema(description = "종료 일시", example = "2025-12-31T23:59:59", requiredMode = REQUIRED)
@NotNull
LocalDateTime endDate
) {
@AssertTrue(message = "종료 일시는 시작 일시 이후여야 합니다.")
Comment thread
dkdltm221 marked this conversation as resolved.
public boolean isValidDateRange() {
if (startDate ==null || endDate == null) {
return true;
}
return !endDate.isBefore(startDate);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package kgu.developers.admin.schedule.presentation.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

@Builder
public record SchedulePersistResponse(
@Schema(description = "일정 id", example = "1", requiredMode = REQUIRED)
Long scheduleId
) {
public static SchedulePersistResponse from(Long scheduleId) {
return SchedulePersistResponse.builder()
.scheduleId(scheduleId)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package kgu.developers.api.schedule.application;

import kgu.developers.domain.schedule.application.command.ScheduleService;
import kgu.developers.domain.schedule.application.query.ScheduleQueryService;
import kgu.developers.domain.schedule.domain.Schedule;
import kgu.developers.domain.schedule.domain.SubmissionType;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Component
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class ScheduleFacade {
private final ScheduleQueryService scheduleQueryService;

public List<Schedule> findAll() {
return scheduleQueryService.getAllScheduleManagements();
}
public Schedule findBySubmissionType(SubmissionType submissionType) {
return scheduleQueryService.getBySubmissionType(submissionType);
}

public Schedule findById(Long id) {
return scheduleQueryService.getScheduleManagement(id);
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package kgu.developers.api.schedule.presentation;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import kgu.developers.api.schedule.presentation.response.ScheduleListResponse;
import kgu.developers.api.schedule.presentation.response.ScheduleSummaryResponse;
import kgu.developers.api.schedule.presentation.response.ScheduleTypeContentResponse;
import kgu.developers.domain.schedule.domain.SubmissionType;
import org.springframework.http.ResponseEntity;

@Tag(name = "Schedule", description = "일정관리 API")
public interface ScheduleController {

@Operation(summary = "전체 일정 조회 API", description = """
- Description : 이 API는 모든 일정을 조회합니다.
- Assignee : 주윤빈
""")
@ApiResponse(
responseCode = "200",
content = @Content(schema = @Schema(implementation = ScheduleListResponse.class)))
ResponseEntity<ScheduleListResponse> getScheduleList();

@Operation(summary = "유형별 일정 본문 조회 API", description = """
- Description : 이 API는 제출유형별 본문만 조회합니다.
- Assignee : 주윤빈
""")
@ApiResponse(
responseCode = "200",
content = @Content(schema = @Schema(implementation = ScheduleTypeContentResponse.class)))
ResponseEntity<ScheduleTypeContentResponse> getSchedulesByType(SubmissionType type);

@Operation(summary = "단일 일정 조회 API", description = """
- Description : 이 API는 단일 일정을 조회합니다.
- Assignee : 주윤빈
""")
@ApiResponse(
responseCode = "200",
content = @Content(schema = @Schema(implementation = ScheduleSummaryResponse.class)))
ResponseEntity<ScheduleSummaryResponse> getScheduleById(Long id);
}
Loading
Loading