Skip to content

Commit 3e6fca9

Browse files
authored
Merge pull request #35 from umc-timeto/develop
[Deploy] Todo & DailyLog 배포
2 parents 8236ce6 + b8fe3e4 commit 3e6fca9

40 files changed

+1125
-50
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package com.umc.timeto.dailyLog.controller;
2+
3+
import com.umc.timeto.dailyLog.dto.DailyLogRequestDTO;
4+
import com.umc.timeto.dailyLog.serivce.DailyLogService;
5+
import com.umc.timeto.global.apiPayload.code.ResponseCode;
6+
import com.umc.timeto.global.apiPayload.dto.ResponseDTO;
7+
import io.swagger.v3.oas.annotations.Operation;
8+
import jakarta.validation.Valid;
9+
import lombok.RequiredArgsConstructor;
10+
import org.springframework.http.ResponseEntity;
11+
import org.springframework.security.core.Authentication;
12+
import org.springframework.web.bind.annotation.*;
13+
14+
15+
@RestController
16+
@RequiredArgsConstructor
17+
@RequestMapping("api/logs")
18+
public class DailyLogController {
19+
private final DailyLogService dailyLogService;
20+
21+
// 일지 등록
22+
@Operation(
23+
summary = "일지 등록",
24+
description = "인증된 유저가 일지를 등록할 수 있습니다."
25+
)
26+
@PostMapping
27+
public ResponseEntity<?> saveLog(@RequestBody @Valid DailyLogRequestDTO dto,
28+
Authentication authentication) {
29+
Long memberId = (Long) authentication.getPrincipal();
30+
var result = dailyLogService.saveLog(dto, memberId);
31+
32+
return ResponseEntity
33+
.status(ResponseCode.SUCCESS_SAVE_LOG.getStatus().value())
34+
.body(new ResponseDTO<>(ResponseCode.SUCCESS_SAVE_LOG, result));
35+
}
36+
37+
// 월별 일지 조회
38+
@Operation(summary = "월별 일지 조회", description = "월별 일지 리스트를 조회합니다.")
39+
@GetMapping("/monthly")
40+
public ResponseEntity<?> getMonthlyLogs(@RequestParam int year,
41+
@RequestParam int month,
42+
Authentication authentication) {
43+
Long memberId = (Long) authentication.getPrincipal();
44+
var result = dailyLogService.getMonthlyLogs(year, month, memberId);
45+
46+
return ResponseEntity
47+
.status(ResponseCode.SUCCESS_GET_MONTHLY_LOGS.getStatus().value())
48+
.body(new ResponseDTO<>(ResponseCode.SUCCESS_GET_MONTHLY_LOGS, result));
49+
}
50+
51+
@Operation(summary = "일별 일지 조회", description = "일지를 조회합니다.")
52+
@GetMapping("/{logId}")
53+
public ResponseEntity<?> getDailyLogs(@PathVariable Long logId,
54+
Authentication authentication) {
55+
Long memberId = (Long) authentication.getPrincipal();
56+
57+
var result = dailyLogService.getDailyLog(logId, memberId);
58+
59+
return ResponseEntity
60+
.status(ResponseCode.SUCCESS_GET_DAILY_LOGS.getStatus().value())
61+
.body(new ResponseDTO<>(ResponseCode.SUCCESS_GET_DAILY_LOGS, result));
62+
}
63+
64+
// 일지 수정
65+
@Operation(
66+
summary = "일지 수정",
67+
description = "작성한 일지의 내용을 수정합니다.")
68+
@PatchMapping("/{logId}")
69+
public ResponseEntity<?> updateLog(@PathVariable Long logId,
70+
@RequestBody @Valid DailyLogRequestDTO dto,
71+
Authentication authentication) {
72+
Long memberId = (Long) authentication.getPrincipal();
73+
var result = dailyLogService.updateLog(logId, dto, memberId);
74+
75+
return ResponseEntity
76+
.status(ResponseCode.SUCCESS_UPDATE_LOG.getStatus().value())
77+
.body(new ResponseDTO<>(ResponseCode.SUCCESS_UPDATE_LOG, result));
78+
}
79+
80+
// 일지 삭제
81+
@Operation(summary = "일지 삭제", description = "작성한 일지를 삭제합니다.")
82+
@DeleteMapping("/{logId}")
83+
public ResponseEntity<?> deleteLog(@PathVariable Long logId,
84+
Authentication authentication) {
85+
Long memberId = (Long) authentication.getPrincipal();
86+
dailyLogService.deleteLog(logId, memberId);
87+
88+
return ResponseEntity
89+
.status(ResponseCode.SUCCESS_DELETE_LOG.getStatus().value())
90+
.body(new ResponseDTO<>(ResponseCode.SUCCESS_DELETE_LOG, null));
91+
}
92+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.umc.timeto.dailyLog.dto;
2+
3+
import com.umc.timeto.dailyLog.enums.Satisfaction;
4+
5+
import java.time.LocalDate;
6+
7+
public record DailyLogMonthlyDTO(
8+
Long logId,
9+
LocalDate date,
10+
Satisfaction satisfaction
11+
) {}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.umc.timeto.dailyLog.dto;
2+
3+
import com.umc.timeto.dailyLog.enums.Achievement;
4+
import com.umc.timeto.dailyLog.enums.Satisfaction;
5+
import jakarta.validation.constraints.Size;
6+
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
8+
9+
@Getter
10+
@NoArgsConstructor
11+
public class DailyLogRequestDTO {
12+
private Satisfaction answer1;
13+
private Achievement answer2;
14+
15+
@Size(max = 255)
16+
private String answer3;
17+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.umc.timeto.dailyLog.dto;
2+
3+
import com.umc.timeto.dailyLog.enums.Achievement;
4+
import com.umc.timeto.dailyLog.enums.Satisfaction;
5+
6+
import java.time.LocalDate;
7+
8+
public record DailyLogResponseDTO(
9+
Long logId,
10+
Satisfaction answer1,
11+
Achievement answer2,
12+
String answer3,
13+
LocalDate createdAt
14+
){}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.umc.timeto.dailyLog.entity;
2+
3+
import com.umc.timeto.dailyLog.enums.Achievement;
4+
import com.umc.timeto.dailyLog.enums.Satisfaction;
5+
import com.umc.timeto.member.entity.Member;
6+
import jakarta.persistence.*;
7+
import lombok.*;
8+
9+
import java.time.LocalDate;
10+
11+
@Entity
12+
@Getter
13+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
14+
@AllArgsConstructor
15+
@Builder
16+
public class DailyLog {
17+
@Id
18+
@GeneratedValue(strategy = GenerationType.IDENTITY)
19+
private long id;
20+
21+
@Column(nullable = false)
22+
private Satisfaction answer1; // 1-3 만족도
23+
24+
@Column(nullable = false)
25+
private Achievement answer2; // 1-5 계획 이행
26+
27+
@Column(nullable = false)
28+
private String answer3; // 잘한 점과 아쉬운 점
29+
30+
@Column(nullable = false)
31+
private LocalDate createdAt;
32+
33+
@ManyToOne(fetch = FetchType.LAZY)
34+
@JoinColumn(name = "member_id")
35+
private Member member;
36+
37+
public void update(Satisfaction answer1, Achievement answer2, String answer3) {
38+
this.answer1 = answer1;
39+
this.answer2 = answer2;
40+
this.answer3 = answer3;
41+
}
42+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.umc.timeto.dailyLog.enums;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
6+
@Getter
7+
@RequiredArgsConstructor
8+
public enum Achievement {
9+
PERFECT(1, "완벽하게 지켰어요."),
10+
MOSTLY(2, "큰 틀에서 잘 따랐어요."),
11+
HALF(3, "절반 이상은 지켰어요."),
12+
SOMEWHAT(4, "계획이 자주 어긋났어요."),
13+
DIFFERENT(5, "계획과는 아주 다른 하루였어요.")
14+
;
15+
16+
private final int code;
17+
private final String description;
18+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.umc.timeto.dailyLog.enums;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
6+
@Getter
7+
@RequiredArgsConstructor
8+
public enum Satisfaction {
9+
GREAT(1, "만족스러웠어요"),
10+
SOSO(2, "그저 그랬어요"),
11+
BAD(3, "아쉬웠어요");
12+
13+
private final int code;
14+
private final String description;
15+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.umc.timeto.dailyLog.repository;
2+
3+
import com.umc.timeto.dailyLog.entity.DailyLog;
4+
import com.umc.timeto.member.entity.Member;
5+
import org.springframework.data.jpa.repository.JpaRepository;
6+
import org.springframework.stereotype.Repository;
7+
8+
import java.time.LocalDate;
9+
import java.util.List;
10+
import java.util.Optional;
11+
12+
@Repository
13+
public interface DailyLogRepository extends JpaRepository<DailyLog, Long> {
14+
Optional<DailyLog> findByMemberAndCreatedAt(Member member, LocalDate createdAt);
15+
List<DailyLog> findByMemberAndCreatedAtBetween(Member member, LocalDate start, LocalDate end);
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.umc.timeto.dailyLog.serivce;
2+
3+
import com.umc.timeto.dailyLog.dto.DailyLogMonthlyDTO;
4+
import com.umc.timeto.dailyLog.dto.DailyLogRequestDTO;
5+
import com.umc.timeto.dailyLog.dto.DailyLogResponseDTO;
6+
7+
import java.util.List;
8+
9+
public interface DailyLogService {
10+
DailyLogResponseDTO saveLog(DailyLogRequestDTO dto, Long memberId);
11+
List<DailyLogMonthlyDTO> getMonthlyLogs(int year, int month, Long memberId);
12+
DailyLogResponseDTO getDailyLog(Long logId, Long memberId);
13+
DailyLogResponseDTO updateLog(Long logId, DailyLogRequestDTO dto, Long memberId);
14+
Long deleteLog(Long logId, Long memberId)
15+
;
16+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package com.umc.timeto.dailyLog.serivce;
2+
3+
import com.umc.timeto.dailyLog.dto.DailyLogMonthlyDTO;
4+
import com.umc.timeto.dailyLog.dto.DailyLogRequestDTO;
5+
import com.umc.timeto.dailyLog.dto.DailyLogResponseDTO;
6+
import com.umc.timeto.dailyLog.entity.DailyLog;
7+
import com.umc.timeto.dailyLog.repository.DailyLogRepository;
8+
import com.umc.timeto.global.apiPayload.code.ErrorCode;
9+
import com.umc.timeto.global.apiPayload.exception.GlobalException;
10+
import com.umc.timeto.member.entity.Member;
11+
import com.umc.timeto.member.repository.MemberRepository;
12+
import lombok.RequiredArgsConstructor;
13+
import org.springframework.stereotype.Service;
14+
import org.springframework.transaction.annotation.Transactional;
15+
16+
import java.time.LocalDate;
17+
import java.util.List;
18+
19+
@Service
20+
@Transactional
21+
@RequiredArgsConstructor
22+
public class DailyLogServiceImpl implements DailyLogService {
23+
private final DailyLogRepository dailyLogRepository;
24+
private final MemberRepository memberRepository;
25+
26+
// 일지 등록
27+
public DailyLogResponseDTO saveLog(DailyLogRequestDTO dto, Long memberId) {
28+
Member member = memberRepository.findById(memberId)
29+
.orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND)); // 에러 코드 수정
30+
31+
LocalDate today = LocalDate.now();
32+
if (dailyLogRepository.findByMemberAndCreatedAt(member, today).isPresent()) {
33+
throw new GlobalException(ErrorCode.DUPLICATE_DAILY_LOG);
34+
}
35+
36+
DailyLog dailyLog = DailyLog.builder()
37+
.answer1(dto.getAnswer1())
38+
.answer2(dto.getAnswer2())
39+
.answer3(dto.getAnswer3())
40+
.createdAt(today)
41+
.member(member)
42+
.build();
43+
44+
DailyLog savedLog = dailyLogRepository.save(dailyLog);
45+
46+
return new DailyLogResponseDTO(
47+
savedLog.getId(),
48+
savedLog.getAnswer1(),
49+
savedLog.getAnswer2(),
50+
savedLog.getAnswer3(),
51+
savedLog.getCreatedAt()
52+
);
53+
}
54+
55+
// 월별 일지 조회
56+
@Transactional(readOnly = true)
57+
public List<DailyLogMonthlyDTO> getMonthlyLogs(int year, int month, Long memberId) {
58+
Member member = memberRepository.findById(memberId)
59+
.orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND));
60+
61+
LocalDate start = LocalDate.of(year, month, 1);
62+
LocalDate end = start.withDayOfMonth(start.lengthOfMonth());
63+
64+
return dailyLogRepository.findByMemberAndCreatedAtBetween(member, start, end)
65+
.stream()
66+
.map(log -> new DailyLogMonthlyDTO(log.getId(), log.getCreatedAt(), log.getAnswer1()))
67+
.toList();
68+
}
69+
70+
// 일별 일지 조회
71+
@Transactional(readOnly = true)
72+
public DailyLogResponseDTO getDailyLog(Long logId, Long memberId) {
73+
Member member = memberRepository.findById(memberId)
74+
.orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND));
75+
76+
DailyLog dailyLog = dailyLogRepository.findById(logId)
77+
.orElseThrow(() -> new GlobalException(ErrorCode.LOG_NOT_FOUND));
78+
79+
// 본인 확인
80+
if (!dailyLog.getMember().getMemberId().equals(member.getMemberId())) {
81+
throw new GlobalException(ErrorCode.LOG_FORBIDDEN);
82+
}
83+
84+
return new DailyLogResponseDTO(
85+
dailyLog.getId(),
86+
dailyLog.getAnswer1(),
87+
dailyLog.getAnswer2(),
88+
dailyLog.getAnswer3(),
89+
dailyLog.getCreatedAt()
90+
);
91+
}
92+
93+
// 일지 수정
94+
public DailyLogResponseDTO updateLog(Long logId, DailyLogRequestDTO dto, Long memberId) {
95+
Member member = memberRepository.findById(memberId)
96+
.orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND));
97+
98+
DailyLog dailyLog = dailyLogRepository.findById(logId)
99+
.orElseThrow(() -> new GlobalException(ErrorCode.LOG_NOT_FOUND));
100+
101+
if (!dailyLog.getMember().getMemberId().equals(member.getMemberId())) {
102+
throw new GlobalException(ErrorCode.LOG_FORBIDDEN);
103+
}
104+
105+
dailyLog.update(dto.getAnswer1(), dto.getAnswer2(), dto.getAnswer3());
106+
107+
return new DailyLogResponseDTO(
108+
dailyLog.getId(),
109+
dailyLog.getAnswer1(),
110+
dailyLog.getAnswer2(),
111+
dailyLog.getAnswer3(),
112+
dailyLog.getCreatedAt()
113+
);
114+
}
115+
116+
// 일지 삭제
117+
public Long deleteLog(Long logId, Long memberId) {
118+
Member member = memberRepository.findById(memberId)
119+
.orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND));
120+
121+
DailyLog dailyLog = dailyLogRepository.findById(logId)
122+
.orElseThrow(() -> new GlobalException(ErrorCode.LOG_NOT_FOUND));
123+
124+
if (!dailyLog.getMember().getMemberId().equals(member.getMemberId())) {
125+
throw new GlobalException(ErrorCode.LOG_FORBIDDEN);
126+
}
127+
128+
dailyLogRepository.delete(dailyLog);
129+
return logId;
130+
}
131+
}

0 commit comments

Comments
 (0)