diff --git a/src/main/java/org/sopt/app/application/appjamuser/AppjamUserInfo.java b/src/main/java/org/sopt/app/application/appjamuser/AppjamUserInfo.java index afd69f57..43fa5baa 100644 --- a/src/main/java/org/sopt/app/application/appjamuser/AppjamUserInfo.java +++ b/src/main/java/org/sopt/app/application/appjamuser/AppjamUserInfo.java @@ -20,10 +20,39 @@ public static class TeamSummary { private String teamName; public static TeamSummary from(AppjamUser appjamUser) { - return TeamSummary.builder(). - teamNumber(appjamUser.getTeamNumber()) + return TeamSummary.builder() + .teamNumber(appjamUser.getTeamNumber()) .teamName(appjamUser.getTeamName()) .build(); } + + public static TeamSummary empty() { + return TeamSummary.builder() + .build(); + } + } + + @Getter + @Builder + @ToString + public static class AppjamUserStatus { + + private TeamNumber teamNumber; + private String teamName; + private boolean isAppjamJoined; + + public static AppjamUserStatus appjamJoined(AppjamUser appjamUser) { + return AppjamUserStatus.builder() + .teamNumber(appjamUser.getTeamNumber()) + .teamName(appjamUser.getTeamName()) + .isAppjamJoined(true) + .build(); + } + + public static AppjamUserStatus appjamNotJoined() { + return AppjamUserStatus.builder() + .isAppjamJoined(false) + .build(); + } } } diff --git a/src/main/java/org/sopt/app/application/appjamuser/AppjamUserService.java b/src/main/java/org/sopt/app/application/appjamuser/AppjamUserService.java index 1e316f7c..6ab8f823 100644 --- a/src/main/java/org/sopt/app/application/appjamuser/AppjamUserService.java +++ b/src/main/java/org/sopt/app/application/appjamuser/AppjamUserService.java @@ -1,10 +1,11 @@ package org.sopt.app.application.appjamuser; import lombok.RequiredArgsConstructor; +import lombok.val; +import org.sopt.app.application.appjamuser.AppjamUserInfo.AppjamUserStatus; import org.sopt.app.application.appjamuser.AppjamUserInfo.TeamSummary; import org.sopt.app.common.exception.NotFoundException; import org.sopt.app.common.response.ErrorCode; -import org.sopt.app.domain.entity.AppjamUser; import org.sopt.app.domain.enums.TeamNumber; import org.sopt.app.interfaces.postgres.AppjamUserRepository; import org.springframework.stereotype.Service; @@ -15,14 +16,20 @@ public class AppjamUserService { private final AppjamUserRepository appjamUserRepository; + public AppjamUserStatus getAppjamUserStatus(Long userId) { + return appjamUserRepository.findByUserId(userId) + .map(AppjamUserStatus::appjamJoined) + .orElseGet(AppjamUserStatus::appjamNotJoined); + } + public TeamSummary getTeamSummaryByTeamNumber(TeamNumber teamNumber) { - AppjamUser appjamUser = appjamUserRepository.findTopByTeamNumberOrderById(teamNumber) + val appjamUser = appjamUserRepository.findTopByTeamNumberOrderById(teamNumber) .orElseThrow(() -> new NotFoundException(ErrorCode.TEAM_NOT_FOUND)); return TeamSummary.from(appjamUser); } public TeamSummary getTeamSummaryByUserId(Long userId) { - AppjamUser appjamUser = appjamUserRepository.findByUserId(userId) + val appjamUser = appjamUserRepository.findByUserId(userId) .orElseThrow(() -> new NotFoundException(ErrorCode.TEAM_NOT_FOUND)); return TeamSummary.from(appjamUser); } diff --git a/src/main/java/org/sopt/app/application/mission/AppjamMissionService.java b/src/main/java/org/sopt/app/application/mission/AppjamMissionService.java index 5eb403f3..29f296ee 100644 --- a/src/main/java/org/sopt/app/application/mission/AppjamMissionService.java +++ b/src/main/java/org/sopt/app/application/mission/AppjamMissionService.java @@ -30,8 +30,14 @@ public class AppjamMissionService { private final StampRepository stampRepository; private final SoptampUserRepository soptampUserRepository; + public List getDisplayedMissions() { + val displayedMissions = missionRepository.findAllByDisplay(true); + return displayedMissions.stream() + .map(AppjamMissionInfo::createWhenUncompleted) + .toList(); + } - public List getAllMissions(TeamNumber teamNumber) { + public List getMissionsByTeam(TeamNumber teamNumber) { val userIds = getTeamUserIds(teamNumber); val stampsByMissionId = getStampMapByUserIds(userIds); val soptampUserByUserId = getSoptampUserMapByUserIds(userIds); @@ -42,9 +48,9 @@ public List getAllMissions(TeamNumber teamNumber) { .toList(); } - public List getMissionsByCondition(TeamNumber teamNumber, + public List getMissionsByTeamAndCondition(TeamNumber teamNumber, boolean isCompleted) { - List allMissions = getAllMissions(teamNumber); + List allMissions = getMissionsByTeam(teamNumber); return allMissions.stream() .filter(mission -> Objects.equals(mission.isCompleted(), isCompleted)) diff --git a/src/main/java/org/sopt/app/application/mission/MissionInfo.java b/src/main/java/org/sopt/app/application/mission/MissionInfo.java index d2cd0271..0e8e8c12 100755 --- a/src/main/java/org/sopt/app/application/mission/MissionInfo.java +++ b/src/main/java/org/sopt/app/application/mission/MissionInfo.java @@ -6,6 +6,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; +import org.sopt.app.application.appjamuser.AppjamUserInfo.AppjamUserStatus; import org.sopt.app.application.appjamuser.AppjamUserInfo.TeamSummary; import org.sopt.app.domain.entity.soptamp.Mission; import org.sopt.app.domain.enums.TeamNumber; @@ -63,6 +64,16 @@ public static AppjamMissionInfo of( .isCompleted(isCompleted) .build(); } + + public static AppjamMissionInfo createWhenUncompleted(Mission mission) { + return AppjamMissionInfo.builder() + .id(mission.getId()) + .title(mission.getTitle()) + .level(mission.getLevel()) + .profileImage(mission.getProfileImage()) + .isCompleted(false) + .build(); + } } @Getter @@ -70,15 +81,20 @@ public static AppjamMissionInfo of( @ToString public static class AppjamMissionInfos { + private TeamNumber myTeamNumber; + private boolean isAppjamJoined; private TeamNumber teamNumber; private String teamName; private List missions; public static AppjamMissionInfos of( + AppjamUserStatus appjamUserStatus, TeamSummary teamSummary, List missions ) { return AppjamMissionInfos.builder() + .myTeamNumber(appjamUserStatus.getTeamNumber()) + .isAppjamJoined(appjamUserStatus.isAppjamJoined()) .teamNumber(teamSummary.getTeamNumber()) .teamName(teamSummary.getTeamName()) .missions(missions) diff --git a/src/main/java/org/sopt/app/application/stamp/AppjamStampService.java b/src/main/java/org/sopt/app/application/stamp/AppjamStampService.java new file mode 100644 index 00000000..981352f6 --- /dev/null +++ b/src/main/java/org/sopt/app/application/stamp/AppjamStampService.java @@ -0,0 +1,41 @@ +package org.sopt.app.application.stamp; + +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.sopt.app.common.exception.BadRequestException; +import org.sopt.app.common.response.ErrorCode; +import org.sopt.app.domain.entity.AppjamUser; +import org.sopt.app.domain.enums.TeamNumber; +import org.sopt.app.interfaces.postgres.AppjamUserRepository; +import org.sopt.app.interfaces.postgres.StampRepository; +import org.sopt.app.presentation.appjamtamp.AppjamtampRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class AppjamStampService { + + private final AppjamUserRepository appjamUserRepository; + private final StampRepository stampRepository; + + @Transactional(readOnly = true) + public void checkDuplicateStamp(TeamNumber teamNumber, Long missionId) { + val appjamUsers = appjamUserRepository.findAllByTeamNumber(teamNumber); + val isDuplicated = stampRepository.existsByUserIdInAndMissionId( + appjamUsers.stream().map(AppjamUser::getUserId).toList(), missionId); + if (isDuplicated) { + throw new BadRequestException(ErrorCode.DUPLICATE_STAMP); + } + } + + @Transactional + public StampInfo.Stamp uploadStamp( + AppjamtampRequest.RegisterStampRequest stampRequest, + Long userId + ) { + val stamp = stampRequest.toStamp(userId); + val newStamp = stampRepository.save(stamp); + return StampInfo.Stamp.from(newStamp); + } +} diff --git a/src/main/java/org/sopt/app/application/stamp/StampInfo.java b/src/main/java/org/sopt/app/application/stamp/StampInfo.java index acb35286..e597e54c 100755 --- a/src/main/java/org/sopt/app/application/stamp/StampInfo.java +++ b/src/main/java/org/sopt/app/application/stamp/StampInfo.java @@ -30,6 +30,21 @@ public static class Stamp { private LocalDateTime updatedAt; private int clapCount; private int viewCount; + + public static StampInfo.Stamp from(org.sopt.app.domain.entity.soptamp.Stamp stamp) { + return Stamp.builder() + .id(stamp.getId()) + .contents(stamp.getContents()) + .images(stamp.getImages()) + .userId(stamp.getUserId()) + .missionId(stamp.getMissionId()) + .activityDate(stamp.getActivityDate()) + .createdAt(stamp.getCreatedAt()) + .updatedAt(stamp.getUpdatedAt()) + .clapCount(stamp.getClapCount()) + .viewCount(stamp.getViewCount()) + .build(); + } } @Getter diff --git a/src/main/java/org/sopt/app/application/stamp/StampService.java b/src/main/java/org/sopt/app/application/stamp/StampService.java index a83f8acf..bdd889a1 100755 --- a/src/main/java/org/sopt/app/application/stamp/StampService.java +++ b/src/main/java/org/sopt/app/application/stamp/StampService.java @@ -1,9 +1,9 @@ package org.sopt.app.application.stamp; +import jakarta.validation.Valid; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import jakarta.validation.Valid; import java.util.Objects; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -20,6 +20,7 @@ import org.sopt.app.presentation.stamp.StampRequest.RegisterStampRequest; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; @@ -242,7 +243,8 @@ public int getStampClapCount(Long stampId) { .getClapCount(); } - @Transactional + // TODO: 비동기로 별도 스레드 혹은 이벤트로 처리하도록 변경 + @Transactional(propagation = Propagation.REQUIRES_NEW) public void increaseViewCountById(Long stampId) { stampRepository.increaseViewCount(stampId); } diff --git a/src/main/java/org/sopt/app/common/response/ErrorCode.java b/src/main/java/org/sopt/app/common/response/ErrorCode.java index 5b8cc144..bf87fca0 100755 --- a/src/main/java/org/sopt/app/common/response/ErrorCode.java +++ b/src/main/java/org/sopt/app/common/response/ErrorCode.java @@ -61,8 +61,9 @@ public enum ErrorCode { // MISSION MISSION_NOT_FOUND("존재하지 않는 미션입니다.", HttpStatus.NOT_FOUND), - //TEAM + // TEAM TEAM_NOT_FOUND("존재하지 않는 팀입니다.", HttpStatus.NOT_FOUND), + TEAM_FORBIDDEN("해당 팀에 대한 권한이 없습니다.", HttpStatus.FORBIDDEN), // STAMP STAMP_NOT_FOUND("존재하지 않는 스탬프입니다.", HttpStatus.BAD_REQUEST), diff --git a/src/main/java/org/sopt/app/facade/AppjamtampFacade.java b/src/main/java/org/sopt/app/facade/AppjamtampFacade.java index d56ac9ac..c6875fef 100644 --- a/src/main/java/org/sopt/app/facade/AppjamtampFacade.java +++ b/src/main/java/org/sopt/app/facade/AppjamtampFacade.java @@ -3,13 +3,21 @@ import java.util.Objects; import lombok.RequiredArgsConstructor; import lombok.val; +import org.sopt.app.application.appjamuser.AppjamUserInfo.AppjamUserStatus; import org.sopt.app.application.appjamuser.AppjamUserService; +import org.sopt.app.application.mission.MissionInfo.Level; +import org.sopt.app.application.mission.MissionService; import org.sopt.app.application.platform.PlatformService; import org.sopt.app.application.soptamp.SoptampUserFinder; +import org.sopt.app.application.soptamp.SoptampUserService; +import org.sopt.app.application.stamp.AppjamStampService; import org.sopt.app.application.stamp.ClapService; import org.sopt.app.application.stamp.StampInfo; import org.sopt.app.application.stamp.StampInfo.AppjamtampView; import org.sopt.app.application.stamp.StampService; +import org.sopt.app.common.exception.BadRequestException; +import org.sopt.app.common.response.ErrorCode; +import org.sopt.app.presentation.appjamtamp.AppjamtampRequest.RegisterStampRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,6 +30,9 @@ public class AppjamtampFacade { private final StampService stampService; private final ClapService clapService; private final AppjamUserService appjamUserService; + private final AppjamStampService appjamStampService; + private final SoptampUserService soptampUserService; + private final MissionService missionService; @Transactional(readOnly = true) public AppjamtampView getAppjamtamps(Long requestUserId, Long missionId, String nickname) { @@ -42,4 +53,22 @@ public AppjamtampView getAppjamtamps(Long requestUserId, Long missionId, String teamSummary ); } + + @Transactional + public StampInfo.Stamp uploadStamp(Long userId, RegisterStampRequest registerStampRequest) { + val appjamUserStatus = appjamUserService.getAppjamUserStatus(userId); + if (!appjamUserStatus.isAppjamJoined()) { + throw new BadRequestException(ErrorCode.TEAM_FORBIDDEN); + } + appjamStampService.checkDuplicateStamp(appjamUserStatus.getTeamNumber(), + registerStampRequest.getMissionId()); + val result = appjamStampService.uploadStamp(registerStampRequest, userId); + Level mission = missionService.getMissionLevelById(registerStampRequest.getMissionId()); + soptampUserService.addPointByLevel(userId, mission.getLevel()); + return result; + } + + public AppjamUserStatus getAppjampStatus(Long userId){ + return appjamUserService.getAppjamUserStatus(userId); + } } diff --git a/src/main/java/org/sopt/app/facade/MissionFacade.java b/src/main/java/org/sopt/app/facade/MissionFacade.java index 925f9949..f5714848 100644 --- a/src/main/java/org/sopt/app/facade/MissionFacade.java +++ b/src/main/java/org/sopt/app/facade/MissionFacade.java @@ -1,12 +1,14 @@ package org.sopt.app.facade; -import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.val; +import org.sopt.app.application.appjamuser.AppjamUserInfo.AppjamUserStatus; +import org.sopt.app.application.appjamuser.AppjamUserInfo.TeamSummary; import org.sopt.app.application.appjamuser.AppjamUserService; import org.sopt.app.application.mission.AppjamMissionService; import org.sopt.app.application.mission.MissionInfo.AppjamMissionInfos; import org.sopt.app.domain.enums.TeamNumber; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -19,16 +21,26 @@ public class MissionFacade { @Transactional(readOnly = true) public AppjamMissionInfos getTeamMissions( - TeamNumber teamNumber, - Optional complete + Long userId, + @Nullable TeamNumber teamNumber, + @Nullable Boolean complete ) { + if (teamNumber == null) { + val missions = appjamMissionService.getDisplayedMissions(); + return AppjamMissionInfos.of(AppjamUserStatus.appjamNotJoined(), TeamSummary.empty(), + missions); + } + val teamSummary = appjamUserService.getTeamSummaryByTeamNumber(teamNumber); - if (complete.isPresent()) { + val appjamUserStatus = appjamUserService.getAppjamUserStatus(userId); + if (complete != null) { return AppjamMissionInfos.of( + appjamUserStatus, teamSummary, - appjamMissionService.getMissionsByCondition(teamNumber, complete.get())); + appjamMissionService.getMissionsByTeamAndCondition(teamNumber, complete)); } - return AppjamMissionInfos.of(teamSummary, appjamMissionService.getAllMissions(teamNumber)); + return AppjamMissionInfos.of(appjamUserStatus, teamSummary, + appjamMissionService.getMissionsByTeam(teamNumber)); } } diff --git a/src/main/java/org/sopt/app/interfaces/postgres/StampRepository.java b/src/main/java/org/sopt/app/interfaces/postgres/StampRepository.java index 96c3fcfd..34a8089e 100755 --- a/src/main/java/org/sopt/app/interfaces/postgres/StampRepository.java +++ b/src/main/java/org/sopt/app/interfaces/postgres/StampRepository.java @@ -22,6 +22,8 @@ public interface StampRepository extends JpaRepository, StampReposi List findAllByUserIdIn(Collection userIds); + boolean existsByUserIdInAndMissionId(Collection userIds, Long missionId); + @Modifying(clearAutomatically = true, flushAutomatically = true) @Query(""" update Stamp s set s.viewCount = s.viewCount + 1 diff --git a/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampController.java b/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampController.java index 10c5d2e6..aec75957 100644 --- a/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampController.java +++ b/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampController.java @@ -6,7 +6,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.validation.Valid; -import java.util.Optional; import lombok.AllArgsConstructor; import lombok.val; import org.sopt.app.domain.enums.TeamNumber; @@ -17,6 +16,8 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -38,10 +39,11 @@ public class AppjamtampController { }) @GetMapping("/mission") public ResponseEntity getMissions( - @RequestParam TeamNumber teamNumber, + @AuthenticationPrincipal Long userId, + @RequestParam(required = false) TeamNumber teamNumber, @RequestParam(required = false) Boolean isCompleted ) { - val result = missionFacade.getTeamMissions(teamNumber, Optional.ofNullable(isCompleted)); + val result = missionFacade.getTeamMissions(userId, teamNumber, isCompleted); val response = appjamtampResponseMapper.of(result); return ResponseEntity.ok(response); } @@ -61,4 +63,21 @@ public ResponseEntity getMissions( val response = appjamtampResponseMapper.of(result); return ResponseEntity.ok(response); } + + @Operation(summary = "앱잼탬프 스탬프 제출하기") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "success"), + @ApiResponse(responseCode = "403", description = "no team", content = @Content), + @ApiResponse(responseCode = "409", description = "duplicate stamp", content = @Content), + @ApiResponse(responseCode = "500", description = "server error", content = @Content) + }) + @PostMapping("/stamp") + public ResponseEntity registerMissions( + @AuthenticationPrincipal Long userId, + @Valid @RequestBody AppjamtampRequest.RegisterStampRequest request + ) { + val result = appjamtampFacade.uploadStamp(userId, request); + val response = appjamtampResponseMapper.of(result); + return ResponseEntity.ok(response); + } } \ No newline at end of file diff --git a/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampRequest.java b/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampRequest.java index 97c1d869..532cfa61 100644 --- a/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampRequest.java +++ b/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampRequest.java @@ -2,10 +2,13 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import org.sopt.app.domain.entity.soptamp.Stamp; +import org.sopt.app.presentation.stamp.StampRequest.BaseStampRequest; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class AppjamtampRequest { @@ -23,4 +26,24 @@ public static class FindStampRequest { private String nickname; } + @Getter + @NoArgsConstructor(access = AccessLevel.PRIVATE) + public static class RegisterStampRequest extends BaseStampRequest { + + public RegisterStampRequest(Long missionId, String image, String contents, + String activityDate) { + super(missionId, image, contents, activityDate); + } + + public Stamp toStamp(Long userId) { + return Stamp.builder() + .contents(this.getContents()) + .images(List.of(this.getImage())) + .missionId(this.getMissionId()) + .activityDate(this.getActivityDate()) + .userId(userId) + .build(); + } + } + } diff --git a/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampResponse.java b/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampResponse.java index 1ebee5a2..041cf4f2 100644 --- a/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampResponse.java +++ b/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampResponse.java @@ -38,12 +38,21 @@ public static class AppjamMissionResponse { @AllArgsConstructor(access = AccessLevel.PUBLIC) public static class AppjamMissionResponses { + @Schema(description = "요청자의 팀 번호", example = "FIRST") + private TeamNumber myTeamNumber; + @Schema(description = "앱잼 참여 여부", example = "true") + private boolean isAppjamJoined; @Schema(description = "팀 번호", example = "FIRST") private TeamNumber teamNumber; @Schema(description = "팀 이름", example = "보핏") private String teamName; @Schema(description = "미션 정보") private List missions; + + @JsonProperty("isAppjamJoined") + public boolean isAppjamJoined() { + return isAppjamJoined; + } } @Getter @@ -88,4 +97,30 @@ public boolean isMine() { return isMine; } } + + @Getter + @AllArgsConstructor(access = AccessLevel.PUBLIC) + @NoArgsConstructor(access = AccessLevel.PRIVATE) + @Builder + public static class StampMain { + + @Schema(description = "스탬프 아이디", example = "1") + private Long id; + @Schema(description = "스탬프 내용", example = "모각공했다!") + private String contents; + @Schema(description = "스탬프 이미지", example = "[https://s3.ap-northeast-2.amazonaws.com/example/283aab53-22e3-46da-85ec-146c99f82ed4.jpeg]") + private List images; + @Schema(description = "활동 날짜", example = "2024.04.08") + private String activityDate; + @Schema(description = "스탬프 생성 일시", example = "2023-03-29T18:39:42.106369") + private LocalDateTime createdAt; + @Schema(description = "스탬프 수정 일시", example = "2023-03-29T18:39:42.106369") + private LocalDateTime updatedAt; + @Schema(description = "미션 아이디", example = "3") + private Long missionId; + @Schema(description = "총 박수 횟수", example = "124") + private int clapCount; + @Schema(description = "조회수", example = "58") + private int viewCount; + } } diff --git a/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampResponseMapper.java b/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampResponseMapper.java index 06d6b2a3..974c5d22 100644 --- a/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampResponseMapper.java +++ b/src/main/java/org/sopt/app/presentation/appjamtamp/AppjamtampResponseMapper.java @@ -1,7 +1,6 @@ package org.sopt.app.presentation.appjamtamp; import java.util.List; - import org.mapstruct.InjectionStrategy; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -9,6 +8,7 @@ import org.sopt.app.application.appjamrank.AppjamRankInfo; import org.sopt.app.application.mission.MissionInfo.AppjamMissionInfo; import org.sopt.app.application.mission.MissionInfo.AppjamMissionInfos; +import org.sopt.app.application.stamp.StampInfo; import org.sopt.app.application.stamp.StampInfo.AppjamtampView; import org.sopt.app.presentation.appjamrank.AppjamRankResponse; import org.sopt.app.presentation.appjamtamp.AppjamtampResponse.AppjamMissionResponse; @@ -21,6 +21,9 @@ ) public interface AppjamtampResponseMapper { + AppjamtampResponse.StampMain of(StampInfo.Stamp stampInfo); + + @Mapping(source = "appjamJoined", target = "isAppjamJoined") AppjamMissionResponses of(AppjamMissionInfos missionList); AppjamRankResponse.AppjamtampRankResponse toResponse(AppjamRankInfo.TeamRank teamRank); @@ -29,7 +32,8 @@ public interface AppjamtampResponseMapper { @Mapping(source = "completed", target = "isCompleted") AppjamMissionResponse toResponse(AppjamMissionInfo info); - default AppjamRankResponse.AppjamtampRankListResponse of(AppjamRankInfo.RankList appjamRankList) { + default AppjamRankResponse.AppjamtampRankListResponse of( + AppjamRankInfo.RankList appjamRankList) { List ranks = appjamRankList.getRanks().stream() .map(this::toResponse) .toList(); @@ -37,8 +41,10 @@ default AppjamRankResponse.AppjamtampRankListResponse of(AppjamRankInfo.RankList return new AppjamRankResponse.AppjamtampRankListResponse(ranks); } - default AppjamRankResponse.AppjamTodayRankListResponse of(AppjamRankInfo.TodayTeamRankList todayTeamRankList) { - List ranks = todayTeamRankList.getRanks().stream() + default AppjamRankResponse.AppjamTodayRankListResponse of( + AppjamRankInfo.TodayTeamRankList todayTeamRankList) { + List ranks = todayTeamRankList.getRanks() + .stream() .map(teamRank -> new AppjamRankResponse.AppjamTodayTeamRankResponse( teamRank.getRank(), teamRank.getTeamName(), diff --git a/src/main/java/org/sopt/app/presentation/user/UserController.java b/src/main/java/org/sopt/app/presentation/user/UserController.java index ede57108..4cc19a95 100755 --- a/src/main/java/org/sopt/app/presentation/user/UserController.java +++ b/src/main/java/org/sopt/app/presentation/user/UserController.java @@ -11,7 +11,6 @@ import java.util.Comparator; import java.util.List; import java.util.Optional; - import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; @@ -23,11 +22,13 @@ import org.sopt.app.common.utils.ActivityDurationCalculator; import org.sopt.app.domain.enums.IconType; import org.sopt.app.domain.enums.SoptPart; +import org.sopt.app.facade.AppjamtampFacade; import org.sopt.app.facade.AuthFacade; import org.sopt.app.facade.PokeFacade; import org.sopt.app.facade.RankFacade; import org.sopt.app.facade.SoptampFacade; import org.sopt.app.facade.UserFacade; +import org.sopt.app.presentation.user.UserResponse.AppjamStatusResponse; import org.sopt.app.presentation.user.UserResponse.SoptLog; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; @@ -52,6 +53,7 @@ public class UserController { private final PokeFacade pokeFacade; private final RankFacade rankFacade; private final UserFacade userFacade; + private final AppjamtampFacade appjamtampFacade; private final FortuneService fortuneService; private final PlatformService platformService; @@ -155,4 +157,13 @@ public ResponseEntity getMySoptLog( return ResponseEntity.ok(response); } + + @Operation(summary = "앱잼 팀 정보 조회") + @GetMapping("/appjam-info") + public ResponseEntity getTeamInfo( + @AuthenticationPrincipal Long userId + ) { + val result = appjamtampFacade.getAppjampStatus(userId); + return ResponseEntity.ok(AppjamStatusResponse.from(result)); + } } diff --git a/src/main/java/org/sopt/app/presentation/user/UserResponse.java b/src/main/java/org/sopt/app/presentation/user/UserResponse.java index ea2915ea..8c7d158a 100755 --- a/src/main/java/org/sopt/app/presentation/user/UserResponse.java +++ b/src/main/java/org/sopt/app/presentation/user/UserResponse.java @@ -1,21 +1,22 @@ package org.sopt.app.presentation.user; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; import java.util.stream.Collectors; - import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; +import org.sopt.app.application.appjamuser.AppjamUserInfo.AppjamUserStatus; import org.sopt.app.application.appservice.dto.AppServiceInfo; import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.PlaygroundProfile; import org.sopt.app.domain.enums.SoptPart; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; +import org.sopt.app.domain.enums.TeamNumber; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class UserResponse { @@ -318,4 +319,29 @@ public static MySoptLog ofActive( ); } } + + @Getter + @Builder + @ToString + public static class AppjamStatusResponse { + @Schema(description = "팀 번호") + private TeamNumber teamNumber; + @Schema(description = "팀 이름") + private String teamName; + @Schema(description = "앱잼 참여 여부") + private boolean isAppjamJoined; + + @JsonProperty("isAppjamJoined") + public boolean isAppjamJoined() { + return isAppjamJoined; + } + + public static AppjamStatusResponse from(AppjamUserStatus appjamUserStatus){ + return AppjamStatusResponse.builder() + .teamNumber(appjamUserStatus.getTeamNumber()) + .teamName(appjamUserStatus.getTeamName()) + .isAppjamJoined(appjamUserStatus.isAppjamJoined()) + .build(); + } + } }