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/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/_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) { 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/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/_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/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 037e80e..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,14 +11,17 @@ 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._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 +34,30 @@ @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) { + + // 0. 포인트 조회 및 차감 + if (team.getPoint() < 100) { + + throw ItemExceptions.NOT_ENOUGH_POINT.toException(); + } + + team.setPoint(team.getPoint() - 100); // 1. 아이템 랜덤 뽑기 ItemType itemType = drawRandomItem(); @@ -101,4 +114,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/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..b77629f --- /dev/null +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_mission_team/dto/request/CreateSpecialTeamMissionRequest.java @@ -0,0 +1,26 @@ +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; + +import java.time.LocalDateTime; + +@Data +@Schema(description = "특별 팀 미션 생성 요청") +public class CreateSpecialTeamMissionRequest { + + @NotNull + @Schema(description = "시작 일시") + LocalDateTime startedAt; + + @NotNull + @Schema(description = "종료 일시") + LocalDateTime endedAt; + + @AssertTrue(message = "종료 일시는 시작 일시보다 이후여야 합니다.") + public boolean isValidTimeRange() { + return startedAt != null && endedAt != null && endedAt.isAfter(startedAt); + } +} 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)); 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/_team_mission/controller/AdminTeamMissionController.java b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/controller/AdminTeamMissionController.java new file mode 100644 index 0000000..da6fd77 --- /dev/null +++ b/src/main/java/com/github/kmu_shell_we/domain/season/_team/_team_mission/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) + ); + } +} 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 57% 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..e50fa09 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,11 +1,12 @@ -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; +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() ); } } 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 79% 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..5006a04 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.*; @@ -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; 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 82% 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..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/_team_mission/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; 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 88% 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..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/_team_mission/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/_team_mission/service/TeamMissionService.java similarity index 65% 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..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/_team_mission/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; @@ -40,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 * * ?") @@ -63,6 +67,50 @@ 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(); + + LocalDateTime seasonStart = season.getStartedAt(); + LocalDateTime seasonEnd = season.getEndedAt(); + 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(); + + 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 @@ -80,6 +128,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 +140,7 @@ private void addRandomMission( TeamMission.builder() .mission(randomMission.getMission()) .team(team) + .startedAt(startedAt) .endedAt(endedAt) .build() ); 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 {