From a4d942b8b2111164f818700d98ed8a881d1729e3 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:25:01 +0900 Subject: [PATCH 01/34] =?UTF-8?q?[SW-127]=20feat(seasonMission=20Read):=20?= =?UTF-8?q?=ED=8A=B9=EC=A0=95=20=EC=8B=9C=EC=A6=8C=EC=9D=98=20=ED=8A=B9?= =?UTF-8?q?=EB=B3=84=20=EB=AF=B8=EC=85=98=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AdminSeasonMissionController.java | 9 +++++++++ .../service/AdminSeasonMissionService.java | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/controller/AdminSeasonMissionController.java b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/controller/AdminSeasonMissionController.java index b0425af..00ec19e 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/controller/AdminSeasonMissionController.java +++ b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/controller/AdminSeasonMissionController.java @@ -32,6 +32,15 @@ public ApiResponse getSeasonMissions( return ApiResponse.ok(adminSeasonMissionService.getSeasonMissions(season)); } + @GetMapping("/special") + @Operation(summary = "특정 시즌 스페셜 미션 조회") + public ApiResponse getSeasonSpecialMissions( + @Parameter(description = "시즌 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Season season + ) { + + return ApiResponse.ok(adminSeasonMissionService.getSeasonSpecialMissions(season)); + } + @PostMapping("/{mission}") @Operation(summary = "시즌 미션 생성") public ApiResponse createSeasonMission( diff --git a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/service/AdminSeasonMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/service/AdminSeasonMissionService.java index 569538a..7e572e6 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/service/AdminSeasonMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/service/AdminSeasonMissionService.java @@ -3,6 +3,7 @@ import com.github.kmu_shell_we.domain.mission._season_mission.entity.SeasonMission; import com.github.kmu_shell_we.domain.mission._season_mission.exception.SeasonMissionExceptions; import com.github.kmu_shell_we.domain.mission._season_mission.repository.SeasonMissionRepository; +import com.github.kmu_shell_we.domain.mission.constant.MissionType; import com.github.kmu_shell_we.domain.mission.dto.response.MissionListResponse; import com.github.kmu_shell_we.domain.mission.dto.response.MissionResponse; import com.github.kmu_shell_we.domain.mission.entity.Mission; @@ -23,6 +24,14 @@ public MissionListResponse getSeasonMissions(Season season) { return MissionListResponse.fromSeasonMission(seasonMissionRepository.findAllBySeason(season)); } + @Transactional(readOnly = true) + public MissionListResponse getSeasonSpecialMissions(Season season){ + + return MissionListResponse.fromSeasonMission( + seasonMissionRepository.findAllBySeasonAndMissionType(season, MissionType.SPECIAL) + ); + } + @Transactional public MissionResponse createSeasonMission(Season season, Mission mission) { From d72306c36d1129d714b1e714d3c54ebbe417e923 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:32:05 +0900 Subject: [PATCH 02/34] =?UTF-8?q?[SW-128]=20feat(TeamMission=20Entity):=20?= =?UTF-8?q?startedAt=20=ED=95=84=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 --- .../domain/season/_team/_mission_team/entity/TeamMission.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/entity/TeamMission.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/entity/TeamMission.java index 7feb947..68ae838 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/entity/TeamMission.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/entity/TeamMission.java @@ -27,6 +27,10 @@ public class TeamMission extends BaseSchema { @JoinColumn(name = "team_id", nullable = false) Team team; + @Column(nullable = false) + @NotNull + LocalDateTime startedAt; + @Column(nullable = false) @NotNull LocalDateTime endedAt; From fb8ffcdf3c90639082424b65b431cc0864a4f45b Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:34:20 +0900 Subject: [PATCH 03/34] =?UTF-8?q?[SW-128]=20feat(speacial=20request):=20?= =?UTF-8?q?=ED=8A=B9=EB=B3=84=20=EB=AF=B8=EC=85=98=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=EC=9A=A9=20request=20dto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CreateSpecialTeamMissionRequest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java new file mode 100644 index 0000000..1019c89 --- /dev/null +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java @@ -0,0 +1,20 @@ +package com.github.kmu_shell_we.domain.season._team._mission_team.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@Schema(description = "특별 팀 미션 생성 요청") +public class CreateSpecialTeamMissionRequest { + + @NotNull + @Schema(description = "시작 일시") + LocalDateTime startedAt; + + @NotNull + @Schema(description = "종료 일시") + LocalDateTime endedAt; +} From 1684b7a94e606c46208c5823d5f46bf1aa45417c Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:35:48 +0900 Subject: [PATCH 04/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20response):?= =?UTF-8?q?=20=EC=9D=91=EB=8B=B5=20=ED=95=84=EB=93=9C=20startedAt,=20ended?= =?UTF-8?q?At=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/TeamMissionResponse.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionResponse.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionResponse.java index 1a5e79d..caaa53a 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionResponse.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionResponse.java @@ -6,6 +6,7 @@ import lombok.AllArgsConstructor; import lombok.Data; +import java.time.LocalDateTime; import java.util.UUID; @Data @@ -19,11 +20,19 @@ public class TeamMissionResponse { @Schema(description = "팀 미션") MissionResponse mission; + @Schema(description = "시작 일시") + LocalDateTime startedAt; + + @Schema(description = "종료 일시") + LocalDateTime endedAt; + public static TeamMissionResponse from(TeamMission teamMission) { return TeamMissionResponse.of( teamMission.getId(), - MissionResponse.from(teamMission.getMission()) + MissionResponse.from(teamMission.getMission()), + teamMission.getStartedAt(), + teamMission.getEndedAt() ); } } From e4aa4c56750ad4392a8f5cef2e8885fb237ddb9a Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:37:15 +0900 Subject: [PATCH 05/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20exceptions)?= =?UTF-8?q?:=20=ED=8A=B9=EB=B3=84=20=EB=AF=B8=EC=85=98=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=EC=97=90=20=ED=95=84=EC=9A=94=ED=95=9C=20exceptions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_season_mission/exception/SeasonMissionExceptions.java | 1 + .../kmu_shell_we/domain/mission/exception/MissionExceptions.java | 1 + .../_team/_mission_team/exceptions/TeamMissionExceptions.java | 1 + 3 files changed, 3 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/exception/SeasonMissionExceptions.java b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/exception/SeasonMissionExceptions.java index 4690abb..9d4d65d 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/exception/SeasonMissionExceptions.java +++ b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/exception/SeasonMissionExceptions.java @@ -10,6 +10,7 @@ public enum SeasonMissionExceptions implements ApiExceptionCode { NOT_FOUND_SEASON_MISSION("SEASON_MISSION_001", "시즌 미션을 찾을 수 없습니다."), ALREADY_ADDED_SEASON_MISSION("SEASON_MISSION_002", "이미 추가된 시즌 미션입니다."), + INVALID_SEASON_MISSION("SEASON_MISSION_003", "현재 시즌의 미션이 아닙니다."), ; private final String code; diff --git a/src/main/java/com/github/kmu_shell_we/domain/mission/exception/MissionExceptions.java b/src/main/java/com/github/kmu_shell_we/domain/mission/exception/MissionExceptions.java index 76d0dd6..dcb3d66 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/mission/exception/MissionExceptions.java +++ b/src/main/java/com/github/kmu_shell_we/domain/mission/exception/MissionExceptions.java @@ -9,6 +9,7 @@ public enum MissionExceptions implements ApiExceptionCode { NOT_FOUND_MISSION("MISSION_001", "미션을 찾을 수 없습니다."), + INVALID_SPECIAL_MISSION_TYPE("MISSION_002", "SPECIAL 타입이 아닙니다."), ; private final String code; diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/exceptions/TeamMissionExceptions.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/exceptions/TeamMissionExceptions.java index 6961ff7..5283a86 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/exceptions/TeamMissionExceptions.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/exceptions/TeamMissionExceptions.java @@ -9,6 +9,7 @@ public enum TeamMissionExceptions implements ApiExceptionCode { NOT_FOUND_TEAM_MISSION("TEAM_MISSION_001", "해당 팀 미션을 찾을 수 없습니다."), + INVALID_MISSION_TIME("TEAM_MISSION_002", "시작/종료 시각이 올바르지 않습니다."), ; private final String code; From 3e9d4c47bf239f0934e485e69b38343d366ecf50 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:39:18 +0900 Subject: [PATCH 06/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20service):?= =?UTF-8?q?=20startedAt=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80=EC=97=90?= =?UTF-8?q?=20=EB=94=B0=EB=9D=BC=20addRandomMission=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=9D=BC=EB=B6=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../season/_team/_mission_team/service/TeamMissionService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java index 94ead9d..0e52422 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java @@ -80,6 +80,7 @@ private void addRandomMission( List teams = teamRepository.findAllBySeason(season); if (teams.isEmpty()) return; + LocalDateTime startedAt = season.getStartedAt(); LocalDateTime endedAt = endCalculator.apply(now); ThreadLocalRandom random = ThreadLocalRandom.current(); @@ -91,6 +92,7 @@ private void addRandomMission( TeamMission.builder() .mission(randomMission.getMission()) .team(team) + .startedAt(startedAt) .endedAt(endedAt) .build() ); From 58190f627e8a54fda3434dd860dd3c7ab14dbd50 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:41:27 +0900 Subject: [PATCH 07/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20service):?= =?UTF-8?q?=20=EA=B4=80=EB=A6=AC=EC=9E=90=EC=9D=98=20=ED=8A=B9=EB=B3=84=20?= =?UTF-8?q?=EB=AF=B8=EC=85=98=20=EB=B0=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/TeamMissionService.java | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java index 0e52422..d7d1db0 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java @@ -3,16 +3,19 @@ import com.github.kmu_shell_we.domain.mission._season_mission.entity.SeasonMission; import com.github.kmu_shell_we.domain.mission._season_mission.repository.SeasonMissionRepository; import com.github.kmu_shell_we.domain.mission.constant.MissionType; +import com.github.kmu_shell_we.domain.mission.entity.Mission; +import com.github.kmu_shell_we.domain.mission.exception.MissionExceptions; import com.github.kmu_shell_we.domain.season._team._mission_team.dto.response.TeamMissionListResponse; import com.github.kmu_shell_we.domain.season._team._mission_team.entity.TeamMission; +import com.github.kmu_shell_we.domain.season._team._mission_team.exceptions.TeamMissionExceptions; import com.github.kmu_shell_we.domain.season._team._mission_team.repository.TeamMissionRepository; import com.github.kmu_shell_we.domain.season._team.entity.Team; +import com.github.kmu_shell_we.domain.season._team.exception.TeamExceptions; import com.github.kmu_shell_we.domain.season._team.repository.TeamRepository; import com.github.kmu_shell_we.domain.season.entity.Season; import com.github.kmu_shell_we.domain.season.exception.SeasonExceptions; import com.github.kmu_shell_we.domain.season.repository.SeasonRepository; import com.github.kmu_shell_we.domain.user.entity.User; -import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.security.access.prepost.PreAuthorize; @@ -63,6 +66,43 @@ public void assignWeeklyMission() { .atStartOfDay()); } + @Transactional + public List createSpecialMission( + Season season, + Mission mission, + LocalDateTime startedAt, + LocalDateTime endedAt + ) { + + if (startedAt == null || endedAt == null || !endedAt.isAfter(startedAt)) + throw TeamMissionExceptions.INVALID_MISSION_TIME.toException(); + + if (!season.isCurrentSeason()) + throw SeasonExceptions.NOT_FOUND_CURRENT_SEASON.toException(); + + if (mission == null) + throw MissionExceptions.NOT_FOUND_MISSION.toException(); + + if (mission.getType() != MissionType.SPECIAL) + throw MissionExceptions.INVALID_SPECIAL_MISSION_TYPE.toException(); + + List teams = season.getTeams(); + if (teams.isEmpty()) + throw TeamExceptions.NOT_FOUND_TEAM.toException(); + + List teamMissions = new ArrayList<>(); + for (Team team : teams) { + teamMissions.add(TeamMission.builder() + .mission(mission) + .team(team) + .startedAt(startedAt) + .endedAt(endedAt) + .build()); + } + + return teamMissionRepository.saveAll(teamMissions); + } + private void addRandomMission( MissionType missionType, Function endCalculator From b9367c5cd23d7878deb096a418bf1df632eda853 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:41:56 +0900 Subject: [PATCH 08/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20controller)?= =?UTF-8?q?:=20=EA=B4=80=EB=A6=AC=EC=9E=90=EC=9D=98=20=ED=8A=B9=EB=B3=84?= =?UTF-8?q?=20=EB=AF=B8=EC=85=98=20=EB=B0=B0=EC=A0=95,=20=ED=8A=B9?= =?UTF-8?q?=EB=B3=84=20=ED=8C=80=20=EB=AF=B8=EC=85=98=EC=9D=84=20=EB=AA=A8?= =?UTF-8?q?=EB=93=A0=20=ED=8C=80=EC=97=90=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminTeamMissionController.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/controller/AdminTeamMissionController.java diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/controller/AdminTeamMissionController.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/controller/AdminTeamMissionController.java new file mode 100644 index 0000000..da6fd77 --- /dev/null +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/controller/AdminTeamMissionController.java @@ -0,0 +1,47 @@ +package com.github.kmu_shell_we.domain.season._team._mission_team.controller; + +import com.github.kmu_shell_we.domain.mission.entity.Mission; +import com.github.kmu_shell_we.domain.season._team._mission_team.dto.request.CreateSpecialTeamMissionRequest; +import com.github.kmu_shell_we.domain.season._team._mission_team.dto.response.TeamMissionListResponse; +import com.github.kmu_shell_we.domain.season._team._mission_team.entity.TeamMission; +import com.github.kmu_shell_we.domain.season._team._mission_team.service.TeamMissionService; +import com.github.kmu_shell_we.domain.season.entity.Season; +import com.github.kmu_shell_we.global.response.ApiResponse; +import com.github.kmu_shell_we.global.security.guard.AdminGuard; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@AdminGuard +@RestController +@RequestMapping("/admin/seasons/{season}/teams/missions") +@RequiredArgsConstructor +@Tag(name = "[관리자] 팀 미션") +public class AdminTeamMissionController { + + private final TeamMissionService teamMissionService; + + @PostMapping("/{mission}") + @Operation(summary = "특별 팀 미션을 모든 팀에 생성") + public ApiResponse createSpecialMissionToAllTeams( + @Parameter(schema=@Schema(type = "string", format = "uuid")) @PathVariable Season season, + @Parameter(schema=@Schema(type = "string", format = "uuid")) @PathVariable Mission mission, + @RequestBody @Valid CreateSpecialTeamMissionRequest request + ) { + List teamMissions = teamMissionService.createSpecialMission( + season, + mission, + request.getStartedAt(), + request.getEndedAt() + ); + return ApiResponse.ok( + TeamMissionListResponse.from(teamMissions) + ); + } +} From dbc05e06a887cd184244bfcb07ab66040d5cf285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EB=B9=84=EC=84=B1?= Date: Mon, 1 Sep 2025 16:09:46 +0900 Subject: [PATCH 09/34] =?UTF-8?q?[SW-127]=20feat(seasonMission=20Read):=20?= =?UTF-8?q?=ED=8A=B9=EC=A0=95=20=EC=8B=9C=EC=A6=8C=EC=9D=98=20=ED=8A=B9?= =?UTF-8?q?=EB=B3=84=20=EB=AF=B8=EC=85=98=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20(#38)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AdminSeasonMissionController.java | 9 +++++++++ .../service/AdminSeasonMissionService.java | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/controller/AdminSeasonMissionController.java b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/controller/AdminSeasonMissionController.java index b0425af..00ec19e 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/controller/AdminSeasonMissionController.java +++ b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/controller/AdminSeasonMissionController.java @@ -32,6 +32,15 @@ public ApiResponse getSeasonMissions( return ApiResponse.ok(adminSeasonMissionService.getSeasonMissions(season)); } + @GetMapping("/special") + @Operation(summary = "특정 시즌 스페셜 미션 조회") + public ApiResponse getSeasonSpecialMissions( + @Parameter(description = "시즌 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Season season + ) { + + return ApiResponse.ok(adminSeasonMissionService.getSeasonSpecialMissions(season)); + } + @PostMapping("/{mission}") @Operation(summary = "시즌 미션 생성") public ApiResponse createSeasonMission( diff --git a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/service/AdminSeasonMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/service/AdminSeasonMissionService.java index 569538a..7e572e6 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/service/AdminSeasonMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/service/AdminSeasonMissionService.java @@ -3,6 +3,7 @@ import com.github.kmu_shell_we.domain.mission._season_mission.entity.SeasonMission; import com.github.kmu_shell_we.domain.mission._season_mission.exception.SeasonMissionExceptions; import com.github.kmu_shell_we.domain.mission._season_mission.repository.SeasonMissionRepository; +import com.github.kmu_shell_we.domain.mission.constant.MissionType; import com.github.kmu_shell_we.domain.mission.dto.response.MissionListResponse; import com.github.kmu_shell_we.domain.mission.dto.response.MissionResponse; import com.github.kmu_shell_we.domain.mission.entity.Mission; @@ -23,6 +24,14 @@ public MissionListResponse getSeasonMissions(Season season) { return MissionListResponse.fromSeasonMission(seasonMissionRepository.findAllBySeason(season)); } + @Transactional(readOnly = true) + public MissionListResponse getSeasonSpecialMissions(Season season){ + + return MissionListResponse.fromSeasonMission( + seasonMissionRepository.findAllBySeasonAndMissionType(season, MissionType.SPECIAL) + ); + } + @Transactional public MissionResponse createSeasonMission(Season season, Mission mission) { From 49ecb0b7a3f397f38f7b8416d699e5182094a91c Mon Sep 17 00:00:00 2001 From: arirang030 <145207957+arirang030@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:00:27 +0900 Subject: [PATCH 10/34] =?UTF-8?q?[0.6.0]=20SW-120=20URL=20=EB=B3=80?= =?UTF-8?q?=EC=A1=B0=EB=A1=9C=20=EB=8B=A4=EB=A5=B8=20=ED=8C=80=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20=EA=B0=80=EB=8A=A5=20&=20?= =?UTF-8?q?=ED=8C=80=20=EB=AF=B8=EC=85=98=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C?= =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=20=ED=8A=9C=ED=94=8C=20=EC=A1=B4=EC=9E=AC?= =?UTF-8?q?=20=EB=B2=84=EA=B7=B8=20=ED=95=B4=EA=B2=B0=20(#37)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [SW-120] refactor(submission): 자신의 팀의 미션만 제출 및 팀 미션 제출 시 Mission ID가 아닌 TeamMission ID 받기 * [SW-120] refactor(item): 자신의 팀의 아이템만 뽑기 및 조회 가능 * [SW-120] refactor(submission): team이 teamMission을 갖고 있는지 검사 및 각 엔티티에서 List.of를 new ArrayList<>()로 변경 * [SW-120] refactor(submission): 미션 중복 제출 금지 --- .../domain/mission/entity/Mission.java | 4 +- .../_item/controller/ItemController.java | 8 +- .../_team/_item/service/ItemService.java | 25 +++++-- .../repository/SubmissionRepository.java | 16 ---- .../service/SubmissionService.java | 67 ----------------- .../controller/SubmissionController.java | 31 ++++---- .../dto/request/CreateSubmissionRequest.java | 2 +- .../dto/response/SubmissionListResponse.java | 4 +- .../dto/response/SubmissionResponse.java | 6 +- .../_submission}/entity/Submission.java | 4 +- .../repository/SubmissionRepository.java | 17 +++++ .../service/SubmissionService.java | 74 +++++++++++++++++++ .../controller/TeamMissionController.java | 6 +- .../dto/response/TeamMissionListResponse.java | 4 +- .../dto/response/TeamMissionResponse.java | 4 +- .../entity/TeamMission.java | 4 +- .../exceptions/TeamMissionExceptions.java | 3 +- .../repository/TeamMissionRepository.java | 10 +-- .../service/TeamMissionService.java | 13 ++-- .../domain/season/_team/entity/Team.java | 7 +- .../domain/season/entity/Season.java | 9 ++- .../kmu_shell_we/domain/user/entity/User.java | 7 +- 22 files changed, 180 insertions(+), 145 deletions(-) delete mode 100644 src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/repository/SubmissionRepository.java delete mode 100644 src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/service/SubmissionService.java rename src/main/java/com/github/kmu_shell_we/domain/season/_team/{_mission_team/_submission_mission_team => _team_mission/_submission}/controller/SubmissionController.java (57%) rename src/main/java/com/github/kmu_shell_we/domain/season/_team/{_mission_team/_submission_mission_team => _team_mission/_submission}/dto/request/CreateSubmissionRequest.java (74%) rename src/main/java/com/github/kmu_shell_we/domain/season/_team/{_mission_team/_submission_mission_team => _team_mission/_submission}/dto/response/SubmissionListResponse.java (72%) rename src/main/java/com/github/kmu_shell_we/domain/season/_team/{_mission_team/_submission_mission_team => _team_mission/_submission}/dto/response/SubmissionResponse.java (70%) rename src/main/java/com/github/kmu_shell_we/domain/season/_team/{_mission_team/_submission_mission_team => _team_mission/_submission}/entity/Submission.java (79%) create mode 100644 src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/repository/SubmissionRepository.java create mode 100644 src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/service/SubmissionService.java rename src/main/java/com/github/kmu_shell_we/domain/season/_team/{_mission_team => _team_mission}/controller/TeamMissionController.java (88%) rename src/main/java/com/github/kmu_shell_we/domain/season/_team/{_mission_team => _team_mission}/dto/response/TeamMissionListResponse.java (79%) rename src/main/java/com/github/kmu_shell_we/domain/season/_team/{_mission_team => _team_mission}/dto/response/TeamMissionResponse.java (83%) rename src/main/java/com/github/kmu_shell_we/domain/season/_team/{_mission_team => _team_mission}/entity/TeamMission.java (83%) rename src/main/java/com/github/kmu_shell_we/domain/season/_team/{_mission_team => _team_mission}/exceptions/TeamMissionExceptions.java (72%) rename src/main/java/com/github/kmu_shell_we/domain/season/_team/{_mission_team => _team_mission}/repository/TeamMissionRepository.java (66%) rename src/main/java/com/github/kmu_shell_we/domain/season/_team/{_mission_team => _team_mission}/service/TeamMissionService.java (91%) diff --git a/src/main/java/com/github/kmu_shell_we/domain/mission/entity/Mission.java b/src/main/java/com/github/kmu_shell_we/domain/mission/entity/Mission.java index 376623e..c436b2f 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/mission/entity/Mission.java +++ b/src/main/java/com/github/kmu_shell_we/domain/mission/entity/Mission.java @@ -7,6 +7,7 @@ import jakarta.validation.constraints.NotNull; import lombok.*; +import java.util.ArrayList; import java.util.List; @Entity @@ -36,5 +37,6 @@ public class Mission extends BaseSchema { @OneToMany(mappedBy = "mission", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) @Builder.Default - List seasonMissions = List.of(); + @Setter(AccessLevel.NONE) + List seasonMissions = new ArrayList<>(); } diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/controller/ItemController.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/controller/ItemController.java index 41528a3..abb6f52 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/controller/ItemController.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/controller/ItemController.java @@ -5,6 +5,7 @@ import com.github.kmu_shell_we.domain.season._team._item.service.ItemService; import com.github.kmu_shell_we.domain.season._team.entity.Team; import com.github.kmu_shell_we.domain.season.entity.Season; +import com.github.kmu_shell_we.domain.user.entity.User; import com.github.kmu_shell_we.global.response.ApiResponse; import com.github.kmu_shell_we.global.security.guard.MemberGuard; import io.swagger.v3.oas.annotations.Operation; @@ -12,6 +13,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; @MemberGuard @@ -26,18 +28,20 @@ public class ItemController { @GetMapping @Operation(summary = "아이템 조회") public ApiResponse getItems( + @AuthenticationPrincipal User user, @Parameter(description = "시즌 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Season season, @Parameter(description = "팀 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Team team ) { - return ApiResponse.ok(itemService.getItems(season, team)); + return ApiResponse.ok(itemService.getItems(user, season, team)); } @PostMapping("/draw") @Operation(summary = "아이템 뽑기") public ApiResponse drawItem( + @AuthenticationPrincipal User user, @Parameter(description = "시즌 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Season season, @Parameter(description = "팀 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Team team ) { - return ApiResponse.ok(itemService.drawItem(season, team)); + return ApiResponse.ok(itemService.drawItem(user, season, team)); } } diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/service/ItemService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/service/ItemService.java index 037e80e..19b86c9 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/service/ItemService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/service/ItemService.java @@ -12,13 +12,15 @@ import com.github.kmu_shell_we.domain.season._team._item.dto.response.detail.ScoreDeductionResponse; import com.github.kmu_shell_we.domain.season._team._item.entity.Item; import com.github.kmu_shell_we.domain.season._team._item.repository.ItemRepository; -import com.github.kmu_shell_we.domain.season._team._mission_team.entity.TeamMission; -import com.github.kmu_shell_we.domain.season._team._mission_team.exceptions.TeamMissionExceptions; -import com.github.kmu_shell_we.domain.season._team._mission_team.repository.TeamMissionRepository; +import com.github.kmu_shell_we.domain.season._team._team_mission.entity.TeamMission; +import com.github.kmu_shell_we.domain.season._team._team_mission.exceptions.TeamMissionExceptions; +import com.github.kmu_shell_we.domain.season._team._team_mission.repository.TeamMissionRepository; +import com.github.kmu_shell_we.domain.season._team._user_team.repository.UserTeamRepository; import com.github.kmu_shell_we.domain.season._team.entity.Team; import com.github.kmu_shell_we.domain.season._team.exception.TeamExceptions; import com.github.kmu_shell_we.domain.season._team.repository.TeamRepository; import com.github.kmu_shell_we.domain.season.entity.Season; +import com.github.kmu_shell_we.domain.user.entity.User; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; @@ -31,20 +33,22 @@ @RequiredArgsConstructor public class ItemService { - private final ItemRepository itemRepository; private final TeamRepository teamRepository; + private final UserTeamRepository userTeamRepository; + private final ItemRepository itemRepository; private final TeamMissionRepository teamMissionRepository; private final SeasonMissionRepository seasonMissionRepository; @Transactional(readOnly = true) - @PreAuthorize("#season.isCurrentSeason() and #season == #team.season") - public ItemListResponse getItems(Season season, Team team) { + @PreAuthorize("@itemService.canAccessItem(#user, #season, #team)") + public ItemListResponse getItems(User user, Season season, Team team) { return ItemListResponse.from(itemRepository.findAllByTeam(team)); } @Transactional - public ItemResponse drawItem(Season season, Team team) { + @PreAuthorize("@itemService.canAccessItem(#user, #season, #team)") + public ItemResponse drawItem(User user, Season season, Team team) { // 1. 아이템 랜덤 뽑기 ItemType itemType = drawRandomItem(); @@ -101,4 +105,11 @@ private ItemType drawRandomItem() { return ItemType.SCORE_DEDUCTION; } + + public boolean canAccessItem(User user, Season season, Team team) { + + return userTeamRepository.findByUserAndTeam(user, team).isPresent() + && season.isCurrentSeason() + && season.equals(team.getSeason()); + } } diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/repository/SubmissionRepository.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/repository/SubmissionRepository.java deleted file mode 100644 index 47a44da..0000000 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/repository/SubmissionRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.repository; - -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.entity.Submission; -import com.github.kmu_shell_we.domain.season._team._mission_team.entity.TeamMission; - -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.List; -import java.util.UUID; - -public interface SubmissionRepository extends JpaRepository { - - Submission findByTeamMission(TeamMission teamMission); - - List findAllByTeamMissionIn(List teamMissions); -} diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/service/SubmissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/service/SubmissionService.java deleted file mode 100644 index 7b9187e..0000000 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/service/SubmissionService.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.service; - -import com.github.kmu_shell_we.domain.mission.entity.Mission; -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.dto.request.CreateSubmissionRequest; -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.dto.response.SubmissionListResponse; -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.dto.response.SubmissionResponse; -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.entity.Submission; -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.repository.SubmissionRepository; -import com.github.kmu_shell_we.domain.season._team._mission_team.entity.TeamMission; -import com.github.kmu_shell_we.domain.season._team._mission_team.exceptions.TeamMissionExceptions; -import com.github.kmu_shell_we.domain.season._team._mission_team.repository.TeamMissionRepository; -import com.github.kmu_shell_we.domain.season._team.entity.Team; -import com.github.kmu_shell_we.domain.season.entity.Season; -import lombok.RequiredArgsConstructor; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; - -@Service -@RequiredArgsConstructor -public class SubmissionService { - - private final TeamMissionRepository teamMissionRepository; - private final SubmissionRepository submissionRepository; - - @Transactional(readOnly = true) - @PreAuthorize("#season.isCurrentSeason() and #season == #team.season") - public SubmissionListResponse getSubmissions(Season season, Team team) { - - List teamMissions = teamMissionRepository.findAllByTeam(team); - - List submissions = submissionRepository.findAllByTeamMissionIn(teamMissions); - - return SubmissionListResponse.from(submissions); - } - - @Transactional(readOnly = true) - @PreAuthorize("#season.isCurrentSeason() and #season == #team.season") - public SubmissionResponse getSubmission(Season season, Team team, Mission mission) { - - TeamMission teamMission = teamMissionRepository.findByTeamAndMission(team, mission) - .orElseThrow(TeamMissionExceptions.NOT_FOUND_TEAM_MISSION::toException); - - Submission submission = submissionRepository.findByTeamMission(teamMission); - - return SubmissionResponse.from(submission); - } - - @Transactional - @PreAuthorize("#season.isCurrentSeason() and #season == #team.season") - public SubmissionResponse submitSubmission(Season season, Team team, Mission mission, CreateSubmissionRequest request) { - - TeamMission teamMission = teamMissionRepository.findByTeamAndMission(team, mission) - .orElseThrow(TeamMissionExceptions.NOT_FOUND_TEAM_MISSION::toException); - - Submission submission = submissionRepository.save(Submission - .builder() - .teamMission(teamMission) - .image(request.getImage()) - .build() - ); - - return SubmissionResponse.from(submission); - } -} diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/controller/SubmissionController.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/controller/SubmissionController.java similarity index 57% rename from src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/controller/SubmissionController.java rename to src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/controller/SubmissionController.java index 37d282d..e3febf0 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/controller/SubmissionController.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/controller/SubmissionController.java @@ -1,13 +1,14 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.controller; +package com.github.kmu_shell_we.domain.season._team._team_mission._submission.controller; -import com.github.kmu_shell_we.domain.mission.entity.Mission; -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.dto.request.CreateSubmissionRequest; -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.dto.response.SubmissionListResponse; -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.dto.response.SubmissionResponse; -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.service.SubmissionService; +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.dto.request.CreateSubmissionRequest; +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.dto.response.SubmissionListResponse; +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.dto.response.SubmissionResponse; +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.service.SubmissionService; +import com.github.kmu_shell_we.domain.season._team._team_mission.entity.TeamMission; import com.github.kmu_shell_we.domain.season._team.entity.Team; import com.github.kmu_shell_we.domain.season.entity.Season; +import com.github.kmu_shell_we.domain.user.entity.User; import com.github.kmu_shell_we.global.response.ApiResponse; import com.github.kmu_shell_we.global.security.guard.MemberGuard; import io.swagger.v3.oas.annotations.Operation; @@ -16,6 +17,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; @MemberGuard @@ -30,33 +32,36 @@ public class SubmissionController { @GetMapping("/submissions") @Operation(summary = "팀 미션 제출 목록 조회") public ApiResponse getSubmissions( + @AuthenticationPrincipal User user, @Parameter(description = "시즌 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Season season, @Parameter(description = "팀 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Team team ) { - return ApiResponse.ok(submissionService.getSubmissions(season, team)); + return ApiResponse.ok(submissionService.getSubmissions(user, season, team)); } - @GetMapping("/missions/{mission}/submissions") + @GetMapping("/team_mission/{teamMission}/submissions") @Operation(summary = "팀 미션 제출 조회") public ApiResponse getSubmission( + @AuthenticationPrincipal User user, @Parameter(description = "시즌 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Season season, @Parameter(description = "팀 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Team team, - @Parameter(description = "미션 ID", schema = @Schema(type = "string", format = "uuid"))@PathVariable Mission mission + @Parameter(description = "팀 미션 ID", schema = @Schema(type = "string", format = "uuid"))@PathVariable TeamMission teamMission ) { - return ApiResponse.ok(submissionService.getSubmission(season, team, mission)); + return ApiResponse.ok(submissionService.getSubmission(user, season, team, teamMission)); } - @PostMapping("/missions/{mission}/submissions") + @PostMapping("/team_mission/{teamMission}/submissions") @Operation(summary = "팀 미션 제출") public ApiResponse submitMission( + @AuthenticationPrincipal User user, @Parameter(description = "시즌 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Season season, @Parameter(description = "팀 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Team team, - @Parameter(description = "미션 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Mission mission, + @Parameter(description = "팀 미션 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable TeamMission teamMission, @RequestBody @Valid CreateSubmissionRequest request ) { - return ApiResponse.ok(submissionService.submitSubmission(season, team, mission, request)); + return ApiResponse.ok(submissionService.submitSubmission(user, season, team, teamMission, request)); } } \ No newline at end of file diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/dto/request/CreateSubmissionRequest.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/dto/request/CreateSubmissionRequest.java similarity index 74% rename from src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/dto/request/CreateSubmissionRequest.java rename to src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/dto/request/CreateSubmissionRequest.java index d7f365b..ec57cd6 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/dto/request/CreateSubmissionRequest.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/dto/request/CreateSubmissionRequest.java @@ -1,4 +1,4 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.dto.request; +package com.github.kmu_shell_we.domain.season._team._team_mission._submission.dto.request; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/dto/response/SubmissionListResponse.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/dto/response/SubmissionListResponse.java similarity index 72% rename from src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/dto/response/SubmissionListResponse.java rename to src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/dto/response/SubmissionListResponse.java index 29ae7ec..c2fd4e4 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/dto/response/SubmissionListResponse.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/dto/response/SubmissionListResponse.java @@ -1,6 +1,6 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.dto.response; +package com.github.kmu_shell_we.domain.season._team._team_mission._submission.dto.response; -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.entity.Submission; +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.entity.Submission; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/dto/response/SubmissionResponse.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/dto/response/SubmissionResponse.java similarity index 70% rename from src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/dto/response/SubmissionResponse.java rename to src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/dto/response/SubmissionResponse.java index cca1dca..06f7547 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/dto/response/SubmissionResponse.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/dto/response/SubmissionResponse.java @@ -1,7 +1,7 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.dto.response; +package com.github.kmu_shell_we.domain.season._team._team_mission._submission.dto.response; -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.entity.Submission; -import com.github.kmu_shell_we.domain.season._team._mission_team.dto.response.TeamMissionResponse; +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.entity.Submission; +import com.github.kmu_shell_we.domain.season._team._team_mission.dto.response.TeamMissionResponse; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/entity/Submission.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/entity/Submission.java similarity index 79% rename from src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/entity/Submission.java rename to src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/entity/Submission.java index b16c120..40db312 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/_submission_mission_team/entity/Submission.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/entity/Submission.java @@ -1,6 +1,6 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.entity; +package com.github.kmu_shell_we.domain.season._team._team_mission._submission.entity; -import com.github.kmu_shell_we.domain.season._team._mission_team.entity.TeamMission; +import com.github.kmu_shell_we.domain.season._team._team_mission.entity.TeamMission; import com.github.kmu_shell_we.global.infra.mysql.BaseSchema; import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/repository/SubmissionRepository.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/repository/SubmissionRepository.java new file mode 100644 index 0000000..d36f2d5 --- /dev/null +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/repository/SubmissionRepository.java @@ -0,0 +1,17 @@ +package com.github.kmu_shell_we.domain.season._team._team_mission._submission.repository; + +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.entity.Submission; +import com.github.kmu_shell_we.domain.season._team._team_mission.entity.TeamMission; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public interface SubmissionRepository extends JpaRepository { + + Optional findByTeamMission(TeamMission teamMission); + + List findAllByTeamMissionIn(List teamMissions); +} diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/service/SubmissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/service/SubmissionService.java new file mode 100644 index 0000000..42a278d --- /dev/null +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/_submission/service/SubmissionService.java @@ -0,0 +1,74 @@ +package com.github.kmu_shell_we.domain.season._team._team_mission._submission.service; + +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.dto.request.CreateSubmissionRequest; +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.dto.response.SubmissionListResponse; +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.dto.response.SubmissionResponse; +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.entity.Submission; +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.repository.SubmissionRepository; +import com.github.kmu_shell_we.domain.season._team._team_mission.entity.TeamMission; +import com.github.kmu_shell_we.domain.season._team._team_mission.exceptions.TeamMissionExceptions; +import com.github.kmu_shell_we.domain.season._team._team_mission.repository.TeamMissionRepository; +import com.github.kmu_shell_we.domain.season._team._user_team.repository.UserTeamRepository; +import com.github.kmu_shell_we.domain.season._team.entity.Team; +import com.github.kmu_shell_we.domain.season.entity.Season; +import com.github.kmu_shell_we.domain.user.entity.User; +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class SubmissionService { + + private final UserTeamRepository userTeamRepository; + private final TeamMissionRepository teamMissionRepository; + private final SubmissionRepository submissionRepository; + + @Transactional(readOnly = true) + @PreAuthorize("@submissionService.canAccessSubmission(#user, #season, #team)") + public SubmissionListResponse getSubmissions(User user, Season season, Team team) { + + List teamMissions = teamMissionRepository.findAllByTeam(team); + + List submissions = submissionRepository.findAllByTeamMissionIn(teamMissions); + + return SubmissionListResponse.from(submissions); + } + + @Transactional(readOnly = true) + @PreAuthorize("@submissionService.canAccessSubmission(#user, #season, #team) and #teamMission.team == #team") + public SubmissionResponse getSubmission(User user, Season season, Team team, TeamMission teamMission) { + + return submissionRepository.findByTeamMission(teamMission) + .map(SubmissionResponse::from) + .orElse(null); + } + + @Transactional + @PreAuthorize("@submissionService.canAccessSubmission(#user, #season, #team) and #teamMission.team == #team") + public SubmissionResponse submitSubmission(User user, Season season, Team team, TeamMission teamMission, CreateSubmissionRequest request) { + + submissionRepository.findByTeamMission(teamMission).ifPresent(submission -> { + throw TeamMissionExceptions.ALREADY_SUBMITTED.toException(); + }); + + Submission submission = submissionRepository.save( + Submission.builder() + .teamMission(teamMission) + .image(request.getImage()) + .build() + ); + + return SubmissionResponse.from(submission); + } + + public boolean canAccessSubmission(User user, Season season, Team team) { + + return userTeamRepository.findByUserAndTeam(user, team).isPresent() + && season.isCurrentSeason() + && season.equals(team.getSeason()); + } +} diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/controller/TeamMissionController.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/controller/TeamMissionController.java similarity index 88% rename from src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/controller/TeamMissionController.java rename to src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/controller/TeamMissionController.java index 76fedf9..b035781 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/controller/TeamMissionController.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/controller/TeamMissionController.java @@ -1,8 +1,8 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team.controller; +package com.github.kmu_shell_we.domain.season._team._team_mission.controller; -import com.github.kmu_shell_we.domain.season._team._mission_team.dto.response.TeamMissionListResponse; -import com.github.kmu_shell_we.domain.season._team._mission_team.service.TeamMissionService; +import com.github.kmu_shell_we.domain.season._team._team_mission.dto.response.TeamMissionListResponse; +import com.github.kmu_shell_we.domain.season._team._team_mission.service.TeamMissionService; import com.github.kmu_shell_we.domain.season._team.entity.Team; import com.github.kmu_shell_we.domain.season.entity.Season; import com.github.kmu_shell_we.global.response.ApiResponse; diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionListResponse.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/dto/response/TeamMissionListResponse.java similarity index 79% rename from src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionListResponse.java rename to src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/dto/response/TeamMissionListResponse.java index 5324249..9abcb1b 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionListResponse.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/dto/response/TeamMissionListResponse.java @@ -1,6 +1,6 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team.dto.response; +package com.github.kmu_shell_we.domain.season._team._team_mission.dto.response; -import com.github.kmu_shell_we.domain.season._team._mission_team.entity.TeamMission; +import com.github.kmu_shell_we.domain.season._team._team_mission.entity.TeamMission; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionResponse.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/dto/response/TeamMissionResponse.java similarity index 83% rename from src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionResponse.java rename to src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/dto/response/TeamMissionResponse.java index 1a5e79d..626cddb 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionResponse.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/dto/response/TeamMissionResponse.java @@ -1,7 +1,7 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team.dto.response; +package com.github.kmu_shell_we.domain.season._team._team_mission.dto.response; import com.github.kmu_shell_we.domain.mission.dto.response.MissionResponse; -import com.github.kmu_shell_we.domain.season._team._mission_team.entity.TeamMission; +import com.github.kmu_shell_we.domain.season._team._team_mission.entity.TeamMission; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/entity/TeamMission.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/entity/TeamMission.java similarity index 83% rename from src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/entity/TeamMission.java rename to src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/entity/TeamMission.java index 7feb947..b65fd25 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/entity/TeamMission.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/entity/TeamMission.java @@ -1,7 +1,7 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team.entity; +package com.github.kmu_shell_we.domain.season._team._team_mission.entity; import com.github.kmu_shell_we.domain.mission.entity.Mission; -import com.github.kmu_shell_we.domain.season._team._mission_team._submission_mission_team.entity.Submission; +import com.github.kmu_shell_we.domain.season._team._team_mission._submission.entity.Submission; import com.github.kmu_shell_we.domain.season._team.entity.Team; import com.github.kmu_shell_we.global.infra.mysql.BaseSchema; import jakarta.persistence.*; diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/exceptions/TeamMissionExceptions.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/exceptions/TeamMissionExceptions.java similarity index 72% rename from src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/exceptions/TeamMissionExceptions.java rename to src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/exceptions/TeamMissionExceptions.java index 6961ff7..5a37a42 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/exceptions/TeamMissionExceptions.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/exceptions/TeamMissionExceptions.java @@ -1,4 +1,4 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team.exceptions; +package com.github.kmu_shell_we.domain.season._team._team_mission.exceptions; import com.github.kmu_shell_we.global.exception.ApiExceptionCode; import lombok.Getter; @@ -9,6 +9,7 @@ public enum TeamMissionExceptions implements ApiExceptionCode { NOT_FOUND_TEAM_MISSION("TEAM_MISSION_001", "해당 팀 미션을 찾을 수 없습니다."), + ALREADY_SUBMITTED("TEAM_002", "이미 인증한 미션입니다."), ; private final String code; diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/repository/TeamMissionRepository.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/repository/TeamMissionRepository.java similarity index 66% rename from src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/repository/TeamMissionRepository.java rename to src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/repository/TeamMissionRepository.java index fda19d5..524dce6 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/repository/TeamMissionRepository.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/repository/TeamMissionRepository.java @@ -1,10 +1,7 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team.repository; +package com.github.kmu_shell_we.domain.season._team._team_mission.repository; -import com.github.kmu_shell_we.domain.mission.entity.Mission; -import com.github.kmu_shell_we.domain.season._team._mission_team.entity.TeamMission; +import com.github.kmu_shell_we.domain.season._team._team_mission.entity.TeamMission; import com.github.kmu_shell_we.domain.season._team.entity.Team; - -import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -15,9 +12,6 @@ public interface TeamMissionRepository extends JpaRepository { - @EntityGraph(attributePaths = {"team", "mission"}) - Optional findByTeamAndMission(Team team, Mission mission); - List findAllByTeamAndEndedAtGreaterThanEqual(Team team, LocalDateTime now); List findAllByTeam(Team team); diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/service/TeamMissionService.java similarity index 91% rename from src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java rename to src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/service/TeamMissionService.java index 94ead9d..b9f1fbb 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/service/TeamMissionService.java @@ -1,18 +1,17 @@ -package com.github.kmu_shell_we.domain.season._team._mission_team.service; +package com.github.kmu_shell_we.domain.season._team._team_mission.service; import com.github.kmu_shell_we.domain.mission._season_mission.entity.SeasonMission; import com.github.kmu_shell_we.domain.mission._season_mission.repository.SeasonMissionRepository; import com.github.kmu_shell_we.domain.mission.constant.MissionType; -import com.github.kmu_shell_we.domain.season._team._mission_team.dto.response.TeamMissionListResponse; -import com.github.kmu_shell_we.domain.season._team._mission_team.entity.TeamMission; -import com.github.kmu_shell_we.domain.season._team._mission_team.repository.TeamMissionRepository; +import com.github.kmu_shell_we.domain.season._team._team_mission.dto.response.TeamMissionListResponse; +import com.github.kmu_shell_we.domain.season._team._team_mission.entity.TeamMission; +import com.github.kmu_shell_we.domain.season._team._team_mission.repository.TeamMissionRepository; import com.github.kmu_shell_we.domain.season._team.entity.Team; import com.github.kmu_shell_we.domain.season._team.repository.TeamRepository; import com.github.kmu_shell_we.domain.season.entity.Season; import com.github.kmu_shell_we.domain.season.exception.SeasonExceptions; import com.github.kmu_shell_we.domain.season.repository.SeasonRepository; import com.github.kmu_shell_we.domain.user.entity.User; -import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.security.access.prepost.PreAuthorize; @@ -44,6 +43,7 @@ public TeamMissionListResponse getTeamMissions(Season season, Team team) { .findAllByTeamAndEndedAtGreaterThanEqual(team, LocalDateTime.now())); } +// @PostConstruct @Scheduled(cron = "0 0 0 * * ?") @Transactional public void assignDailyMission() { @@ -52,6 +52,7 @@ public void assignDailyMission() { now -> now.toLocalDate().plusDays(1).atStartOfDay()); } +// @PostConstruct @Scheduled(cron = "0 0 0 ? * MON") @Transactional public void assignWeeklyMission() { @@ -78,7 +79,7 @@ private void addRandomMission( if (missions.isEmpty()) return; List teams = teamRepository.findAllBySeason(season); - if (teams.isEmpty()) return; +// if (teams.isEmpty()) return; LocalDateTime endedAt = endCalculator.apply(now); ThreadLocalRandom random = ThreadLocalRandom.current(); diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/entity/Team.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/entity/Team.java index 2f941be..dac6e9b 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/entity/Team.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/entity/Team.java @@ -7,6 +7,7 @@ import jakarta.persistence.*; import lombok.*; +import java.util.ArrayList; import java.util.List; @Entity @@ -35,9 +36,11 @@ public class Team extends BaseSchema { @OneToMany(mappedBy = "team", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) @Builder.Default - List userTeams = List.of(); + @Setter(AccessLevel.NONE) + List userTeams = new ArrayList<>(); @OneToMany(mappedBy = "team", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) @Builder.Default - List items = List.of(); + @Setter(AccessLevel.NONE) + List items = new ArrayList<>(); } diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/entity/Season.java b/src/main/java/com/github/kmu_shell_we/domain/season/entity/Season.java index 8dd261b..3ec6de8 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/entity/Season.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/entity/Season.java @@ -9,6 +9,7 @@ import lombok.experimental.SuperBuilder; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; @Entity @@ -39,11 +40,13 @@ public class Season extends BaseSchema { @OneToMany(mappedBy = "season", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) @Builder.Default - List teams = List.of(); + @Setter(AccessLevel.NONE) + List teams = new ArrayList<>(); @OneToMany(mappedBy = "season", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) @Builder.Default - List missions = List.of(); + @Setter(AccessLevel.NONE) + List seasonMissions = new ArrayList<>(); public boolean isCurrentSeason() { @@ -51,4 +54,4 @@ public boolean isCurrentSeason() { return now.isAfter(startedAt) && now.isBefore(endedAt); } -} \ No newline at end of file +} diff --git a/src/main/java/com/github/kmu_shell_we/domain/user/entity/User.java b/src/main/java/com/github/kmu_shell_we/domain/user/entity/User.java index 0ca314c..6fe6d99 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/user/entity/User.java +++ b/src/main/java/com/github/kmu_shell_we/domain/user/entity/User.java @@ -6,6 +6,7 @@ import jakarta.persistence.*; import lombok.*; +import java.util.ArrayList; import java.util.List; @Entity @@ -35,11 +36,13 @@ public class User extends BaseSchema { @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) @Builder.Default - List userTeams = List.of(); + @Setter(AccessLevel.NONE) + List userTeams = new ArrayList<>(); @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) @Builder.Default - List schedules = List.of(); + @Setter(AccessLevel.NONE) + List schedules = new ArrayList<>(); public enum Role { From 2e46cde3a325470c35ae06aec408a06875479e73 Mon Sep 17 00:00:00 2001 From: arirang030 <145207957+arirang030@users.noreply.github.com> Date: Sat, 6 Sep 2025 00:31:14 +0900 Subject: [PATCH 11/34] =?UTF-8?q?[0.6.0]=20SW-133=20=ED=8C=80=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=ED=91=9C=20=EC=A1=B0=ED=9A=8C=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=20=EB=82=B4=20=EC=9C=A0=EC=A0=80=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EB=94=94=20UUID=EB=A1=9C=20=EB=B0=9B=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_team/_schedule/controller/TeamScheduleController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_schedule/controller/TeamScheduleController.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_schedule/controller/TeamScheduleController.java index 3b90d02..2b0e946 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_schedule/controller/TeamScheduleController.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_schedule/controller/TeamScheduleController.java @@ -9,6 +9,7 @@ import com.github.kmu_shell_we.global.security.guard.MemberGuard; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; @@ -30,7 +31,7 @@ public class TeamScheduleController { public ApiResponse getTeamSchedule( @Parameter(description = "시즌 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Season season, @Parameter(description = "팀 ID", schema = @Schema(type = "string", format = "uuid")) @PathVariable Team team, - @RequestParam List users + @Parameter(description = "유저 ID 목록", array = @ArraySchema(schema = @Schema(type = "string", format = "uuid"))) @RequestParam List users ) { return ApiResponse.ok(scheduleService.getTeamSchedule(season, team, users)); From 44baaf0b7a4f1df8dbb0e9731e55682086452b57 Mon Sep 17 00:00:00 2001 From: arirang030 <145207957+arirang030@users.noreply.github.com> Date: Sat, 6 Sep 2025 19:47:44 +0900 Subject: [PATCH 12/34] =?UTF-8?q?[0.6.0]=20SW-124=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=ED=85=9C=20=EB=BD=91=EA=B8=B0=20=EC=A0=84=20=ED=8F=AC=EC=9D=B8?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=94=EB=9F=89=20=ED=99=95=EC=9D=B8=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20(#41)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [SW-124] refactor(item): 아이템 뽑기 시 포인트 조회 및 차감 * [SW-124] chore(item): 예외 코드 수정 --- .../season/_team/_item/exception/ItemExceptions.java | 1 + .../domain/season/_team/_item/service/ItemService.java | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/exception/ItemExceptions.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/exception/ItemExceptions.java index 6fc7a6b..3712a6b 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/exception/ItemExceptions.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/exception/ItemExceptions.java @@ -9,6 +9,7 @@ public enum ItemExceptions implements ApiExceptionCode { FAILED_TO_DRAW("ITEM_001", "아이템을 뽑는데 실패했습니다."), + NOT_ENOUGH_POINT("ITEM_002", "포인트가 부족합니다."), ; private final String code; diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/service/ItemService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/service/ItemService.java index 19b86c9..9a22b69 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/service/ItemService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_item/service/ItemService.java @@ -11,6 +11,7 @@ import com.github.kmu_shell_we.domain.season._team._item.dto.response.detail.MissionChangeResponse; import com.github.kmu_shell_we.domain.season._team._item.dto.response.detail.ScoreDeductionResponse; import com.github.kmu_shell_we.domain.season._team._item.entity.Item; +import com.github.kmu_shell_we.domain.season._team._item.exception.ItemExceptions; import com.github.kmu_shell_we.domain.season._team._item.repository.ItemRepository; import com.github.kmu_shell_we.domain.season._team._team_mission.entity.TeamMission; import com.github.kmu_shell_we.domain.season._team._team_mission.exceptions.TeamMissionExceptions; @@ -50,6 +51,14 @@ public ItemListResponse getItems(User user, Season season, Team team) { @PreAuthorize("@itemService.canAccessItem(#user, #season, #team)") public ItemResponse drawItem(User user, Season season, Team team) { + // 0. 포인트 조회 및 차감 + if (team.getPoint() < 100) { + + throw ItemExceptions.NOT_ENOUGH_POINT.toException(); + } + + team.setPoint(team.getPoint() - 100); + // 1. 아이템 랜덤 뽑기 ItemType itemType = drawRandomItem(); From 87101eea5bc41e21295aefecd228121ebffecb2e Mon Sep 17 00:00:00 2001 From: BORB Date: Wed, 10 Sep 2025 19:53:27 +0900 Subject: [PATCH 13/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20dto):=20DTO?= =?UTF-8?q?=20=EB=A0=88=EB=B2=A8=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?:=20endedAt=20>=20startedAt=20=EB=B3=B4=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/CreateSpecialTeamMissionRequest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java index 1019c89..b77629f 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java @@ -1,6 +1,7 @@ package com.github.kmu_shell_we.domain.season._team._mission_team.dto.request; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -17,4 +18,9 @@ public class CreateSpecialTeamMissionRequest { @NotNull @Schema(description = "종료 일시") LocalDateTime endedAt; + + @AssertTrue(message = "종료 일시는 시작 일시보다 이후여야 합니다.") + public boolean isValidTimeRange() { + return startedAt != null && endedAt != null && endedAt.isAfter(startedAt); + } } From c74c7cb1010e1d9a55a0ff1e22d2549263814afc Mon Sep 17 00:00:00 2001 From: BORB Date: Wed, 10 Sep 2025 19:54:57 +0900 Subject: [PATCH 14/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20service):?= =?UTF-8?q?=20=EC=8B=9C=EC=A6=8C=20=EB=B2=94=EC=9C=84=20=EB=B2=97=EC=96=B4?= =?UTF-8?q?=EB=82=9C=20=EC=8B=9C=EA=B0=84=20=EC=B0=A8=EB=8B=A8.=20special?= =?UTF-8?q?=20=EB=AF=B8=EC=85=98=20=EC=8B=9C=EA=B0=84=EC=9D=B4=20=EC=8B=9C?= =?UTF-8?q?=EC=A6=8C=20=EB=B0=94=EA=B9=A5=EC=9D=B4=EB=A9=B4=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=ED=95=84=EC=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_mission_team/service/TeamMissionService.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java index d7d1db0..6f92bfd 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java @@ -77,6 +77,14 @@ public List createSpecialMission( if (startedAt == null || endedAt == null || !endedAt.isAfter(startedAt)) throw TeamMissionExceptions.INVALID_MISSION_TIME.toException(); + LocalDateTime seasonStart = season.getStartedAt(); + LocalDateTime seasonEnd = season.getEndedAt(); + if (seasonStart != null && seasonEnd != null) { + if (startedAt.isBefore(seasonStart) || endedAt.isAfter(seasonEnd)) { + throw TeamMissionExceptions.INVALID_MISSION_TIME.toException(); + } + } + if (!season.isCurrentSeason()) throw SeasonExceptions.NOT_FOUND_CURRENT_SEASON.toException(); @@ -99,7 +107,7 @@ public List createSpecialMission( .endedAt(endedAt) .build()); } - + return teamMissionRepository.saveAll(teamMissions); } From a6dc8a900fb994e3b0f646b3315dd0972c896003 Mon Sep 17 00:00:00 2001 From: BORB Date: Wed, 10 Sep 2025 20:15:03 +0900 Subject: [PATCH 15/34] =?UTF-8?q?[SW-128]=20fix(teamMission=20service):=20?= =?UTF-8?q?=EB=AF=B8=EB=9E=98=20=EC=8B=9C=EC=9E=91=20=EB=AF=B8=EC=85=98?= =?UTF-8?q?=EA=B9=8C=EC=A7=80=20=EB=85=B8=EC=B6=9C=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8:=20startedAt=20<=3D=20now=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=B6=94=EA=B0=80=20=ED=95=84=EC=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_team/_mission_team/repository/TeamMissionRepository.java | 4 ++-- .../_team/_mission_team/service/TeamMissionService.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/repository/TeamMissionRepository.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/repository/TeamMissionRepository.java index fda19d5..bb126c5 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/repository/TeamMissionRepository.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/repository/TeamMissionRepository.java @@ -18,10 +18,10 @@ public interface TeamMissionRepository extends JpaRepository @EntityGraph(attributePaths = {"team", "mission"}) Optional findByTeamAndMission(Team team, Mission mission); - List findAllByTeamAndEndedAtGreaterThanEqual(Team team, LocalDateTime now); - List findAllByTeam(Team team); @Query("SELECT tm FROM TeamMission tm WHERE tm.team = :team and tm.endedAt >= :now and tm.submission is null and tm.mission.type = 'DAILY' ORDER BY RAND() LIMIT 1") Optional findCurrentMission(Team team, LocalDateTime now); + + List findAllByTeamAndStartedAtLessThanEqualAndEndedAtGreaterThanEqual(Team team, LocalDateTime now, LocalDateTime now1); } diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java index 6f92bfd..4ea3af9 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java @@ -43,8 +43,9 @@ public class TeamMissionService { @PreAuthorize("#season.isCurrentSeason() and #season == #team.season and @teamMissionService.teamCheck(#team, authentication.principal)") public TeamMissionListResponse getTeamMissions(Season season, Team team) { + LocalDateTime now = LocalDateTime.now(); return TeamMissionListResponse.from(teamMissionRepository - .findAllByTeamAndEndedAtGreaterThanEqual(team, LocalDateTime.now())); + .findAllByTeamAndStartedAtLessThanEqualAndEndedAtGreaterThanEqual(team, now, now)); } @Scheduled(cron = "0 0 0 * * ?") From 8a575b75ab15145b21d583b80e0067825e05230b Mon Sep 17 00:00:00 2001 From: BORB Date: Wed, 10 Sep 2025 20:19:18 +0900 Subject: [PATCH 16/34] =?UTF-8?q?[SW-128]=20refactor(teamMission=20service?= =?UTF-8?q?):=20=EC=8B=9C=EC=A6=8C=20=EA=B2=BD=EA=B3=84=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=EC=9D=B4=20=ED=95=9C=EC=AA=BD=20=EA=B2=BD=EA=B3=84=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=EC=8B=9C=20=EB=AC=B4=EC=8B=9C=20=EB=90=A8?= =?UTF-8?q?=20=E2=80=94=20=EA=B0=81=20=EA=B2=BD=EA=B3=84=EB=A5=BC=20?= =?UTF-8?q?=EB=8F=85=EB=A6=BD=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_team/_mission_team/service/TeamMissionService.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java index 4ea3af9..deeae9c 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java @@ -80,11 +80,10 @@ public List createSpecialMission( LocalDateTime seasonStart = season.getStartedAt(); LocalDateTime seasonEnd = season.getEndedAt(); - if (seasonStart != null && seasonEnd != null) { - if (startedAt.isBefore(seasonStart) || endedAt.isAfter(seasonEnd)) { - throw TeamMissionExceptions.INVALID_MISSION_TIME.toException(); - } - } + if (seasonStart != null && startedAt.isBefore(seasonStart)) + throw TeamMissionExceptions.INVALID_MISSION_TIME.toException(); + if (seasonEnd != null && endedAt.isAfter(seasonEnd)) + throw TeamMissionExceptions.INVALID_MISSION_TIME.toException(); if (!season.isCurrentSeason()) throw SeasonExceptions.NOT_FOUND_CURRENT_SEASON.toException(); From 52483c79b778cf5394d9c2505fa711bf843110fb Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:32:05 +0900 Subject: [PATCH 17/34] =?UTF-8?q?[SW-128]=20feat(TeamMission=20Entity):=20?= =?UTF-8?q?startedAt=20=ED=95=84=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 --- .../domain/season/_team/_mission_team/entity/TeamMission.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/entity/TeamMission.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/entity/TeamMission.java index 7feb947..68ae838 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/entity/TeamMission.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/entity/TeamMission.java @@ -27,6 +27,10 @@ public class TeamMission extends BaseSchema { @JoinColumn(name = "team_id", nullable = false) Team team; + @Column(nullable = false) + @NotNull + LocalDateTime startedAt; + @Column(nullable = false) @NotNull LocalDateTime endedAt; From e0cc8b7a6f289e890d35f998642de66d39ea71d9 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:34:20 +0900 Subject: [PATCH 18/34] =?UTF-8?q?[SW-128]=20feat(speacial=20request):=20?= =?UTF-8?q?=ED=8A=B9=EB=B3=84=20=EB=AF=B8=EC=85=98=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=EC=9A=A9=20request=20dto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CreateSpecialTeamMissionRequest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java new file mode 100644 index 0000000..1019c89 --- /dev/null +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java @@ -0,0 +1,20 @@ +package com.github.kmu_shell_we.domain.season._team._mission_team.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@Schema(description = "특별 팀 미션 생성 요청") +public class CreateSpecialTeamMissionRequest { + + @NotNull + @Schema(description = "시작 일시") + LocalDateTime startedAt; + + @NotNull + @Schema(description = "종료 일시") + LocalDateTime endedAt; +} From 0a8d6859f94834cb05e14ccfeb970872dbeb9d93 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:35:48 +0900 Subject: [PATCH 19/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20response):?= =?UTF-8?q?=20=EC=9D=91=EB=8B=B5=20=ED=95=84=EB=93=9C=20startedAt,=20ended?= =?UTF-8?q?At=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/TeamMissionResponse.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionResponse.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionResponse.java index 1a5e79d..caaa53a 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionResponse.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/response/TeamMissionResponse.java @@ -6,6 +6,7 @@ import lombok.AllArgsConstructor; import lombok.Data; +import java.time.LocalDateTime; import java.util.UUID; @Data @@ -19,11 +20,19 @@ public class TeamMissionResponse { @Schema(description = "팀 미션") MissionResponse mission; + @Schema(description = "시작 일시") + LocalDateTime startedAt; + + @Schema(description = "종료 일시") + LocalDateTime endedAt; + public static TeamMissionResponse from(TeamMission teamMission) { return TeamMissionResponse.of( teamMission.getId(), - MissionResponse.from(teamMission.getMission()) + MissionResponse.from(teamMission.getMission()), + teamMission.getStartedAt(), + teamMission.getEndedAt() ); } } From 6e8be2f86cb577c0b637ca693b0ef7073a954947 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:37:15 +0900 Subject: [PATCH 20/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20exceptions)?= =?UTF-8?q?:=20=ED=8A=B9=EB=B3=84=20=EB=AF=B8=EC=85=98=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=EC=97=90=20=ED=95=84=EC=9A=94=ED=95=9C=20exceptions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_season_mission/exception/SeasonMissionExceptions.java | 1 + .../kmu_shell_we/domain/mission/exception/MissionExceptions.java | 1 + .../_team/_mission_team/exceptions/TeamMissionExceptions.java | 1 + 3 files changed, 3 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/exception/SeasonMissionExceptions.java b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/exception/SeasonMissionExceptions.java index 4690abb..9d4d65d 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/exception/SeasonMissionExceptions.java +++ b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/exception/SeasonMissionExceptions.java @@ -10,6 +10,7 @@ public enum SeasonMissionExceptions implements ApiExceptionCode { NOT_FOUND_SEASON_MISSION("SEASON_MISSION_001", "시즌 미션을 찾을 수 없습니다."), ALREADY_ADDED_SEASON_MISSION("SEASON_MISSION_002", "이미 추가된 시즌 미션입니다."), + INVALID_SEASON_MISSION("SEASON_MISSION_003", "현재 시즌의 미션이 아닙니다."), ; private final String code; diff --git a/src/main/java/com/github/kmu_shell_we/domain/mission/exception/MissionExceptions.java b/src/main/java/com/github/kmu_shell_we/domain/mission/exception/MissionExceptions.java index 76d0dd6..dcb3d66 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/mission/exception/MissionExceptions.java +++ b/src/main/java/com/github/kmu_shell_we/domain/mission/exception/MissionExceptions.java @@ -9,6 +9,7 @@ public enum MissionExceptions implements ApiExceptionCode { NOT_FOUND_MISSION("MISSION_001", "미션을 찾을 수 없습니다."), + INVALID_SPECIAL_MISSION_TYPE("MISSION_002", "SPECIAL 타입이 아닙니다."), ; private final String code; diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/exceptions/TeamMissionExceptions.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/exceptions/TeamMissionExceptions.java index 6961ff7..5283a86 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/exceptions/TeamMissionExceptions.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/exceptions/TeamMissionExceptions.java @@ -9,6 +9,7 @@ public enum TeamMissionExceptions implements ApiExceptionCode { NOT_FOUND_TEAM_MISSION("TEAM_MISSION_001", "해당 팀 미션을 찾을 수 없습니다."), + INVALID_MISSION_TIME("TEAM_MISSION_002", "시작/종료 시각이 올바르지 않습니다."), ; private final String code; From c9479fb29e568c5259f8fa44bf088eb084c54722 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:39:18 +0900 Subject: [PATCH 21/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20service):?= =?UTF-8?q?=20startedAt=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80=EC=97=90?= =?UTF-8?q?=20=EB=94=B0=EB=9D=BC=20addRandomMission=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=9D=BC=EB=B6=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../season/_team/_mission_team/service/TeamMissionService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java index 94ead9d..0e52422 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java @@ -80,6 +80,7 @@ private void addRandomMission( List teams = teamRepository.findAllBySeason(season); if (teams.isEmpty()) return; + LocalDateTime startedAt = season.getStartedAt(); LocalDateTime endedAt = endCalculator.apply(now); ThreadLocalRandom random = ThreadLocalRandom.current(); @@ -91,6 +92,7 @@ private void addRandomMission( TeamMission.builder() .mission(randomMission.getMission()) .team(team) + .startedAt(startedAt) .endedAt(endedAt) .build() ); From abfee04399f905cda7779efb57affa8dcd168e25 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:41:27 +0900 Subject: [PATCH 22/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20service):?= =?UTF-8?q?=20=EA=B4=80=EB=A6=AC=EC=9E=90=EC=9D=98=20=ED=8A=B9=EB=B3=84=20?= =?UTF-8?q?=EB=AF=B8=EC=85=98=20=EB=B0=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/TeamMissionService.java | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java index 0e52422..d7d1db0 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java @@ -3,16 +3,19 @@ import com.github.kmu_shell_we.domain.mission._season_mission.entity.SeasonMission; import com.github.kmu_shell_we.domain.mission._season_mission.repository.SeasonMissionRepository; import com.github.kmu_shell_we.domain.mission.constant.MissionType; +import com.github.kmu_shell_we.domain.mission.entity.Mission; +import com.github.kmu_shell_we.domain.mission.exception.MissionExceptions; import com.github.kmu_shell_we.domain.season._team._mission_team.dto.response.TeamMissionListResponse; import com.github.kmu_shell_we.domain.season._team._mission_team.entity.TeamMission; +import com.github.kmu_shell_we.domain.season._team._mission_team.exceptions.TeamMissionExceptions; import com.github.kmu_shell_we.domain.season._team._mission_team.repository.TeamMissionRepository; import com.github.kmu_shell_we.domain.season._team.entity.Team; +import com.github.kmu_shell_we.domain.season._team.exception.TeamExceptions; import com.github.kmu_shell_we.domain.season._team.repository.TeamRepository; import com.github.kmu_shell_we.domain.season.entity.Season; import com.github.kmu_shell_we.domain.season.exception.SeasonExceptions; import com.github.kmu_shell_we.domain.season.repository.SeasonRepository; import com.github.kmu_shell_we.domain.user.entity.User; -import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.security.access.prepost.PreAuthorize; @@ -63,6 +66,43 @@ public void assignWeeklyMission() { .atStartOfDay()); } + @Transactional + public List createSpecialMission( + Season season, + Mission mission, + LocalDateTime startedAt, + LocalDateTime endedAt + ) { + + if (startedAt == null || endedAt == null || !endedAt.isAfter(startedAt)) + throw TeamMissionExceptions.INVALID_MISSION_TIME.toException(); + + if (!season.isCurrentSeason()) + throw SeasonExceptions.NOT_FOUND_CURRENT_SEASON.toException(); + + if (mission == null) + throw MissionExceptions.NOT_FOUND_MISSION.toException(); + + if (mission.getType() != MissionType.SPECIAL) + throw MissionExceptions.INVALID_SPECIAL_MISSION_TYPE.toException(); + + List teams = season.getTeams(); + if (teams.isEmpty()) + throw TeamExceptions.NOT_FOUND_TEAM.toException(); + + List teamMissions = new ArrayList<>(); + for (Team team : teams) { + teamMissions.add(TeamMission.builder() + .mission(mission) + .team(team) + .startedAt(startedAt) + .endedAt(endedAt) + .build()); + } + + return teamMissionRepository.saveAll(teamMissions); + } + private void addRandomMission( MissionType missionType, Function endCalculator From 16b5c72b718e26b362ebfe83985945f5f1acbd7b Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:41:56 +0900 Subject: [PATCH 23/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20controller)?= =?UTF-8?q?:=20=EA=B4=80=EB=A6=AC=EC=9E=90=EC=9D=98=20=ED=8A=B9=EB=B3=84?= =?UTF-8?q?=20=EB=AF=B8=EC=85=98=20=EB=B0=B0=EC=A0=95,=20=ED=8A=B9?= =?UTF-8?q?=EB=B3=84=20=ED=8C=80=20=EB=AF=B8=EC=85=98=EC=9D=84=20=EB=AA=A8?= =?UTF-8?q?=EB=93=A0=20=ED=8C=80=EC=97=90=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminTeamMissionController.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/controller/AdminTeamMissionController.java diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/controller/AdminTeamMissionController.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/controller/AdminTeamMissionController.java new file mode 100644 index 0000000..da6fd77 --- /dev/null +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/controller/AdminTeamMissionController.java @@ -0,0 +1,47 @@ +package com.github.kmu_shell_we.domain.season._team._mission_team.controller; + +import com.github.kmu_shell_we.domain.mission.entity.Mission; +import com.github.kmu_shell_we.domain.season._team._mission_team.dto.request.CreateSpecialTeamMissionRequest; +import com.github.kmu_shell_we.domain.season._team._mission_team.dto.response.TeamMissionListResponse; +import com.github.kmu_shell_we.domain.season._team._mission_team.entity.TeamMission; +import com.github.kmu_shell_we.domain.season._team._mission_team.service.TeamMissionService; +import com.github.kmu_shell_we.domain.season.entity.Season; +import com.github.kmu_shell_we.global.response.ApiResponse; +import com.github.kmu_shell_we.global.security.guard.AdminGuard; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@AdminGuard +@RestController +@RequestMapping("/admin/seasons/{season}/teams/missions") +@RequiredArgsConstructor +@Tag(name = "[관리자] 팀 미션") +public class AdminTeamMissionController { + + private final TeamMissionService teamMissionService; + + @PostMapping("/{mission}") + @Operation(summary = "특별 팀 미션을 모든 팀에 생성") + public ApiResponse createSpecialMissionToAllTeams( + @Parameter(schema=@Schema(type = "string", format = "uuid")) @PathVariable Season season, + @Parameter(schema=@Schema(type = "string", format = "uuid")) @PathVariable Mission mission, + @RequestBody @Valid CreateSpecialTeamMissionRequest request + ) { + List teamMissions = teamMissionService.createSpecialMission( + season, + mission, + request.getStartedAt(), + request.getEndedAt() + ); + return ApiResponse.ok( + TeamMissionListResponse.from(teamMissions) + ); + } +} From ae7a8aa9c696d363df33abb6bdc1e8b6a3810630 Mon Sep 17 00:00:00 2001 From: BORB Date: Wed, 10 Sep 2025 19:53:27 +0900 Subject: [PATCH 24/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20dto):=20DTO?= =?UTF-8?q?=20=EB=A0=88=EB=B2=A8=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?:=20endedAt=20>=20startedAt=20=EB=B3=B4=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/CreateSpecialTeamMissionRequest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java index 1019c89..b77629f 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java @@ -1,6 +1,7 @@ package com.github.kmu_shell_we.domain.season._team._mission_team.dto.request; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -17,4 +18,9 @@ public class CreateSpecialTeamMissionRequest { @NotNull @Schema(description = "종료 일시") LocalDateTime endedAt; + + @AssertTrue(message = "종료 일시는 시작 일시보다 이후여야 합니다.") + public boolean isValidTimeRange() { + return startedAt != null && endedAt != null && endedAt.isAfter(startedAt); + } } From 825b1d31989c28e116abb30df1a929bf2de6834e Mon Sep 17 00:00:00 2001 From: BORB Date: Wed, 10 Sep 2025 19:54:57 +0900 Subject: [PATCH 25/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20service):?= =?UTF-8?q?=20=EC=8B=9C=EC=A6=8C=20=EB=B2=94=EC=9C=84=20=EB=B2=97=EC=96=B4?= =?UTF-8?q?=EB=82=9C=20=EC=8B=9C=EA=B0=84=20=EC=B0=A8=EB=8B=A8.=20special?= =?UTF-8?q?=20=EB=AF=B8=EC=85=98=20=EC=8B=9C=EA=B0=84=EC=9D=B4=20=EC=8B=9C?= =?UTF-8?q?=EC=A6=8C=20=EB=B0=94=EA=B9=A5=EC=9D=B4=EB=A9=B4=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=ED=95=84=EC=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_mission_team/service/TeamMissionService.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java index d7d1db0..6f92bfd 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java @@ -77,6 +77,14 @@ public List createSpecialMission( if (startedAt == null || endedAt == null || !endedAt.isAfter(startedAt)) throw TeamMissionExceptions.INVALID_MISSION_TIME.toException(); + LocalDateTime seasonStart = season.getStartedAt(); + LocalDateTime seasonEnd = season.getEndedAt(); + if (seasonStart != null && seasonEnd != null) { + if (startedAt.isBefore(seasonStart) || endedAt.isAfter(seasonEnd)) { + throw TeamMissionExceptions.INVALID_MISSION_TIME.toException(); + } + } + if (!season.isCurrentSeason()) throw SeasonExceptions.NOT_FOUND_CURRENT_SEASON.toException(); @@ -99,7 +107,7 @@ public List createSpecialMission( .endedAt(endedAt) .build()); } - + return teamMissionRepository.saveAll(teamMissions); } From f00f7fd9a88f1b4b37f66451a57a7f46e4238cab Mon Sep 17 00:00:00 2001 From: BORB Date: Wed, 10 Sep 2025 20:15:03 +0900 Subject: [PATCH 26/34] =?UTF-8?q?[SW-128]=20fix(teamMission=20service):=20?= =?UTF-8?q?=EB=AF=B8=EB=9E=98=20=EC=8B=9C=EC=9E=91=20=EB=AF=B8=EC=85=98?= =?UTF-8?q?=EA=B9=8C=EC=A7=80=20=EB=85=B8=EC=B6=9C=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8:=20startedAt=20<=3D=20now=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=B6=94=EA=B0=80=20=ED=95=84=EC=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_team/_mission_team/repository/TeamMissionRepository.java | 4 ++-- .../_team/_mission_team/service/TeamMissionService.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/repository/TeamMissionRepository.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/repository/TeamMissionRepository.java index fda19d5..bb126c5 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/repository/TeamMissionRepository.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/repository/TeamMissionRepository.java @@ -18,10 +18,10 @@ public interface TeamMissionRepository extends JpaRepository @EntityGraph(attributePaths = {"team", "mission"}) Optional findByTeamAndMission(Team team, Mission mission); - List findAllByTeamAndEndedAtGreaterThanEqual(Team team, LocalDateTime now); - List findAllByTeam(Team team); @Query("SELECT tm FROM TeamMission tm WHERE tm.team = :team and tm.endedAt >= :now and tm.submission is null and tm.mission.type = 'DAILY' ORDER BY RAND() LIMIT 1") Optional findCurrentMission(Team team, LocalDateTime now); + + List findAllByTeamAndStartedAtLessThanEqualAndEndedAtGreaterThanEqual(Team team, LocalDateTime now, LocalDateTime now1); } diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java index 6f92bfd..4ea3af9 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java @@ -43,8 +43,9 @@ public class TeamMissionService { @PreAuthorize("#season.isCurrentSeason() and #season == #team.season and @teamMissionService.teamCheck(#team, authentication.principal)") public TeamMissionListResponse getTeamMissions(Season season, Team team) { + LocalDateTime now = LocalDateTime.now(); return TeamMissionListResponse.from(teamMissionRepository - .findAllByTeamAndEndedAtGreaterThanEqual(team, LocalDateTime.now())); + .findAllByTeamAndStartedAtLessThanEqualAndEndedAtGreaterThanEqual(team, now, now)); } @Scheduled(cron = "0 0 0 * * ?") From a63a3ac8e55ca8a12b563bd51e7b03d07628ec8d Mon Sep 17 00:00:00 2001 From: BORB Date: Wed, 10 Sep 2025 20:19:18 +0900 Subject: [PATCH 27/34] =?UTF-8?q?[SW-128]=20refactor(teamMission=20service?= =?UTF-8?q?):=20=EC=8B=9C=EC=A6=8C=20=EA=B2=BD=EA=B3=84=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=EC=9D=B4=20=ED=95=9C=EC=AA=BD=20=EA=B2=BD=EA=B3=84=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=EC=8B=9C=20=EB=AC=B4=EC=8B=9C=20=EB=90=A8?= =?UTF-8?q?=20=E2=80=94=20=EA=B0=81=20=EA=B2=BD=EA=B3=84=EB=A5=BC=20?= =?UTF-8?q?=EB=8F=85=EB=A6=BD=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_team/_mission_team/service/TeamMissionService.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java index 4ea3af9..deeae9c 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/service/TeamMissionService.java @@ -80,11 +80,10 @@ public List createSpecialMission( LocalDateTime seasonStart = season.getStartedAt(); LocalDateTime seasonEnd = season.getEndedAt(); - if (seasonStart != null && seasonEnd != null) { - if (startedAt.isBefore(seasonStart) || endedAt.isAfter(seasonEnd)) { - throw TeamMissionExceptions.INVALID_MISSION_TIME.toException(); - } - } + if (seasonStart != null && startedAt.isBefore(seasonStart)) + throw TeamMissionExceptions.INVALID_MISSION_TIME.toException(); + if (seasonEnd != null && endedAt.isAfter(seasonEnd)) + throw TeamMissionExceptions.INVALID_MISSION_TIME.toException(); if (!season.isCurrentSeason()) throw SeasonExceptions.NOT_FOUND_CURRENT_SEASON.toException(); From f47ef188efc5b1a725065ace4ca108872bc96329 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:32:05 +0900 Subject: [PATCH 28/34] =?UTF-8?q?[SW-128]=20feat(TeamMission=20Entity):=20?= =?UTF-8?q?startedAt=20=ED=95=84=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 --- .../domain/season/_team/_team_mission/entity/TeamMission.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/entity/TeamMission.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/entity/TeamMission.java index b65fd25..5006a04 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/entity/TeamMission.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/entity/TeamMission.java @@ -27,6 +27,10 @@ public class TeamMission extends BaseSchema { @JoinColumn(name = "team_id", nullable = false) Team team; + @Column(nullable = false) + @NotNull + LocalDateTime startedAt; + @Column(nullable = false) @NotNull LocalDateTime endedAt; From cfc1ad1f7e3980b9a317013becc06f2829852b50 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:34:20 +0900 Subject: [PATCH 29/34] =?UTF-8?q?[SW-128]=20feat(speacial=20request):=20?= =?UTF-8?q?=ED=8A=B9=EB=B3=84=20=EB=AF=B8=EC=85=98=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=EC=9A=A9=20request=20dto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CreateSpecialTeamMissionRequest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java new file mode 100644 index 0000000..1019c89 --- /dev/null +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java @@ -0,0 +1,20 @@ +package com.github.kmu_shell_we.domain.season._team._mission_team.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@Schema(description = "특별 팀 미션 생성 요청") +public class CreateSpecialTeamMissionRequest { + + @NotNull + @Schema(description = "시작 일시") + LocalDateTime startedAt; + + @NotNull + @Schema(description = "종료 일시") + LocalDateTime endedAt; +} From a5453d71e9a455309da468e922d675c5f3e3a6e2 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:35:48 +0900 Subject: [PATCH 30/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20response):?= =?UTF-8?q?=20=EC=9D=91=EB=8B=B5=20=ED=95=84=EB=93=9C=20startedAt,=20ended?= =?UTF-8?q?At=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/TeamMissionResponse.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/dto/response/TeamMissionResponse.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/dto/response/TeamMissionResponse.java index 626cddb..e50fa09 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/dto/response/TeamMissionResponse.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/dto/response/TeamMissionResponse.java @@ -6,6 +6,7 @@ import lombok.AllArgsConstructor; import lombok.Data; +import java.time.LocalDateTime; import java.util.UUID; @Data @@ -19,11 +20,19 @@ public class TeamMissionResponse { @Schema(description = "팀 미션") MissionResponse mission; + @Schema(description = "시작 일시") + LocalDateTime startedAt; + + @Schema(description = "종료 일시") + LocalDateTime endedAt; + public static TeamMissionResponse from(TeamMission teamMission) { return TeamMissionResponse.of( teamMission.getId(), - MissionResponse.from(teamMission.getMission()) + MissionResponse.from(teamMission.getMission()), + teamMission.getStartedAt(), + teamMission.getEndedAt() ); } } From 7155ed772a664101a81d975af704b7dbaa36a74d Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:37:15 +0900 Subject: [PATCH 31/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20exceptions)?= =?UTF-8?q?:=20=ED=8A=B9=EB=B3=84=20=EB=AF=B8=EC=85=98=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=EC=97=90=20=ED=95=84=EC=9A=94=ED=95=9C=20exceptions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_season_mission/exception/SeasonMissionExceptions.java | 1 + .../kmu_shell_we/domain/mission/exception/MissionExceptions.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/exception/SeasonMissionExceptions.java b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/exception/SeasonMissionExceptions.java index 4690abb..9d4d65d 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/exception/SeasonMissionExceptions.java +++ b/src/main/java/com/github/kmu_shell_we/domain/mission/_season_mission/exception/SeasonMissionExceptions.java @@ -10,6 +10,7 @@ public enum SeasonMissionExceptions implements ApiExceptionCode { NOT_FOUND_SEASON_MISSION("SEASON_MISSION_001", "시즌 미션을 찾을 수 없습니다."), ALREADY_ADDED_SEASON_MISSION("SEASON_MISSION_002", "이미 추가된 시즌 미션입니다."), + INVALID_SEASON_MISSION("SEASON_MISSION_003", "현재 시즌의 미션이 아닙니다."), ; private final String code; diff --git a/src/main/java/com/github/kmu_shell_we/domain/mission/exception/MissionExceptions.java b/src/main/java/com/github/kmu_shell_we/domain/mission/exception/MissionExceptions.java index 76d0dd6..dcb3d66 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/mission/exception/MissionExceptions.java +++ b/src/main/java/com/github/kmu_shell_we/domain/mission/exception/MissionExceptions.java @@ -9,6 +9,7 @@ public enum MissionExceptions implements ApiExceptionCode { NOT_FOUND_MISSION("MISSION_001", "미션을 찾을 수 없습니다."), + INVALID_SPECIAL_MISSION_TYPE("MISSION_002", "SPECIAL 타입이 아닙니다."), ; private final String code; From 92363bc7073691dbb50c9cb0f53eeb097c565b60 Mon Sep 17 00:00:00 2001 From: BORB Date: Thu, 28 Aug 2025 23:39:18 +0900 Subject: [PATCH 32/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20service):?= =?UTF-8?q?=20startedAt=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80=EC=97=90?= =?UTF-8?q?=20=EB=94=B0=EB=9D=BC=20addRandomMission=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=9D=BC=EB=B6=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../season/_team/_team_mission/service/TeamMissionService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/service/TeamMissionService.java index b9f1fbb..473ebfb 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/service/TeamMissionService.java @@ -81,6 +81,7 @@ private void addRandomMission( List teams = teamRepository.findAllBySeason(season); // if (teams.isEmpty()) return; + LocalDateTime startedAt = season.getStartedAt(); LocalDateTime endedAt = endCalculator.apply(now); ThreadLocalRandom random = ThreadLocalRandom.current(); @@ -92,6 +93,7 @@ private void addRandomMission( TeamMission.builder() .mission(randomMission.getMission()) .team(team) + .startedAt(startedAt) .endedAt(endedAt) .build() ); From fbda45fe11db361dfcae9ff44fe083b0c7c05256 Mon Sep 17 00:00:00 2001 From: BORB Date: Wed, 10 Sep 2025 19:53:27 +0900 Subject: [PATCH 33/34] =?UTF-8?q?[SW-128]=20feat(teamMission=20dto):=20DTO?= =?UTF-8?q?=20=EB=A0=88=EB=B2=A8=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?:=20endedAt=20>=20startedAt=20=EB=B3=B4=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/CreateSpecialTeamMissionRequest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java index 1019c89..b77629f 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java @@ -1,6 +1,7 @@ package com.github.kmu_shell_we.domain.season._team._mission_team.dto.request; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -17,4 +18,9 @@ public class CreateSpecialTeamMissionRequest { @NotNull @Schema(description = "종료 일시") LocalDateTime endedAt; + + @AssertTrue(message = "종료 일시는 시작 일시보다 이후여야 합니다.") + public boolean isValidTimeRange() { + return startedAt != null && endedAt != null && endedAt.isAfter(startedAt); + } } From 7e17a29922599dfecf289b627e5b9aeafcabf2be Mon Sep 17 00:00:00 2001 From: BORB Date: Wed, 10 Sep 2025 20:15:03 +0900 Subject: [PATCH 34/34] =?UTF-8?q?[SW-128]=20fix(teamMission=20service):=20?= =?UTF-8?q?=EB=AF=B8=EB=9E=98=20=EC=8B=9C=EC=9E=91=20=EB=AF=B8=EC=85=98?= =?UTF-8?q?=EA=B9=8C=EC=A7=80=20=EB=85=B8=EC=B6=9C=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8:=20startedAt=20<=3D=20now=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=B6=94=EA=B0=80=20=ED=95=84=EC=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../season/_team/_team_mission/service/TeamMissionService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/service/TeamMissionService.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/service/TeamMissionService.java index 473ebfb..9b08e84 100644 --- a/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/service/TeamMissionService.java +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/service/TeamMissionService.java @@ -39,8 +39,9 @@ public class TeamMissionService { @PreAuthorize("#season.isCurrentSeason() and #season == #team.season and @teamMissionService.teamCheck(#team, authentication.principal)") public TeamMissionListResponse getTeamMissions(Season season, Team team) { + LocalDateTime now = LocalDateTime.now(); return TeamMissionListResponse.from(teamMissionRepository - .findAllByTeamAndEndedAtGreaterThanEqual(team, LocalDateTime.now())); + .findAllByTeamAndStartedAtLessThanEqualAndEndedAtGreaterThanEqual(team, now, now)); } // @PostConstruct