Skip to content

Commit c0527db

Browse files
authored
Merge branch 'dev' into Test/155
2 parents 62ee836 + a4d8484 commit c0527db

File tree

7 files changed

+236
-0
lines changed

7 files changed

+236
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.back.domain.study.memo.controller;
2+
3+
4+
import com.back.domain.study.memo.dto.MemoRequestDto;
5+
import com.back.domain.study.memo.dto.MemoResponseDto;
6+
import com.back.domain.study.memo.service.MemoService;
7+
import com.back.global.common.dto.RsData;
8+
import com.back.global.security.user.CustomUserDetails;
9+
import jakarta.validation.Valid;
10+
import lombok.RequiredArgsConstructor;
11+
import org.springframework.format.annotation.DateTimeFormat;
12+
import org.springframework.http.ResponseEntity;
13+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
14+
import org.springframework.web.bind.annotation.*;
15+
16+
import java.time.LocalDate;
17+
import java.util.List;
18+
19+
@RestController
20+
@RequiredArgsConstructor
21+
@RequestMapping("/api/memos")
22+
public class MemoController {
23+
private final MemoService memoService;
24+
25+
// ==================== 생성 및 수정 ===================
26+
// 메모 생성 및 수정
27+
@PostMapping
28+
public ResponseEntity<RsData<MemoResponseDto>> createOrUpdateMemo(
29+
@AuthenticationPrincipal CustomUserDetails user,
30+
@Valid @RequestBody MemoRequestDto request
31+
) {
32+
Long userId = user.getUserId();
33+
MemoResponseDto response = memoService.createOrUpdateMemo(userId, request);
34+
return ResponseEntity.ok(RsData.success("메모가 저장되었습니다.", response));
35+
}
36+
37+
// ==================== 조회 ===================
38+
// 날짜별 메모 조회
39+
@GetMapping
40+
public ResponseEntity<RsData<MemoResponseDto>> getMemoByDate(
41+
@AuthenticationPrincipal CustomUserDetails user,
42+
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date
43+
) {
44+
Long userId = user.getUserId();
45+
MemoResponseDto response = memoService.getMemoByDate(userId, date);
46+
return ResponseEntity.ok(RsData.success("메모를 조회했습니다.", response));
47+
}
48+
49+
// ==================== 삭제 ===================
50+
// 메모 삭제
51+
@DeleteMapping("/{memoId}")
52+
public ResponseEntity<RsData<MemoResponseDto>> deleteMemo(
53+
@AuthenticationPrincipal CustomUserDetails user,
54+
@PathVariable Long memoId
55+
) {
56+
Long userId = user.getUserId();
57+
MemoResponseDto response = memoService.deleteMemo(userId, memoId);
58+
return ResponseEntity.ok(RsData.success("메모가 삭제되었습니다.", response));
59+
}
60+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.back.domain.study.memo.dto;
2+
3+
import lombok.Getter;
4+
import lombok.NoArgsConstructor;
5+
6+
import java.time.LocalDate;
7+
8+
@Getter
9+
@NoArgsConstructor
10+
public class MemoRequestDto {
11+
private LocalDate date;
12+
13+
private String description;
14+
15+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.back.domain.study.memo.dto;
2+
3+
import com.back.domain.study.memo.entity.Memo;
4+
import lombok.Getter;
5+
import lombok.NoArgsConstructor;
6+
7+
import java.time.LocalDate;
8+
9+
@Getter
10+
@NoArgsConstructor
11+
public class MemoResponseDto {
12+
private Long id;
13+
private LocalDate date;
14+
private String description;
15+
16+
// 엔티티 -> DTO 변환
17+
public static MemoResponseDto from(Memo memo) {
18+
MemoResponseDto dto = new MemoResponseDto();
19+
dto.id = memo.getId();
20+
dto.date = memo.getDate();
21+
dto.description = memo.getDescription();
22+
return dto;
23+
}
24+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.back.domain.study.memo.entity;
2+
3+
import com.back.domain.user.entity.User;
4+
import com.back.global.entity.BaseEntity;
5+
import jakarta.persistence.*;
6+
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
8+
9+
import java.time.LocalDate;
10+
11+
@Entity
12+
@Getter
13+
@NoArgsConstructor
14+
public class Memo extends BaseEntity {
15+
@ManyToOne(fetch = FetchType.LAZY)
16+
@JoinColumn(name = "user_id", nullable = false)
17+
private User user;
18+
19+
@Column(nullable = false)
20+
private LocalDate date;
21+
22+
@Column(columnDefinition = "TEXT")
23+
private String description;
24+
25+
// setter 사용 안하고 메서드를 이용
26+
// 생성
27+
public static Memo create(User user, LocalDate date, String description) {
28+
Memo memo = new Memo();
29+
memo.user = user;
30+
memo.date = date;
31+
memo.description = description;
32+
return memo;
33+
}
34+
// 수정
35+
public void update(String description) {
36+
this.description = description;
37+
}
38+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.back.domain.study.memo.repository;
2+
3+
import com.back.domain.study.memo.entity.Memo;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
7+
import java.time.LocalDate;
8+
import java.util.Optional;
9+
10+
@Repository
11+
public interface MemoRepository extends JpaRepository<Memo, Long> {
12+
// 사용자의 날짜별 메모 조회
13+
Optional<Memo> findByUserIdAndDate(Long userId, LocalDate date);
14+
15+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.back.domain.study.memo.service;
2+
3+
import com.back.domain.study.memo.dto.MemoRequestDto;
4+
import com.back.domain.study.memo.dto.MemoResponseDto;
5+
import com.back.domain.study.memo.entity.Memo;
6+
import com.back.domain.study.memo.repository.MemoRepository;
7+
import com.back.domain.user.entity.User;
8+
import com.back.domain.user.repository.UserRepository;
9+
import com.back.global.exception.CustomException;
10+
import com.back.global.exception.ErrorCode;
11+
import lombok.RequiredArgsConstructor;
12+
import org.springframework.stereotype.Service;
13+
import org.springframework.transaction.annotation.Transactional;
14+
15+
import java.time.LocalDate;
16+
import java.util.Optional;
17+
18+
@Service
19+
@RequiredArgsConstructor
20+
@Transactional(readOnly = true)
21+
public class MemoService {
22+
private final MemoRepository memoRepository;
23+
private final UserRepository userRepository;
24+
25+
// ==================== 생성 및 수정 ===================
26+
// 같은 날짜에 메모가 있으면 수정, 없으면 생성
27+
@Transactional
28+
public MemoResponseDto createOrUpdateMemo(Long userId, MemoRequestDto request) {
29+
// 사용자 조회
30+
User user = userRepository.findById(userId)
31+
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
32+
33+
// 같은 날짜의 메모가 있는지 확인
34+
Optional<Memo> existingMemo = memoRepository.findByUserIdAndDate(userId, request.getDate());
35+
36+
Memo memo;
37+
if (existingMemo.isPresent()) {
38+
// 기존 메모 수정
39+
memo = existingMemo.get();
40+
memo.update(request.getDescription());
41+
} else {
42+
// 새 메모 생성
43+
memo = Memo.create(user, request.getDate(), request.getDescription());
44+
memo = memoRepository.save(memo);
45+
}
46+
47+
return MemoResponseDto.from(memo);
48+
}
49+
50+
// ==================== 조회 ===================
51+
public MemoResponseDto getMemoByDate(Long userId, LocalDate date) {
52+
// 사용자 존재 확인
53+
if (!userRepository.existsById(userId)) {
54+
throw new CustomException(ErrorCode.USER_NOT_FOUND);
55+
}
56+
57+
// 메모를 조회해서 해당 날짜에 없으면 null
58+
return memoRepository.findByUserIdAndDate(userId, date)
59+
.map(MemoResponseDto::from)
60+
.orElse(null);
61+
}
62+
63+
// ==================== 삭제 ===================
64+
@Transactional
65+
public MemoResponseDto deleteMemo(Long userId, Long memoId) {
66+
Memo memo = memoRepository.findById(memoId)
67+
.orElseThrow(() -> new CustomException(ErrorCode.MEMO_NOT_FOUND));
68+
69+
// 권한 확인
70+
if (!memo.getUser().getId().equals(userId)) {
71+
throw new CustomException(ErrorCode.FORBIDDEN);
72+
}
73+
74+
MemoResponseDto memoDto = MemoResponseDto.from(memo);
75+
76+
memoRepository.delete(memo);
77+
// 삭제된 메모 정보 반환
78+
return memoDto;
79+
}
80+
81+
}

src/main/java/com/back/global/exception/ErrorCode.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ public enum ErrorCode {
5656
// ======================== 학습 기록 관련 ========================
5757
DURATION_MISMATCH(HttpStatus.BAD_REQUEST, "RECORD_001", "받은 duration과 계산된 duration이 5초 이상 차이납니다."),
5858

59+
// ======================== 알림 관련 ========================
60+
MEMO_NOT_FOUND(HttpStatus.NOT_FOUND, "MEMO_001", "존재하지 않는 메모입니다."),
61+
5962
// ======================== 알림 관련 ========================
6063
NOTIFICATION_NOT_FOUND(HttpStatus.NOT_FOUND, "NOTIFICATION_001", "존재하지 않는 알림입니다."),
6164
NOTIFICATION_FORBIDDEN(HttpStatus.FORBIDDEN, "NOTIFICATION_002", "알림에 대한 접근 권한이 없습니다."),

0 commit comments

Comments
 (0)