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
2 changes: 2 additions & 0 deletions src/main/java/umc7th/bulk/BulkApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableJpaAuditing
@EnableScheduling
public class BulkApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ public interface RecordRepository extends JpaRepository<Record, Long> {
@Query("SELECT r FROM Record r WHERE r.user = :user AND r.date = :date")
List<Record> findByUserAndDate(@Param("user") User user, @Param("date") LocalDate date);

boolean existsByUserAndDate(User user, LocalDate date);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package umc7th.bulk.record.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import umc7th.bulk.user.repository.UserRepository;

@Slf4j
@Service
@RequiredArgsConstructor
public class RecordCompleteResetService {

private final UserRepository userRepository;

/**
* 맀일 μžμ •μ— record_complete 값을 false둜 μ΄ˆκΈ°ν™”ν•˜λŠ” 배치 μž‘μ—…
*/

@Transactional
@Scheduled(cron = "0 0 0 * * ?")
public void resetRecordComplete() {
log.info("맀일 μžμ • record_complete κ°’ μ΄ˆκΈ°ν™” μ‹œμž‘...");
int updatedCount = userRepository.resetRecordComplete();
log.info("βœ… μ΄ˆκΈ°ν™” μ™„λ£Œ: {}λͺ…μ˜ record_complete 값을 false둜 λ³€κ²½", updatedCount);
}
}
69 changes: 69 additions & 0 deletions src/main/java/umc7th/bulk/record/service/RecordServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import umc7th.bulk.global.error.GeneralErrorCode;
import umc7th.bulk.global.error.exception.CustomException;
import umc7th.bulk.group.entity.Group;
import umc7th.bulk.group.repository.GroupRepository;
import umc7th.bulk.meal.entity.MealType;
import umc7th.bulk.mealItem.entity.MealItem;
import umc7th.bulk.mealMealItemMapping.entity.MealMealItemMapping;
Expand All @@ -19,6 +23,8 @@
import umc7th.bulk.record.upload.S3Service;
import umc7th.bulk.recordedFood.entity.RecordedFood;
import umc7th.bulk.recordedFood.repository.RecordedFoodRepository;
import umc7th.bulk.stageRecord.entity.StageRecord;
import umc7th.bulk.stageRecord.repository.StageRecordRepository;
import umc7th.bulk.user.domain.User;
import umc7th.bulk.user.repository.UserRepository;
import umc7th.bulk.user.service.UserService;
Expand All @@ -42,6 +48,9 @@ public class RecordServiceImpl implements RecordService {
private final UserService userService;
private final UserRepository userRepository;

private final StageRecordRepository stageRecordRepository;
private final GroupRepository groupRepository;

@Transactional
public RecordResponseDto createRecord(RecordRequestDto.Create requestDto) {
// μ‚¬μš©μž 쑰회
Expand All @@ -58,6 +67,10 @@ public RecordResponseDto createRecord(RecordRequestDto.Create requestDto) {
throw new IllegalArgumentException("이미 ν•΄λ‹Ή λ‚ μ§œμ™€ λΌλ‹ˆμ— λŒ€ν•œ 기둝이 μ‘΄μž¬ν•©λ‹ˆλ‹€.");
}

// μ‚¬μš©μžμ˜ ν•΄λ‹Ή λ‚ μ§œ 기둝 확인
boolean hasRecordToday = recordRepository.existsByUserAndDate(user, requestDto.getDate());


// μ‚¬μš©μžμ˜ λΌλ‹ˆ(MealType)에 ν•΄λ‹Ήν•˜λŠ” 식단 데이터 쑰회
List<MealMealItemMapping> mealMappings = mealMealItemMappingRepository.findByMeal_LocalDateAndMeal_Type(
requestDto.getDate(), requestDto.getMealType());
Expand All @@ -80,6 +93,14 @@ public RecordResponseDto createRecord(RecordRequestDto.Create requestDto) {

Record savedRecord = recordRepository.save(record);

// ν•˜λ£¨μ— ν•œ λ²ˆμ΄λΌλ„ κΈ°λ‘ν•˜λ©΄ record_complete = true μ„€μ •
if (!hasRecordToday) {
user.markRecordComplete();
userRepository.save(user);
}

checkAndAdvanceStage(user.getGroup());

// MealItem을 기반으둜 RecordedFood 생성
List<RecordedFood> recordedFoods = mealMappings.stream()
.map(MealMealItemMapping::getMealItem)
Expand Down Expand Up @@ -158,6 +179,10 @@ public RecordResponseDto createNotFollowedRecord(RecordRequestDto.CreateNotFollo
// MealType λ³€ν™˜
MealType type = requestDto.getMealType();

// μ‚¬μš©μžμ˜ ν•΄λ‹Ή λ‚ μ§œ 기둝 확인
boolean hasRecordToday = recordRepository.existsByUserAndDate(user, requestDto.getDate());


String uploadedImageUrl = null;
String gptRawResponseString = null;

Expand Down Expand Up @@ -262,6 +287,14 @@ public RecordResponseDto createNotFollowedRecord(RecordRequestDto.CreateNotFollo
Record savedRecord = recordRepository.save(record);
log.info("βœ… Record μ €μž₯ μ™„λ£Œ: recordId={}", savedRecord.getId());

// ν•˜λ£¨μ— ν•œ λ²ˆμ΄λΌλ„ κΈ°λ‘ν•˜λ©΄ record_complete = true μ„€μ •
if (!hasRecordToday) {
user.markRecordComplete();
userRepository.save(user);
}

checkAndAdvanceStage(user.getGroup());

// Response 생성
return RecordResponseDto.builder()
.recordId(savedRecord.getId())
Expand Down Expand Up @@ -356,5 +389,41 @@ public RecordResponseDto.TodaySummary getTodayRecord(User user) {
.build();
}

public void checkAndAdvanceStage(Group group) {
// ν˜„μž¬ κ·Έλ£Ήμ—μ„œ recordComplete = true인 μœ μ € 수 확인
int recordedCount = userRepository.countByGroupAndRecordCompleteTrue(group);

if (recordedCount >= 5) {
advanceStage(group);
}
}

private void advanceStage(Group group) {
// ν˜„μž¬ 그룹의 κ°€μž₯ μ΅œμ‹  μŠ€ν…Œμ΄μ§€ κ°€μ Έμ˜€κΈ°
StageRecord currentStageRecord = stageRecordRepository
.findTopByGroupOrderByStageNumberDesc(group)
.orElseThrow(() -> new CustomException(GeneralErrorCode.GROUP_NOT_FOUND_404));

// ν˜„μž¬ μŠ€ν…Œμ΄μ§€ μ™„λ£Œ 처리
currentStageRecord.completeStage();
stageRecordRepository.save(currentStageRecord);

// 그룹의 ν˜„μž¬ μŠ€ν…Œμ΄μ§€ 증가
group.advanceStage();
groupRepository.save(group);

// μƒˆλ‘œμš΄ μŠ€ν…Œμ΄μ§€ 기둝 생성
StageRecord newStageRecord = StageRecord.builder()
.group(group)
.stageNumber(group.getCurrentStage())
.totalUsers((int) userRepository.countByGroup(group))
.recordedUsers(0) // μƒˆλ‘œμš΄ μŠ€ν…Œμ΄μ§€μ΄λ―€λ‘œ 기둝된 μ‚¬μš©μž 0λͺ…λΆ€ν„° μ‹œμž‘
.isCompleted(false)
.build();

stageRecordRepository.save(newStageRecord);
}



}
2 changes: 2 additions & 0 deletions src/main/java/umc7th/bulk/stageRecord/entity/StageRecord.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public void increaseRecordedUsers() {
this.recordedUsers++;
}

public void increaseTotalUsers() { this.totalUsers++; }

// μŠ€ν…Œμ΄μ§€ μ™„λ£Œ 처리 둜직
public void completeStage() {
this.isCompleted = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package umc7th.bulk.stageRecord.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import umc7th.bulk.group.entity.Group;
import umc7th.bulk.stageRecord.entity.StageRecord;

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

public interface StageRecordRepository extends JpaRepository<StageRecord, Long> {
List<StageRecord> findByGroupGroupIdOrderByStageNumberAsc(Long groupId);

Optional<StageRecord> findTopByGroupOrderByStageNumberDesc(Group group);
}
9 changes: 8 additions & 1 deletion src/main/java/umc7th/bulk/user/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public class User extends BaseTimeEntity {
private String favoriteFood;

@Column(nullable = false, name = "record_complete")
private boolean recordComplete;
private boolean recordComplete = false;

@Column(nullable = false, name = "access_token")
private String accessToken;
Expand Down Expand Up @@ -168,6 +168,13 @@ public void setGroup(Group group) {
}
}


public void markRecordComplete() {
if (!this.recordComplete) {
this.recordComplete = true;
}

}
public void updateCurrentNutrients(Long calories, Long carbos, Long proteins, Long fats) {
this.curCalories += calories;
this.curCarbos += carbos;
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/umc7th/bulk/user/repository/UserRepository.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package umc7th.bulk.user.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
import umc7th.bulk.group.entity.Group;
import umc7th.bulk.user.domain.User;

import java.util.List;
Expand All @@ -14,4 +19,22 @@ public interface UserRepository extends JpaRepository<User,Long> {
List<User> findByGroupGroupIdAndRecordCompleteTrue(Long groupId); // ν•΄λ‹Ή κ·Έλ£Ή id μ—μ„œ 였늘 기둝 λ‹¬μ„±ν•œ μ‚¬μš©μž 리슀트
Optional<User> findByKakaoId(String kakaoId);
Optional<User> findByEmail(String email);

@Modifying
@Transactional
@Query("UPDATE User u SET u.recordComplete = false")
int resetRecordComplete();

// νŠΉμ • κ·Έλ£Ή 기둝 λ‹¬μ„±ν•œ 인원 수 쑰회 (였늘 기둝 μ™„λ£Œν•œ 인원 수)
@Query("SELECT COUNT(u) FROM User u WHERE u.group = :group AND u.recordComplete = true")
int countByGroupAndRecordCompleteTrue(@Param("group") Group group);

// νŠΉμ • κ·Έλ£Ή 총 인원 수 쑰회
@Query("SELECT COUNT(u) FROM User u WHERE u.group = :group")
int countByGroup(@Param("group") Group group);





}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import umc7th.bulk.global.jwt.util.JwtProvider;
import umc7th.bulk.group.entity.Group;
import umc7th.bulk.group.repository.GroupRepository;
import umc7th.bulk.stageRecord.entity.StageRecord;
import umc7th.bulk.stageRecord.repository.StageRecordRepository;
import umc7th.bulk.user.domain.User;
import umc7th.bulk.user.dto.UserRequestDTO;
import umc7th.bulk.user.dto.UserResponseDTO;
Expand All @@ -30,6 +32,7 @@ public class UserCommandServiceImpl implements UserCommandService {
private final JwtProvider jwtProvider;
private final BulkCharacterRepository bulkCharacterRepository;
private final GroupRepository groupRepository;
private final StageRecordRepository stageRecordRepository;

@Override
public UserResponseDTO.UserTokenDTO signup(UserRequestDTO.SignupDTO dto) {
Expand Down Expand Up @@ -69,9 +72,26 @@ public UserResponseDTO.UserTokenDTO signup(UserRequestDTO.SignupDTO dto) {
.currentStage(1)
.endDate(LocalDateTime.now().plusDays(7)) // κ·Έλ£Ή μ’…λ£ŒμΌ 7일 ν›„ μ„€μ •
.build();
return groupRepository.save(newGroup);
groupRepository.save(newGroup);

StageRecord firstStage = StageRecord.builder()
.group(newGroup)
.stageNumber(1)
.totalUsers(1)
.recordedUsers(0)
.isCompleted(false)
.build();
stageRecordRepository.save(firstStage);

return newGroup;
});

if (!groupRepository.findGroupWithSpace().isPresent()) { // κΈ°μ‘΄ 그룹인지 확인
StageRecord latestStage = stageRecordRepository.findTopByGroupOrderByStageNumberDesc(group)
.orElseThrow(() -> new RuntimeException("StageRecord not found for existing group."));
latestStage.increaseTotalUsers();
stageRecordRepository.save(latestStage);
}


// User μ €μž₯ (BulkCharacter 포함)
Expand Down
21 changes: 21 additions & 0 deletions src/main/resources/certificate.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDazCCAlOgAwIBAgIUWrOnf2nFmTI+YEg8AiaSqry4HPswDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNTAyMTkxMjI2MjJaFw0yNjAy
MTkxMjI2MjJaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCowVmGzO1HRrd22gUE3U66jSaBN1I9Zw8Uo7o9fUch
gAvDZUEY7zWlhCwWvyXaaG6opVwBH/n8Hwm+x+BSAqhcBfZyP6Cn5wNeXEn69Hx/
4uIR3lrKo8cFeSm6ukwDuEi/Rk8Yp4Sfruu1ErDLJx/daA5HS6ikA7oyZpfMJN7x
NOs3bmbyrPvgCqEty+sGa3/tXPv8ocRjt829stDBVsEjEa6F7VcRRchIqIswA63B
KxJUTKI59NsLznr1hRsIOInwjEXlUPF2KwMwva+Eb0cA3SoXh9fizLMOtJ6lW5as
Xucm+spSV8EpfPkWi+Bn3z7DRfydtKzr0oWVMMObjLtDAgMBAAGjUzBRMB0GA1Ud
DgQWBBQNFGQPkXx1xq+hg8NvMEFqJYwpKjAfBgNVHSMEGDAWgBQNFGQPkXx1xq+h
g8NvMEFqJYwpKjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCd
ntLw/fXZpmH8RZ5W/972iBE0w4ZzxsdoXAKcMQUOoQDsypQLf9ZuUYYf3zuvUEjT
Rc8PWSnB44UHBi0AgHFmjOED+ct2bLOopWEJQ7/hXcwg9a1hQu4XG78RSG6FmX7q
frOUGZLAcVV3Yr7hR8BwVny4S/Fuze2u/SnnbgH1Y0KDvDlhhOfYjNDdDmRb+thI
zfpvSDE9ojvC/PwT/1pXPoLBb/BkILOKEeASmHUgb4LI1D3+Ak2z0tpPUAKmI+/P
b9NVAtuCkR6UvvGhxYklAnAdJIfn5NzRS+DVzHq3CgrCGVKfaShjZJT7HNu3Qqe9
ZZWG85U/eCbbl0FVRB5o
-----END CERTIFICATE-----
Binary file added src/main/resources/keystore.p12
Binary file not shown.
28 changes: 28 additions & 0 deletions src/main/resources/private.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCowVmGzO1HRrd2
2gUE3U66jSaBN1I9Zw8Uo7o9fUchgAvDZUEY7zWlhCwWvyXaaG6opVwBH/n8Hwm+
x+BSAqhcBfZyP6Cn5wNeXEn69Hx/4uIR3lrKo8cFeSm6ukwDuEi/Rk8Yp4Sfruu1
ErDLJx/daA5HS6ikA7oyZpfMJN7xNOs3bmbyrPvgCqEty+sGa3/tXPv8ocRjt829
stDBVsEjEa6F7VcRRchIqIswA63BKxJUTKI59NsLznr1hRsIOInwjEXlUPF2KwMw
va+Eb0cA3SoXh9fizLMOtJ6lW5asXucm+spSV8EpfPkWi+Bn3z7DRfydtKzr0oWV
MMObjLtDAgMBAAECggEAS4z4hEmlpyXpSCv2WEWuFAXSacI3Luc/UKm2XQYDvOND
IPDpcnzRoy7nwC1GiJ/9fsI9TQGgXPgWWFPKwVyQPFatDVwgFFtv3iRqOJCRVn3g
YUiPlC47kV87x+3Uz0uHQh77lVmWHhllTFU4UlNLSEfoMJIWR4ulph/ZMNuG9ixU
IBftnOUp0RlPpxl1nsRmNs70NkOiF9bMHjZ8KNd6RwKLFNLBeunBQdTGMz5/wqew
no5F/KR0eMdVWaM6movM//Q0KmIm6jdu8e2ZYMjOOsuDFE+E2VcXCPWUtuUKWdEF
f/h2oPcfvW29/KjlCWHJilJirKvUh4dh5GIgWuA8CQKBgQDotHdEbmZyE2MQzRXh
Plh1xQ13iJ3gx+j0x7tt1NluZ+lE6BtN0xFwvYC4rH3cvoh4TWatAAan3nnb0o3a
Rw7yromYyQFIRzU1PsiSt1Ty1u7Iw/w34gQgDW9gfmtXRsYxiU6F0p9qZLfH0PXX
g/LVqEqOD+Zv1IzehfU3SiUpCwKBgQC5pgtZZAHvXLW6H74iGvISZ7/o/bd62/Or
AEP2t1Ja7JHk9MxmwNJ3Wa8JGjnZ2Pbd3xqVTqPddZFUfSgsNpGckJvuqWyqPYYU
/aYWEzrEypkh3ZbhCYE612Jp7SUwjWJgDqe0FdnzZKd/R6D4UIOFn2DKtnXbBqJO
N8GhMEHJqQKBgDWZM4tgfloyGvRIuIxr5sYhgAuTPQIEKaUPyBzxFK+4YWNMrtVL
E05LZ7WhjU/l1tsWwNqCEgZiWOEH60JmcYv2JZ06VwBF3nyIHHymm3tfhBpcAeEB
Pv/++DNaivDMTWQlgx+RtsQztJzihW2BZ9JMc/eqs+H4LAYpBqUYf9ynAoGAcD0J
A4RI/zPn0p06UFhGHgaHqg8qjKbKDIpejJyMt9fq5KdzpHPTSsD35+LpMuHPbphh
8/7VZyCbOp9oWEKtiiCLhaD8x3fmxm4LqbD6iNuL9UOI4ojijnaFU1FCeLYh0b1K
er/zQwmJkpP1p+rVeUXAOQ5S9pZuLifbct5AB/ECgYAgHXUpe6tqm7RjaQYCCYZa
153NAZbOVkgzsihllyR1QGMPrRYr56SyKQ9UX2AS3i4F0x5Cz8+uOFWhBAeZaGX1
AYMPrzDUOVyEdPQyX0Xc8kWoYeUmhnm+QUSaF9XUUvSU4a0O8Vp4GqOvTGNUwgKi
fukZyfJQFc4AJhUFbSIv0g==
-----END PRIVATE KEY-----
Loading