Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import BE_Elixir.Elixir.domain.auth.dto.AccessTokenDTO;
import BE_Elixir.Elixir.domain.auth.dto.response.TokenResponseDTO;
import BE_Elixir.Elixir.domain.auth.dto.request.LoginRequestDTO;
import BE_Elixir.Elixir.domain.challenge.service.ChallengeAchievementService;
import BE_Elixir.Elixir.domain.member.entity.MemberDetails;
import BE_Elixir.Elixir.domain.member.service.MemberDetailsService;
import BE_Elixir.Elixir.global.exception.CustomException;
Expand Down Expand Up @@ -30,6 +31,7 @@ public class AuthService {
private final JwtProvider jwtProvider;
private final RedisAuthService redisAuthService;
private final MemberDetailsService memberDetailsService;
private final ChallengeAchievementService challengeAchievementService;

// 로그인 (jwt 발급 및 Redis 저장)
public TokenResponseDTO signIn(LoginRequestDTO request) {
Expand All @@ -51,6 +53,11 @@ public TokenResponseDTO signIn(LoginRequestDTO request) {
redisAuthService.saveRefreshToken(email, refreshToken);
log.info("Refresh Token Redis에 저장: email={}, token={}", email, refreshToken);

String memberEmail = request.getEmail();

// 자동 참여 메서드 호출
challengeAchievementService.challengeParticipation(memberEmail);

return tokenResponse;
} catch (BadCredentialsException e) {
log.warn("로그인 실패 - 잘못된 비밀번호: {}", request.getEmail());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ public class ChallengeAchievementId implements Serializable {
private Long memberId;
private Long challengeId;

public ChallengeAchievementId(Long memberId, Long challengeId) {
this.memberId = memberId;
this.challengeId = challengeId;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -119,6 +121,7 @@ else if (event instanceof RecipeEvent) {
handleGoal(goalType, memberId, openedAt, resultSetter);
}


// 목표 달성 결과에 따라 다음 단계 활성화
if (achievement.isStep1Goal1Achieved() && achievement.isStep1Goal2Achieved()) {
achievement.setStep2Goal1Active(true);
Expand Down Expand Up @@ -168,10 +171,28 @@ private void handleGoal(ChallengeGoalType goalType, Long memberId, LocalDateTime
case DIET_LUNCH ->
achieved = dietLogRepository.existsByMemberIdAndTypeAndTimeAfter(memberId, DietLogType.점심, openedAt);
case DIET_THREE_MEALS -> {
boolean hasBreakfast = dietLogRepository.existsByMemberIdAndTypeAndTimeAfter(memberId, DietLogType.아침, openedAt);
boolean hasLunch = dietLogRepository.existsByMemberIdAndTypeAndTimeAfter(memberId, DietLogType.점심, openedAt);
boolean hasDinner = dietLogRepository.existsByMemberIdAndTypeAndTimeAfter(memberId, DietLogType.저녁, openedAt);
achieved = hasBreakfast && hasLunch && hasDinner;
// 특정 날짜 단위로 아침/점심/저녁이 모두 기록된 날이 있는지를 체크
List<LocalDate> datesWithBreakfast = dietLogRepository.findTimesWithDietTypeAfter(memberId, DietLogType.아침, openedAt).stream()
.map(LocalDateTime::toLocalDate)
.distinct()
.toList();

List<LocalDate> datesWithLunch = dietLogRepository.findTimesWithDietTypeAfter(memberId, DietLogType.점심, openedAt).stream()
.map(LocalDateTime::toLocalDate)
.distinct()
.toList();

List<LocalDate> datesWithDinner = dietLogRepository.findTimesWithDietTypeAfter(memberId, DietLogType.저녁, openedAt).stream()
.map(LocalDateTime::toLocalDate)
.distinct()
.toList();

// 교집합으로 하루라도 3끼 다 먹은 날이 있는지 확인
Set<LocalDate> breakfastSet = new HashSet<>(datesWithBreakfast);
breakfastSet.retainAll(datesWithLunch);
breakfastSet.retainAll(datesWithDinner);

achieved = !breakfastSet.isEmpty();
}
case DIET_SEASONAL_ONCE -> {
// 사용자의 식단에 포함된 식재료 목록
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package BE_Elixir.Elixir.domain.challenge.repository;

import BE_Elixir.Elixir.domain.challenge.entity.ChallengeAchievement;
import BE_Elixir.Elixir.domain.challenge.entity.ChallengeAchievementId;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;

public interface ChallengeAchievementRepository extends JpaRepository<ChallengeAchievement, Long> {
public interface ChallengeAchievementRepository extends JpaRepository<ChallengeAchievement, ChallengeAchievementId> {
// 챌린지에 대한 사용자의 달성 상태 정보 조회
Optional<ChallengeAchievement> findByChallengeIdAndMemberId(Long challengeId, Long memberId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import BE_Elixir.Elixir.domain.challenge.dto.response.ChallengeProgressResponseDTO;
import BE_Elixir.Elixir.domain.challenge.entity.Challenge;
import BE_Elixir.Elixir.domain.challenge.entity.ChallengeAchievement;
import BE_Elixir.Elixir.domain.challenge.entity.ChallengeAchievementId;
import BE_Elixir.Elixir.domain.challenge.repository.ChallengeAchievementRepository;
import BE_Elixir.Elixir.domain.challenge.repository.ChallengeRepository;
import BE_Elixir.Elixir.domain.member.repository.MemberRepository;
import BE_Elixir.Elixir.global.exception.CustomException;
import BE_Elixir.Elixir.global.exception.ErrorCode;
import jakarta.transaction.Transactional;
Expand All @@ -22,6 +24,7 @@ public class ChallengeAchievementService {

private final ChallengeRepository challengeRepository;
private final ChallengeAchievementRepository challengeAchievementRepository;
private final MemberRepository memberRepository;

@Transactional
public void save(ChallengeAchievement achievement) {
Expand Down Expand Up @@ -120,4 +123,40 @@ public ChallengeProgressResponseDTO getBeforeProgress(Long memberId, Long challe
.orElseGet(() -> ChallengeProgressResponseDTO.empty(challenge));
}

// 챌린지 자동 참여
@Transactional
public void challengeParticipation(String memberEmail) {
LocalDate now = LocalDate.now();
int year = now.getYear();
int month = now.getMonthValue();

// 회원 정보 조회 (email -> memberId)
Long memberId = memberRepository.findByEmail(memberEmail)
.orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND))
.getId();

Challenge challenge = challengeRepository.findByYearAndMonth(year, month)
.orElseThrow(() -> new CustomException(ErrorCode.CHALLENGE_NOT_FOUND));

ChallengeAchievementId id = new ChallengeAchievementId(memberId, challenge.getId());

boolean exists = challengeAchievementRepository.existsById(id);

if (!exists) {
ChallengeAchievement achievement = new ChallengeAchievement();
achievement.setMemberId(memberId);
achievement.setChallengeId(challenge.getId());
achievement.setStep1Goal1Active(true);
achievement.setStep1Goal2Active(true);
achievement.setStep2Goal1Active(false);
achievement.setStep2Goal2Active(false);
achievement.setStep3Goal1Active(false);
achievement.setStep3Goal2Active(false);
achievement.setStep4Goal1Active(false);
achievement.setStep4Goal2Active(false);
achievement.setOpenedAt(LocalDateTime.now());

challengeAchievementRepository.save(achievement);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

Expand Down Expand Up @@ -46,5 +47,9 @@ int countDietLogsInMonth(@Param("memberId") Long memberId,
@Param("startOfMonth") LocalDateTime startOfMonth,
@Param("endOfMonth") LocalDateTime endOfMonth);


// - 특정 시간 이후에 작성된 기록
@Query("SELECT DISTINCT dl.time FROM DietLog dl WHERE dl.member.id = :memberId AND dl.type = :type AND dl.time > :after")
List<LocalDateTime> findTimesWithDietTypeAfter(@Param("memberId") Long memberId,
@Param("type") DietLogType type,
@Param("after") LocalDateTime after);
}