diff --git a/build.gradle b/build.gradle index 6a4b2cf..f4894d3 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-security' + // implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' diff --git a/src/main/java/com/example/fixlog/controller/follow/FollowController.java b/src/main/java/com/example/FixLog/controller/FollowController.java similarity index 95% rename from src/main/java/com/example/fixlog/controller/follow/FollowController.java rename to src/main/java/com/example/FixLog/controller/FollowController.java index f9b3cf4..a078870 100644 --- a/src/main/java/com/example/fixlog/controller/follow/FollowController.java +++ b/src/main/java/com/example/FixLog/controller/FollowController.java @@ -1,4 +1,4 @@ -package com.example.fixlog.controller.follow; +package com.example.fixlog.controller; import com.example.fixlog.dto.Response; import com.example.fixlog.dto.follow.request.FollowRequestDto; @@ -6,7 +6,7 @@ import com.example.fixlog.dto.follow.response.FollowResponseDto; import com.example.fixlog.dto.follow.response.FollowerListResponseDto; import com.example.fixlog.dto.follow.response.FollowingListResponseDto; -import com.example.fixlog.service.follow.FollowService; +import com.example.fixlog.service.FollowService; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; diff --git a/src/main/java/com/example/FixLog/controller/MemberController.java b/src/main/java/com/example/FixLog/controller/MemberController.java new file mode 100644 index 0000000..ef580e2 --- /dev/null +++ b/src/main/java/com/example/FixLog/controller/MemberController.java @@ -0,0 +1,38 @@ +//package com.example.fixlog.controller; +// +// +//import com.example.fixlog.dto.Response; +//import com.example.fixlog.dto.member.SignupRequestDto; +//import com.example.fixlog.dto.member.DuplicateCheckResponseDto; +//import com.example.fixlog.service.MemberService; +//import lombok.RequiredArgsConstructor; +//import org.springframework.http.ResponseEntity; +//import org.springframework.web.bind.annotation.*; +// +//@RestController +//@RequestMapping("/api/members") +//@RequiredArgsConstructor +//public class MemberController { +// +// private final MemberService memberService; +// +// @PostMapping("/signup") +// public ResponseEntity> signup(@RequestBody SignupRequestDto request) { +// memberService.signup(request); +// return ResponseEntity.ok(Response.success("회원가입이 완료되었습니다.", null)); +// } +// +// @GetMapping("/check-email") +// public ResponseEntity> checkEmail(@RequestParam String email) { +// boolean exists = memberService.isEmailDuplicated(email); +// String msg = exists ? "이미 사용 중인 이메일입니다." : "사용 가능한 이메일입니다."; +// return ResponseEntity.ok(Response.success(msg, new DuplicateCheckResponseDto(exists))); +// } +// +// @GetMapping("/check-nickname") +// public ResponseEntity> checkNickname(@RequestParam String nickname) { +// boolean exists = memberService.isNicknameDuplicated(nickname); +// String msg = exists ? "이미 사용 중인 닉네임입니다." : "사용 가능한 닉네임입니다."; +// return ResponseEntity.ok(Response.success(msg, new DuplicateCheckResponseDto(exists))); +// } +//} diff --git a/src/main/java/com/example/fixlog/controller/post/PostController.java b/src/main/java/com/example/FixLog/controller/PostController.java similarity index 97% rename from src/main/java/com/example/fixlog/controller/post/PostController.java rename to src/main/java/com/example/FixLog/controller/PostController.java index 251e98a..ac310f7 100644 --- a/src/main/java/com/example/fixlog/controller/post/PostController.java +++ b/src/main/java/com/example/FixLog/controller/PostController.java @@ -1,4 +1,4 @@ -package com.example.fixlog.controller.post; +package com.example.fixlog.controller; import com.example.fixlog.dto.UserIdDto; import com.example.fixlog.dto.post.PostRequestDto; diff --git a/src/main/java/com/example/FixLog/domain/bookmark/BookmarkFolder.java b/src/main/java/com/example/FixLog/domain/bookmark/BookmarkFolder.java index 27ab427..f1e153c 100644 --- a/src/main/java/com/example/FixLog/domain/bookmark/BookmarkFolder.java +++ b/src/main/java/com/example/FixLog/domain/bookmark/BookmarkFolder.java @@ -1,6 +1,5 @@ package com.example.fixlog.domain.bookmark; - import com.example.fixlog.domain.member.Member; import jakarta.persistence.*; import lombok.AccessLevel; @@ -14,18 +13,24 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class BookmarkFolder { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "folderId") - private Long id; + @Column(name = "folder_id") + private Long folderId; - @Column(name = "folderName", nullable = false) - private String name; // 폴더 이름 + @Column(name = "folder_name", nullable = false) + private String folderName; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userId", nullable = false) - private Member owner; + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private Member userId; - @OneToMany(mappedBy = "folder", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(mappedBy = "folderId", cascade = CascadeType.ALL, orphanRemoval = true) private List bookmarks = new ArrayList<>(); + + public BookmarkFolder(Member userId){ + this.userId = userId; + this.folderName = "default folder"; + } } diff --git a/src/main/java/com/example/FixLog/mock/TagTestDataInitializer.java b/src/main/java/com/example/FixLog/mock/TagTestDataInitializer.java new file mode 100644 index 0000000..54a975a --- /dev/null +++ b/src/main/java/com/example/FixLog/mock/TagTestDataInitializer.java @@ -0,0 +1,31 @@ +package com.example.fixlog.mock; + +import com.example.fixlog.domain.tag.Tag; +import com.example.fixlog.domain.tag.TagCategory; +import com.example.fixlog.repository.tag.TagRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.util.List; + +import static com.example.fixlog.domain.tag.TagCategory.*; + +@Component +@RequiredArgsConstructor +public class TagTestDataInitializer implements CommandLineRunner { + + private final TagRepository tagRepository; + + @Override + public void run(String... args) { + if (tagRepository.count() == 0) { + Tag tag1 = Tag.of(MAJOR_CATEGORY, "101"); + Tag tag2 = Tag.of(MAJOR_CATEGORY, "101"); + Tag tag3 = Tag.of(MIDDLE_CATEGORY, "201"); + Tag tag4 = Tag.of(MINOR_CATEGORY, "301"); + tagRepository.saveAll(List.of(tag1, tag2, tag3, tag4)); + System.out.println("임시 태그 4개 삽입 완료"); + } + } +} diff --git a/src/main/java/com/example/FixLog/repository/bookmark/BookmarkFolderRepository.java b/src/main/java/com/example/FixLog/repository/bookmark/BookmarkFolderRepository.java new file mode 100644 index 0000000..a74352b --- /dev/null +++ b/src/main/java/com/example/FixLog/repository/bookmark/BookmarkFolderRepository.java @@ -0,0 +1,9 @@ +package com.example.fixlog.repository.bookmark; + +import com.example.fixlog.domain.bookmark.BookmarkFolder; +import com.example.fixlog.domain.member.Member; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface BookmarkFolderRepository extends JpaRepository { + BookmarkFolder findByUserId(Member userId); +} diff --git a/src/main/java/com/example/FixLog/repository/post/PostTagRepository.java b/src/main/java/com/example/FixLog/repository/post/PostTagRepository.java new file mode 100644 index 0000000..91a94e4 --- /dev/null +++ b/src/main/java/com/example/FixLog/repository/post/PostTagRepository.java @@ -0,0 +1,7 @@ +package com.example.fixlog.repository.post; + +import com.example.fixlog.domain.post.PostTag; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface PostTagRepository extends JpaRepository { +} diff --git a/src/main/java/com/example/FixLog/repository/tag/TagRepository.java b/src/main/java/com/example/FixLog/repository/tag/TagRepository.java new file mode 100644 index 0000000..97701ed --- /dev/null +++ b/src/main/java/com/example/FixLog/repository/tag/TagRepository.java @@ -0,0 +1,7 @@ +package com.example.fixlog.repository.tag; + +import com.example.fixlog.domain.tag.Tag; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TagRepository extends JpaRepository { +} diff --git a/src/main/java/com/example/fixlog/service/follow/FollowService.java b/src/main/java/com/example/FixLog/service/FollowService.java similarity index 70% rename from src/main/java/com/example/fixlog/service/follow/FollowService.java rename to src/main/java/com/example/FixLog/service/FollowService.java index 7011d08..16d4c2f 100644 --- a/src/main/java/com/example/fixlog/service/follow/FollowService.java +++ b/src/main/java/com/example/FixLog/service/FollowService.java @@ -1,4 +1,4 @@ -package com.example.fixlog.service.follow; +package com.example.fixlog.service; import com.example.fixlog.dto.follow.response.FollowResponseDto; import com.example.fixlog.dto.follow.response.FollowerListResponseDto; @@ -26,42 +26,42 @@ public class FollowService { @Transactional public FollowResponseDto follow(String requesterEmail, Long targetMemberId){ Member follower = memberRepository.findByEmail(requesterEmail) - .orElseThrow(() -> new CustomException(ErrorCode.MEMBEREMAIL_NOT_FOUNT)); + .orElseThrow(() -> new CustomException(ErrorCode.USER_EMAIL_NOT_FOUNT)); Member following = memberRepository.findById(targetMemberId) - .orElseThrow(() -> new CustomException(ErrorCode.MEMBERID_NOT_FOUND)); + .orElseThrow(() -> new CustomException(ErrorCode.USER_ID_NOT_FOUND)); // 자기 자신은 팔로우 불가 - if (follower.getId().equals(following.getId())) { - throw new CustomException(ErrorCode.CANNOT_FOLLOW_SELF); + if (follower.getUserId().equals(following.getUserId())) { + throw new CustomException(ErrorCode.SELF_FOLLOW_NOT_ALLOWED); } // 중복 팔로우 방지 - if (followRepository.existsByFollowerAndFollowing(follower, following)) { + if (followRepository.existsByFollowerIdAndFollowingId(follower, following)) { throw new CustomException(ErrorCode.ALREADY_FOLLOWING); } Follow follow = new Follow(follower, following); Follow saved = followRepository.save(follow); - return new FollowResponseDto(saved.getId(), following.getId(), following.getNickname()); + return new FollowResponseDto(saved.getFollowId(), following.getUserId(), following.getNickname()); } // 언팔로우하기 @Transactional public void unfollow(String requesterEmail, Long targetMemberId) { Member follower = memberRepository.findByEmail(requesterEmail) - .orElseThrow(() -> new CustomException(ErrorCode.MEMBEREMAIL_NOT_FOUNT)); + .orElseThrow(() -> new CustomException(ErrorCode.USER_EMAIL_NOT_FOUNT)); Member following = memberRepository.findById(targetMemberId) - .orElseThrow(() -> new CustomException(ErrorCode.MEMBERID_NOT_FOUND)); + .orElseThrow(() -> new CustomException(ErrorCode.USER_ID_NOT_FOUND)); // 자기 자신은 팔로우 불가 - if (follower.getId().equals(following.getId())) { - throw new CustomException(ErrorCode.CANNOT_FOLLOW_SELF); + if (follower.getUserId().equals(following.getUserId())) { + throw new CustomException(ErrorCode.SELF_FOLLOW_NOT_ALLOWED); } - Follow follow = followRepository.findByFollowerAndFollowing(follower, following) - .orElseThrow(() -> new CustomException(ErrorCode.CANNOT_UNFOLLOW_SELF)); + Follow follow = followRepository.findByFollowerIdAndFollowingId(follower, following) + .orElseThrow(() -> new CustomException(ErrorCode.SELF_UNFOLLOW_NOT_ALLOWED)); followRepository.delete(follow); } @@ -70,15 +70,15 @@ public void unfollow(String requesterEmail, Long targetMemberId) { @Transactional(readOnly = true) public List getMyFollowers(String requesterEmail) { Member me = memberRepository.findByEmail(requesterEmail) - .orElseThrow(() -> new CustomException(ErrorCode.MEMBEREMAIL_NOT_FOUNT)); + .orElseThrow(() -> new CustomException(ErrorCode.USER_EMAIL_NOT_FOUNT)); - List follows = followRepository.findByFollowing(me); + List follows = followRepository.findByFollowingId(me); return follows.stream() .map(follow -> new FollowerListResponseDto( - follow.getId(), - follow.getFollower().getId(), - follow.getFollower().getNickname() + follow.getFollowId(), + follow.getFollowerId().getUserId(), + follow.getFollowerId().getNickname() )) .toList(); } @@ -87,15 +87,15 @@ public List getMyFollowers(String requesterEmail) { @Transactional(readOnly = true) public List getMyFollowings(String requesterEmail) { Member me = memberRepository.findByEmail(requesterEmail) - .orElseThrow(() -> new CustomException(ErrorCode.MEMBEREMAIL_NOT_FOUNT)); + .orElseThrow(() -> new CustomException(ErrorCode.USER_EMAIL_NOT_FOUNT)); - List follows = followRepository.findByFollower(me); + List follows = followRepository.findByFollowerId(me); return follows.stream() .map(follow -> new FollowingListResponseDto( - follow.getId(), - follow.getFollowing().getId(), - follow.getFollowing().getNickname() + follow.getFollowId(), + follow.getFollowingId().getUserId(), + follow.getFollowingId().getNickname() )) .toList(); } diff --git a/src/main/java/com/example/FixLog/service/MemberService.java b/src/main/java/com/example/FixLog/service/MemberService.java new file mode 100644 index 0000000..d50f3e1 --- /dev/null +++ b/src/main/java/com/example/FixLog/service/MemberService.java @@ -0,0 +1,56 @@ +//package com.example.fixlog.service; +// +//import com.example.fixlog.domain.bookmark.BookmarkFolder; +//import com.example.fixlog.domain.member.Member; +//import com.example.fixlog.domain.member.SocialType; +//import com.example.fixlog.dto.member.SignupRequestDto; +//import com.example.fixlog.exception.CustomException; +//import com.example.fixlog.exception.ErrorCode; +//import com.example.fixlog.repository.MemberRepository; +//import com.example.fixlog.repository.bookmark.BookmarkFolderRepository; +//import lombok.RequiredArgsConstructor; +//import org.springframework.security.crypto.password.PasswordEncoder; +//import org.springframework.stereotype.Service; +// +//@Service +//@RequiredArgsConstructor +//public class MemberService { +// +// private final MemberRepository memberRepository; +// private final PasswordEncoder passwordEncoder; +// private final BookmarkFolderRepository bookmarkFolderRepository; +// +// public void signup(SignupRequestDto request) { +// // 이메일 중복 검사 +// if (isEmailDuplicated(request.getEmail())) { +// throw new CustomException(ErrorCode.EMAIL_DUPLICATED); +// } +// +// // 닉네임 중복 검사 +// if (isNicknameDuplicated(request.getNickname())) { +// throw new CustomException(ErrorCode.NICKNAME_DUPLICATED); +// } +// +// // 문제 없으면 저장 +// Member member = Member.of( +// request.getEmail(), +// passwordEncoder.encode(request.getPassword()), +// request.getNickname(), +// SocialType.EMAIL +// ); +// +// // 기본 폴더 생성 +// BookmarkFolder newFolder = new BookmarkFolder(member); +// bookmarkFolderRepository.save(newFolder); +// +// memberRepository.save(member); +// } +// +// public boolean isEmailDuplicated(String email) { +// return memberRepository.findByEmail(email).isPresent(); +// } +// +// public boolean isNicknameDuplicated(String nickname) { +// return memberRepository.findByNickname(nickname).isPresent(); +// } +//} diff --git a/src/main/java/com/example/fixlog/config/SecurityConfig.java b/src/main/java/com/example/fixlog/config/SecurityConfig.java index 2c7be84..44bf58b 100644 --- a/src/main/java/com/example/fixlog/config/SecurityConfig.java +++ b/src/main/java/com/example/fixlog/config/SecurityConfig.java @@ -1,31 +1,31 @@ -package com.example.fixlog.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; - -@Configuration -public class SecurityConfig { - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http - .csrf(csrf -> csrf.disable()) - .authorizeHttpRequests(auth -> auth - .requestMatchers(HttpMethod.POST, "/api/members/signup").permitAll() - .requestMatchers(HttpMethod.GET, "/api/members/check-email").permitAll() - .requestMatchers(HttpMethod.GET, "/api/members/check-nickname").permitAll() - .anyRequest().authenticated() - ); - return http.build(); - } - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } -} +//package com.example.fixlog.config; +// +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.http.HttpMethod; +//import org.springframework.security.config.annotation.web.builders.HttpSecurity; +//import org.springframework.security.web.SecurityFilterChain; +//import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +//import org.springframework.security.crypto.password.PasswordEncoder; +// +//@Configuration +//public class SecurityConfig { +// +// @Bean +// public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { +// http +// .csrf(csrf -> csrf.disable()) +// .authorizeHttpRequests(auth -> auth +// .requestMatchers(HttpMethod.POST, "/api/members/signup").permitAll() +// .requestMatchers(HttpMethod.GET, "/api/members/check-email").permitAll() +// .requestMatchers(HttpMethod.GET, "/api/members/check-nickname").permitAll() +// .anyRequest().authenticated() +// ); +// return http.build(); +// } +// +// @Bean +// public PasswordEncoder passwordEncoder() { +// return new BCryptPasswordEncoder(); +// } +//} diff --git a/src/main/java/com/example/fixlog/controller/member/MemberController.java b/src/main/java/com/example/fixlog/controller/member/MemberController.java deleted file mode 100644 index cf01613..0000000 --- a/src/main/java/com/example/fixlog/controller/member/MemberController.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.example.fixlog.controller.member; - - -import com.example.fixlog.dto.Response; -import com.example.fixlog.dto.member.SignupRequestDto; -import com.example.fixlog.dto.member.DuplicateCheckResponseDto; -import com.example.fixlog.service.member.MemberService; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/api/members") -@RequiredArgsConstructor -public class MemberController { - - private final MemberService memberService; - - @PostMapping("/signup") - public ResponseEntity> signup(@RequestBody SignupRequestDto request) { - memberService.signup(request); - return ResponseEntity.ok(Response.success("회원가입이 완료되었습니다.", null)); - } - - @GetMapping("/check-email") - public ResponseEntity> checkEmail(@RequestParam String email) { - boolean exists = memberService.isEmailDuplicated(email); - String msg = exists ? "이미 사용 중인 이메일입니다." : "사용 가능한 이메일입니다."; - return ResponseEntity.ok(Response.success(msg, new DuplicateCheckResponseDto(exists))); - } - - @GetMapping("/check-nickname") - public ResponseEntity> checkNickname(@RequestParam String nickname) { - boolean exists = memberService.isNicknameDuplicated(nickname); - String msg = exists ? "이미 사용 중인 닉네임입니다." : "사용 가능한 닉네임입니다."; - return ResponseEntity.ok(Response.success(msg, new DuplicateCheckResponseDto(exists))); - } -} diff --git a/src/main/java/com/example/fixlog/domain/bookmark/Bookmark.java b/src/main/java/com/example/fixlog/domain/bookmark/Bookmark.java index 2119ef9..37c1e3f 100644 --- a/src/main/java/com/example/fixlog/domain/bookmark/Bookmark.java +++ b/src/main/java/com/example/fixlog/domain/bookmark/Bookmark.java @@ -1,6 +1,5 @@ package com.example.fixlog.domain.bookmark; -import com.example.fixlog.domain.member.Member; import com.example.fixlog.domain.post.Post; import jakarta.persistence.*; @@ -8,7 +7,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; - @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -16,22 +14,22 @@ public class Bookmark { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name="bookmarkId") - private Long id; + @Column(name="bookmark_id") + private Long bookmarkId; @ManyToOne - @JoinColumn(name = "postId") - private Post post; + @JoinColumn(name = "post_id") + private Post postId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "folderId") - private BookmarkFolder folder; + @JoinColumn(name = "folder_id") + private BookmarkFolder folderId; private boolean isMarked; - public Bookmark(Member userId, Post postId){ - this.member = userId; - this.post = postId; + public Bookmark(BookmarkFolder folderId, Post postId){ + this.folderId = folderId; + this.postId = postId; } public void ToggleBookmark(boolean state){ diff --git a/src/main/java/com/example/fixlog/domain/follow/Follow.java b/src/main/java/com/example/fixlog/domain/follow/Follow.java index 01a3a8f..7b2b9cf 100644 --- a/src/main/java/com/example/fixlog/domain/follow/Follow.java +++ b/src/main/java/com/example/fixlog/domain/follow/Follow.java @@ -13,19 +13,19 @@ public class Follow { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "followId") - private Long id; + @Column(name = "follow_id") + private Long followId; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "followerId", nullable = false) - private Member follower; + private Member followerId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "followingId", nullable = false) - private Member following; + @JoinColumn(name = "following_id", nullable = false) + private Member followingId; - public Follow(Member follower, Member following) { - this.follower = follower; - this.following = following; + public Follow(Member followerId, Member followingId) { + this.followerId = followerId; + this.followingId = followingId; } } diff --git a/src/main/java/com/example/fixlog/domain/fork/Fork.java b/src/main/java/com/example/fixlog/domain/fork/Fork.java index aa0f43b..fba9343 100644 --- a/src/main/java/com/example/fixlog/domain/fork/Fork.java +++ b/src/main/java/com/example/fixlog/domain/fork/Fork.java @@ -14,18 +14,18 @@ public class Fork { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "forkId") - private Long id; + @Column(name = "fork_id") + private Long forkId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userId", nullable = false) - private Member member; + @JoinColumn(name = "user_id", nullable = false) + private Member userId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "postId", nullable = false) - private Post originalPost; + @JoinColumn(name = "post_id", nullable = false) + private Post originalPostId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "forkPostId", nullable = false) - private Post forkedPost; + @JoinColumn(name = "fork_post_id", nullable = false) + private Post forkedPostId; } diff --git a/src/main/java/com/example/fixlog/domain/like/PostLike.java b/src/main/java/com/example/fixlog/domain/like/PostLike.java index 8077ae0..0959c5f 100644 --- a/src/main/java/com/example/fixlog/domain/like/PostLike.java +++ b/src/main/java/com/example/fixlog/domain/like/PostLike.java @@ -14,22 +14,22 @@ public class PostLike { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "likeId", nullable = false) - private Long id; + @Column(name = "like_id", nullable = false) + private Long likeId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userId", nullable = false) - private Member member; + @JoinColumn(name = "user_id", nullable = false) + private Member userId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "postId", nullable = false) - private Post post; + @JoinColumn(name = "post_id", nullable = false) + private Post postId; private boolean isLiked; public PostLike(Member userId, Post postId){ - this.member = userId; - this.post = postId; + this.userId = userId; + this.postId = postId; this.isLiked = true; // 객체 생성 시 true } diff --git a/src/main/java/com/example/fixlog/domain/member/Member.java b/src/main/java/com/example/fixlog/domain/member/Member.java index 810d65d..ce04d4a 100644 --- a/src/main/java/com/example/fixlog/domain/member/Member.java +++ b/src/main/java/com/example/fixlog/domain/member/Member.java @@ -22,8 +22,8 @@ public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "userId") - private Long id; + @Column(name = "user_id") + private Long userId; @Column(nullable = false) private String email; @@ -56,12 +56,15 @@ public class Member { @Column(length = 200) private String bio; - @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(mappedBy = "userId", cascade = CascadeType.ALL, orphanRemoval = true) private List posts = new ArrayList<>(); - // 북마크 폴더 - @OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, orphanRemoval = true) - private List bookmarkFolders = new ArrayList<>(); + // 북마크 폴더 + @OneToOne(mappedBy = "userId", cascade = CascadeType.ALL, orphanRemoval = true) + private BookmarkFolder bookmarkFolderId; + // 우선은 계정 당 폴더 하나만 있는 걸로 생성 + // @OneToMany(mappedBy = "userId", cascade = CascadeType.ALL, orphanRemoval = true) + // private List bookmarkFolders = new ArrayList<>(); // Member 객체를 정적 팩토리 방식으로 회원가입 시에 생성하는 메서드 // Member 객체를 정적 팩토리 방식으로 생성하는 메서드 diff --git a/src/main/java/com/example/fixlog/domain/post/Post.java b/src/main/java/com/example/fixlog/domain/post/Post.java index 86c54d6..8933766 100644 --- a/src/main/java/com/example/fixlog/domain/post/Post.java +++ b/src/main/java/com/example/fixlog/domain/post/Post.java @@ -18,16 +18,19 @@ public class Post { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "postId", nullable = false) - private Long id; + @Column(name = "post_id", nullable = false) + private Long postId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userId", nullable = false) - private Member member; + @JoinColumn(name = "user_id", nullable = false) + private Member userId; @Column(length = 100, nullable = false) private String postTitle; + @Column(columnDefinition = "TEXT") + private String coverImage; + @Lob // 텍스트가 길어질 수 있는 필드에 사용 @Column(nullable = false) private String problem; @@ -55,7 +58,6 @@ public class Post { private String referenceLink; @Lob - @Column(columnDefinition = "TEXT") private String extraContent; @Column(nullable = false) @@ -64,20 +66,19 @@ public class Post { @Column(nullable = false) private LocalDateTime editedAt; - @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) - private List postImages = new ArrayList<>(); - // 북마크와의 관계 - @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(mappedBy = "postId", cascade = CascadeType.ALL, orphanRemoval = true) private List bookmarks = new ArrayList<>(); - // Todo : tags 도 postImage 처럼 join 해와야 하는 거 아닌가? + @OneToMany(mappedBy = "postId", cascade = CascadeType.ALL, orphanRemoval = true) + private List postTags = new ArrayList<>(); - public Post(Member userId, String postTitle, String problem, String errorMessage, String environment, - String reproduceCode, String solutionCode, String causeAnalysis, String referenceLink, - String extraContent, LocalDateTime createdAt, LocalDateTime editedAt){ - this.member = userId; + public Post(Member userId, String postTitle, String coverImage, String problem, String errorMessage, + String environment, String reproduceCode, String solutionCode, String causeAnalysis, + String referenceLink, String extraContent, LocalDateTime createdAt, LocalDateTime editedAt){ + this.userId = userId; this.postTitle = postTitle; + this.coverImage = coverImage; this.problem = problem; this.errorMessage = errorMessage; this.environment = environment; diff --git a/src/main/java/com/example/fixlog/domain/post/PostImage.java b/src/main/java/com/example/fixlog/domain/post/PostImage.java deleted file mode 100644 index 3c982b0..0000000 --- a/src/main/java/com/example/fixlog/domain/post/PostImage.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.example.fixlog.domain.post; - -import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Entity -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class PostImage { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "postImageId",nullable = false) - private Long id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "postId", nullable = false) - private Post post; - - @Column(columnDefinition = "TEXT", nullable = false) - private String postImageUrl; -} diff --git a/src/main/java/com/example/fixlog/domain/post/PostTag.java b/src/main/java/com/example/fixlog/domain/post/PostTag.java index b3dc0ec..a45bbc9 100644 --- a/src/main/java/com/example/fixlog/domain/post/PostTag.java +++ b/src/main/java/com/example/fixlog/domain/post/PostTag.java @@ -13,14 +13,19 @@ public class PostTag { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "postTagId",nullable = false) - private Long id; + @Column(name = "post_tag_id",nullable = false) + private Long postTagId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "postId", nullable = false) - private Post post; + @JoinColumn(name = "post_id", nullable = false) + private Post postId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "tagId", nullable = false) - private Tag tag; + @JoinColumn(name = "tag_id", nullable = false) + private Tag tagId; + + public PostTag(Post postId, Tag tagId){ + this.postId = postId; + this.tagId = tagId; + } } diff --git a/src/main/java/com/example/fixlog/domain/tag/Tag.java b/src/main/java/com/example/fixlog/domain/tag/Tag.java index f48360a..422fe09 100644 --- a/src/main/java/com/example/fixlog/domain/tag/Tag.java +++ b/src/main/java/com/example/fixlog/domain/tag/Tag.java @@ -1,5 +1,7 @@ package com.example.fixlog.domain.tag; +import com.example.fixlog.domain.member.Member; +import com.example.fixlog.domain.member.SocialType; import jakarta.persistence.*; import lombok.AccessLevel; import lombok.Getter; @@ -12,12 +14,19 @@ public class Tag { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "tagId",nullable = false) - private Long id; + @Column(name = "tag_id",nullable = false) + private Long tagId; @Enumerated(EnumType.STRING) private TagCategory tagCategory; @Column(length = 20, nullable = false) - private String tag_name; + private String tagName; + + public static Tag of(TagCategory tagCategory, String tagName) { + Tag tag = new Tag(); + tag.tagCategory = tagCategory; + tag.tagName = tagName; + return tag; + } } \ No newline at end of file diff --git a/src/main/java/com/example/fixlog/domain/tag/TagCategory.java b/src/main/java/com/example/fixlog/domain/tag/TagCategory.java index ba9964d..2f5c46d 100644 --- a/src/main/java/com/example/fixlog/domain/tag/TagCategory.java +++ b/src/main/java/com/example/fixlog/domain/tag/TagCategory.java @@ -1,7 +1,20 @@ package com.example.fixlog.domain.tag; +import lombok.Getter; + +@Getter public enum TagCategory { - STYLE, - CONCEPT, - ETC + MAJOR_CATEGORY("대분류"), + MIDDLE_CATEGORY("중분류"), + MINOR_CATEGORY("소분류"); + + private final String displayName; + + TagCategory(String displayName) { + this.displayName = displayName; + } + + public String getDisplayName() { + return displayName; + } } diff --git a/src/main/java/com/example/fixlog/dto/post/PostRequestDto.java b/src/main/java/com/example/fixlog/dto/post/PostRequestDto.java index a159bdc..364edfd 100644 --- a/src/main/java/com/example/fixlog/dto/post/PostRequestDto.java +++ b/src/main/java/com/example/fixlog/dto/post/PostRequestDto.java @@ -2,10 +2,13 @@ import lombok.Getter; +import java.util.List; + @Getter public class PostRequestDto { private Long userId; // Fixme : 회원가입 구현 후 삭제 예정 private String postTitle; + private String coverImageUrl; private String problem; private String errorMessage; private String environment; @@ -15,6 +18,8 @@ public class PostRequestDto { private String referenceLink; private String extraContent; + private List tags; + // private List postImageUrl; // private List tags; } diff --git a/src/main/java/com/example/fixlog/exception/ErrorCode.java b/src/main/java/com/example/fixlog/exception/ErrorCode.java index 2759866..e760904 100644 --- a/src/main/java/com/example/fixlog/exception/ErrorCode.java +++ b/src/main/java/com/example/fixlog/exception/ErrorCode.java @@ -7,16 +7,16 @@ @Getter @AllArgsConstructor public enum ErrorCode { - MEMBERID_NOT_FOUND(HttpStatus.NOT_FOUND, "회원 ID를 찾을 수 없습니다"), - MEMBEREMAIL_NOT_FOUNT(HttpStatus.NOT_FOUND, "회원 이메일을 찾을 수 없습니다."), - CANNOT_FOLLOW_SELF(HttpStatus.BAD_REQUEST, "자기 자신은 팔로우할 수 없습니다"), - CANNOT_UNFOLLOW_SELF(HttpStatus.BAD_REQUEST, "자기 자신은 언팔로우할 수 없습니다"), - ALREADY_FOLLOWING(HttpStatus.CONFLICT, "이미 팔로우 중입니다"), - FOLLOW_NOT_FOUND(HttpStatus.NOT_FOUND, "팔로우 관계가 존재하지 않습니다"), + USER_ID_NOT_FOUND(HttpStatus.NOT_FOUND,"존재하지 않는 사용자 아이디입니다."), + USER_EMAIL_NOT_FOUNT(HttpStatus.NOT_FOUND, "회원 이메일을 찾을 수 없습니다."), EMAIL_DUPLICATED(HttpStatus.CONFLICT, "중복된 이메일입니다"), NICKNAME_DUPLICATED(HttpStatus.CONFLICT, "중복된 닉네임입니다"), - USER_ID_NOT_FOUND(HttpStatus.NOT_FOUND,"존재하지 않는 사용자 아이디입니다."), - POST_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 게시글입니다."); + SELF_FOLLOW_NOT_ALLOWED(HttpStatus.BAD_REQUEST, "자기 자신은 팔로우할 수 없습니다"), + SELF_UNFOLLOW_NOT_ALLOWED(HttpStatus.BAD_REQUEST, "자기 자신은 언팔로우할 수 없습니다"), + ALREADY_FOLLOWING(HttpStatus.CONFLICT, "이미 팔로우 중입니다"), + FOLLOW_NOT_FOUND(HttpStatus.NOT_FOUND, "팔로우 관계가 존재하지 않습니다"), + POST_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 게시글입니다."), + TAG_NOT_FOUND(HttpStatus.NOT_FOUND, "없는 태그 번호입니다."); private final HttpStatus status; private final String message; diff --git a/src/main/java/com/example/fixlog/mock/MemberTestDataInitializer.java b/src/main/java/com/example/fixlog/mock/MemberTestDataInitializer.java index 39470b9..deef082 100644 --- a/src/main/java/com/example/fixlog/mock/MemberTestDataInitializer.java +++ b/src/main/java/com/example/fixlog/mock/MemberTestDataInitializer.java @@ -1,6 +1,8 @@ package com.example.fixlog.mock; +import com.example.fixlog.domain.bookmark.BookmarkFolder; import com.example.fixlog.repository.MemberRepository; +import com.example.fixlog.repository.bookmark.BookmarkFolderRepository; import lombok.RequiredArgsConstructor; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @@ -14,6 +16,7 @@ public class MemberTestDataInitializer implements CommandLineRunner { private final MemberRepository memberRepository; + private final BookmarkFolderRepository bookmarkFolderRepository; @Override public void run(String... args) { @@ -21,6 +24,11 @@ public void run(String... args) { Member member1 = Member.of("test1@example.com", "1234", "가나다", SocialType.EMAIL); Member member2 = Member.of("test2@example.com", "1234", "라마바", SocialType.EMAIL); memberRepository.saveAll(List.of(member1, member2)); + + BookmarkFolder folder1 = new BookmarkFolder(member1); + BookmarkFolder folder2 = new BookmarkFolder(member2); + bookmarkFolderRepository.saveAll(List.of(folder1, folder2)); + System.out.println("테스트용 멤버 2명 삽입 완료"); } } diff --git a/src/main/java/com/example/fixlog/repository/bookmark/BookmarkRepository.java b/src/main/java/com/example/fixlog/repository/bookmark/BookmarkRepository.java index 304f00b..703a942 100644 --- a/src/main/java/com/example/fixlog/repository/bookmark/BookmarkRepository.java +++ b/src/main/java/com/example/fixlog/repository/bookmark/BookmarkRepository.java @@ -1,12 +1,12 @@ package com.example.fixlog.repository.bookmark; import com.example.fixlog.domain.bookmark.Bookmark; -import com.example.fixlog.domain.member.Member; +import com.example.fixlog.domain.bookmark.BookmarkFolder; import com.example.fixlog.domain.post.Post; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; public interface BookmarkRepository extends JpaRepository { - Optional findByMemberAndPost(Member userId, Post postId); + Optional findByFolderIdAndPostId(BookmarkFolder folderId, Post postId); } diff --git a/src/main/java/com/example/fixlog/repository/follow/FollowRepository.java b/src/main/java/com/example/fixlog/repository/follow/FollowRepository.java index f87cde3..63fe3ae 100644 --- a/src/main/java/com/example/fixlog/repository/follow/FollowRepository.java +++ b/src/main/java/com/example/fixlog/repository/follow/FollowRepository.java @@ -8,8 +8,8 @@ import java.util.Optional; public interface FollowRepository extends JpaRepository { - boolean existsByFollowerAndFollowing(Member follower, Member following); // 중복 방지 - 같은 사람 다시 팔로우 - Optional findByFollowerAndFollowing(Member follower, Member following); // 팔로우 관계 조회 - List findByFollowing(Member following); // 나를 팔로우하는 사용자 조회 (팔로워들) - List findByFollower(Member follower); // 내가 팔로우하는 사용자 조회 (팔로잉들) + boolean existsByFollowerIdAndFollowingId(Member follower, Member following); // 중복 방지 - 같은 사람 다시 팔로우 + Optional findByFollowerIdAndFollowingId(Member follower, Member following); // 팔로우 관계 조회 + List findByFollowingId(Member following); // 나를 팔로우하는 사용자 조회 (팔로워들) + List findByFollowerId(Member follower); // 내가 팔로우하는 사용자 조회 (팔로잉들) } diff --git a/src/main/java/com/example/fixlog/repository/like/PostLikeRepository.java b/src/main/java/com/example/fixlog/repository/like/PostLikeRepository.java index 1714aeb..274ac3e 100644 --- a/src/main/java/com/example/fixlog/repository/like/PostLikeRepository.java +++ b/src/main/java/com/example/fixlog/repository/like/PostLikeRepository.java @@ -8,5 +8,5 @@ import java.util.Optional; public interface PostLikeRepository extends JpaRepository { - Optional findByMemberAndPost(Member userId, Post postId); + Optional findByUserIdAndPostId(Member userId, Post postId); } diff --git a/src/main/java/com/example/fixlog/service/PostService.java b/src/main/java/com/example/fixlog/service/PostService.java index 9104c69..0ccbc60 100644 --- a/src/main/java/com/example/fixlog/service/PostService.java +++ b/src/main/java/com/example/fixlog/service/PostService.java @@ -1,20 +1,27 @@ package com.example.fixlog.service; import com.example.fixlog.domain.bookmark.Bookmark; +import com.example.fixlog.domain.bookmark.BookmarkFolder; import com.example.fixlog.domain.like.PostLike; import com.example.fixlog.domain.member.Member; import com.example.fixlog.domain.post.Post; +import com.example.fixlog.domain.post.PostTag; +import com.example.fixlog.domain.tag.Tag; import com.example.fixlog.dto.UserIdDto; import com.example.fixlog.dto.post.PostRequestDto; import com.example.fixlog.exception.CustomException; import com.example.fixlog.exception.ErrorCode; import com.example.fixlog.repository.MemberRepository; +import com.example.fixlog.repository.bookmark.BookmarkFolderRepository; import com.example.fixlog.repository.bookmark.BookmarkRepository; import com.example.fixlog.repository.like.PostLikeRepository; import com.example.fixlog.repository.post.PostRepository; +import com.example.fixlog.repository.tag.TagRepository; +import jakarta.transaction.Transactional; import org.springframework.stereotype.Service; import java.time.LocalDateTime; +import java.util.List; import java.util.Optional; @Service @@ -23,24 +30,38 @@ public class PostService { private final MemberRepository memberRepository; private final PostLikeRepository postLikeRepository; private final BookmarkRepository bookmarkRepository; + private final TagRepository tagRepository; + private final BookmarkFolderRepository bookmarkFolderRepository; public PostService(PostRepository postRepository, MemberRepository memberRepository, - PostLikeRepository postLikeRepository, BookmarkRepository bookmarkRepository){ + PostLikeRepository postLikeRepository, BookmarkRepository bookmarkRepository, + TagRepository tagRepository, BookmarkFolderRepository bookmarkFolderRepository){ this.postRepository = postRepository; this.memberRepository = memberRepository; this.postLikeRepository = postLikeRepository; this.bookmarkRepository = bookmarkRepository; + this.tagRepository = tagRepository; + this.bookmarkFolderRepository = bookmarkFolderRepository; } // 게시글 생성하기 + @Transactional public void createPost(PostRequestDto postRequestDto){ Long userIdInput = postRequestDto.getUserId(); Member userId = memberRepository.findById(userIdInput) .orElseThrow(() -> new CustomException(ErrorCode.USER_ID_NOT_FOUND)); + String coverImageUrl = postRequestDto.getCoverImageUrl(); + if (coverImageUrl == null || coverImageUrl.isBlank()) + coverImageUrl = "url"; + + // Todo : 북마크 카테고리별로 선택 제한 두기 + + // 게시글 발행 Post newPost = new Post( userId, postRequestDto.getPostTitle(), + coverImageUrl, postRequestDto.getProblem(), postRequestDto.getErrorMessage(), postRequestDto.getEnvironment(), @@ -51,7 +72,18 @@ public void createPost(PostRequestDto postRequestDto){ postRequestDto.getExtraContent(), LocalDateTime.now(), LocalDateTime.now() - ); postRepository.save(newPost); + ); + + // 태그 저장 + List tagIds = postRequestDto.getTags(); // 이제 Long ID 목록임 + for (Long tagId : tagIds) { + Tag tag = tagRepository.findById(tagId) + .orElseThrow(() -> new CustomException(ErrorCode.TAG_NOT_FOUND)); + PostTag postTag = new PostTag(newPost, tag); + newPost.getPostTags().add(postTag); + } + + postRepository.save(newPost); } // 게시글 조회하기 @@ -68,7 +100,7 @@ public void togglePostLike(Long postIdInput, UserIdDto userIdDto){ Post postId = postRepository.findById(postIdInput) .orElseThrow(() -> new CustomException(ErrorCode.POST_NOT_FOUND)); - Optional optionalLike = postLikeRepository.findByMemberAndPost(userId, postId); + Optional optionalLike = postLikeRepository.findByUserIdAndPostId(userId, postId); if (optionalLike.isEmpty()){ // 객체 없는 경우 PostLike newLike = new PostLike(userId, postId); @@ -90,10 +122,11 @@ public void toggleBookmark(Long postIdInput, UserIdDto userIdDto){ Post postId = postRepository.findById(postIdInput) .orElseThrow(() -> new CustomException(ErrorCode.POST_NOT_FOUND)); - Optional optionalBookmark = bookmarkRepository.findByMemberAndPost(userId, postId); + BookmarkFolder folderId = bookmarkFolderRepository.findByUserId(userId); // 이 코드는 폴더가 하나일 때만 적용됨 + Optional optionalBookmark = bookmarkRepository.findByFolderIdAndPostId(folderId, postId); if (optionalBookmark.isEmpty()){ // 객체 없는 경우 - Bookmark newBookmark = new Bookmark(userId, postId); + Bookmark newBookmark = new Bookmark(folderId, postId); bookmarkRepository.save(newBookmark); } else { // 객체 있는 경우 Bookmark bookmark = optionalBookmark.get(); diff --git a/src/main/java/com/example/fixlog/service/member/MemberService.java b/src/main/java/com/example/fixlog/service/member/MemberService.java deleted file mode 100644 index 12f5e88..0000000 --- a/src/main/java/com/example/fixlog/service/member/MemberService.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.example.fixlog.service.member; - -import com.example.fixlog.domain.member.Member; -import com.example.fixlog.domain.member.SocialType; -import com.example.fixlog.dto.member.SignupRequestDto; -import com.example.fixlog.exception.CustomException; -import com.example.fixlog.exception.ErrorCode; -import com.example.fixlog.repository.MemberRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class MemberService { - - private final MemberRepository memberRepository; - private final PasswordEncoder passwordEncoder; - - public void signup(SignupRequestDto request) { - // 이메일 중복 검사 - if (isEmailDuplicated(request.getEmail())) { - throw new CustomException(ErrorCode.EMAIL_DUPLICATED); - } - - // 닉네임 중복 검사 - if (isNicknameDuplicated(request.getNickname())) { - throw new CustomException(ErrorCode.NICKNAME_DUPLICATED); - } - - // 문제 없으면 저장 - Member member = Member.of( - request.getEmail(), - passwordEncoder.encode(request.getPassword()), - request.getNickname(), - SocialType.EMAIL - ); - - memberRepository.save(member); - } - - public boolean isEmailDuplicated(String email) { - return memberRepository.findByEmail(email).isPresent(); - } - - public boolean isNicknameDuplicated(String nickname) { - return memberRepository.findByNickname(nickname).isPresent(); - } -}