diff --git a/backend/src/main/java/com/ai/lawyer/domain/member/repositories/MemberRepository.java b/backend/src/main/java/com/ai/lawyer/domain/member/repositories/MemberRepository.java index 8e02781a..f6248e76 100644 --- a/backend/src/main/java/com/ai/lawyer/domain/member/repositories/MemberRepository.java +++ b/backend/src/main/java/com/ai/lawyer/domain/member/repositories/MemberRepository.java @@ -4,6 +4,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository @@ -12,4 +13,7 @@ public interface MemberRepository extends JpaRepository { Optional findByLoginId(String loginId); boolean existsByLoginId(String loginId); + + List findByLoginIdIn(List loginIds); } + diff --git a/backend/src/main/java/com/ai/lawyer/domain/poll/repository/PollVoteRepository.java b/backend/src/main/java/com/ai/lawyer/domain/poll/repository/PollVoteRepository.java index f86b32bf..6ab33ec3 100644 --- a/backend/src/main/java/com/ai/lawyer/domain/poll/repository/PollVoteRepository.java +++ b/backend/src/main/java/com/ai/lawyer/domain/poll/repository/PollVoteRepository.java @@ -1,6 +1,8 @@ package com.ai.lawyer.domain.poll.repository; import com.ai.lawyer.domain.poll.entity.PollVote; +import com.ai.lawyer.domain.poll.entity.Poll; +import com.ai.lawyer.domain.member.entity.Member; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -12,7 +14,7 @@ public interface PollVoteRepository extends JpaRepository, PollVoteRepositoryCustom { Optional findByMember_MemberIdAndPoll_PollId(Long memberId, Long pollId); void deleteByMember_MemberIdAndPoll_PollId(Long memberId, Long pollId); - Optional findByMember_MemberIdAndPollOptions_PollItemsId(Long memberId, Long pollItemsId); + List findByMember_MemberIdAndPollOptions_PollItemsId(Long memberId, Long pollItemsId); List findByMember_MemberId(Long memberId); /** @@ -22,4 +24,9 @@ public interface PollVoteRepository extends JpaRepository, PollV @Modifying @Query("DELETE FROM PollVote pv WHERE pv.member.memberId = :memberId") void deleteByMemberIdValue(@Param("memberId") Long memberId); + + boolean existsByPollAndMember(Poll poll, Member member); + + @Query("SELECT pv.member.memberId FROM PollVote pv WHERE pv.poll = :poll") + List findMemberIdsByPoll(@Param("poll") Poll poll); } diff --git a/backend/src/main/java/com/ai/lawyer/domain/poll/service/PollServiceImpl.java b/backend/src/main/java/com/ai/lawyer/domain/poll/service/PollServiceImpl.java index 2f338000..4e54805f 100644 --- a/backend/src/main/java/com/ai/lawyer/domain/poll/service/PollServiceImpl.java +++ b/backend/src/main/java/com/ai/lawyer/domain/poll/service/PollServiceImpl.java @@ -450,7 +450,7 @@ private PollDto convertToDto(Poll poll, Long memberId, boolean withStatistics) { Long voteCount = pollVoteRepository.countByPollOptionId(option.getPollItemsId()); boolean voted = false; if (memberId != null) { - voted = pollVoteRepository.findByMember_MemberIdAndPollOptions_PollItemsId(memberId, option.getPollItemsId()).isPresent(); + voted = !pollVoteRepository.findByMember_MemberIdAndPollOptions_PollItemsId(memberId, option.getPollItemsId()).isEmpty(); } List statics = null; if (withStatistics && poll.getStatus() == Poll.PollStatus.CLOSED) { diff --git a/backend/src/main/java/com/ai/lawyer/domain/post/repository/PostRepository.java b/backend/src/main/java/com/ai/lawyer/domain/post/repository/PostRepository.java index 4c29374b..db085a25 100644 --- a/backend/src/main/java/com/ai/lawyer/domain/post/repository/PostRepository.java +++ b/backend/src/main/java/com/ai/lawyer/domain/post/repository/PostRepository.java @@ -29,4 +29,6 @@ public interface PostRepository extends JpaRepository { Page findByPoll_Status(PollStatus status, Pageable pageable); Page findByPoll_StatusAndPoll_PollIdIn(PollStatus status, List pollIds, Pageable pageable); Page findByPoll_PollIdIn(List pollIds, Pageable pageable); + boolean existsByPostName(String postName); + List findByPostName(String postName); } \ No newline at end of file diff --git a/backend/src/main/java/com/ai/lawyer/global/init/DummyData.java b/backend/src/main/java/com/ai/lawyer/global/init/DummyData.java new file mode 100644 index 00000000..b74a0696 --- /dev/null +++ b/backend/src/main/java/com/ai/lawyer/global/init/DummyData.java @@ -0,0 +1,166 @@ +package com.ai.lawyer.global.init; + +import com.ai.lawyer.domain.member.entity.Member; +import com.ai.lawyer.domain.member.entity.Member.Gender; +import com.ai.lawyer.domain.member.repositories.MemberRepository; +import com.ai.lawyer.domain.poll.dto.PollForPostDto; +import com.ai.lawyer.domain.post.entity.Post; +import com.ai.lawyer.domain.post.repository.PostRepository; +import com.ai.lawyer.domain.poll.entity.Poll; +import com.ai.lawyer.domain.poll.entity.PollOptions; +import com.ai.lawyer.domain.poll.entity.PollVote; +import com.ai.lawyer.domain.poll.repository.PollOptionsRepository; +import com.ai.lawyer.domain.poll.repository.PollRepository; +import com.ai.lawyer.domain.poll.repository.PollVoteRepository; +import com.ai.lawyer.domain.post.dto.PostRequestDto; +import com.ai.lawyer.domain.poll.dto.PollOptionCreateDto; +import com.ai.lawyer.domain.poll.dto.PollCreateDto; +import com.ai.lawyer.domain.post.dto.PostWithPollCreateDto; +import com.ai.lawyer.domain.post.dto.PostDetailDto; +import com.ai.lawyer.domain.post.service.PostService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.Set; + +@Component +public class DummyData implements CommandLineRunner { + private final MemberRepository memberRepository; + private final PostRepository postRepository; + private final PollRepository pollRepository; + private final PollOptionsRepository pollOptionsRepository; + private final PollVoteRepository pollVoteRepository; + private final PostService postService; + + @Autowired + public DummyData(MemberRepository memberRepository, PostRepository postRepository, + PollRepository pollRepository, PollOptionsRepository pollOptionsRepository, + PollVoteRepository pollVoteRepository, PostService postService) { + this.memberRepository = memberRepository; + this.postRepository = postRepository; + this.pollRepository = pollRepository; + this.pollOptionsRepository = pollOptionsRepository; + this.pollVoteRepository = pollVoteRepository; + this.postService = postService; + } + + @Override + public void run(String... args) { + if (memberRepository.existsByLoginId("dummy1@test.com")) { + System.out.println("더미 데이터가 이미 존재합니다. 전체 더미 생성 로직을 건너뜁니다."); + return; + } + + if (true) { + List allLoginIds = new ArrayList<>(); + for (int i = 1; i <= 1000; i++) { + allLoginIds.add("dummy" + i + "@test.com"); + } + List existingMembers = memberRepository.findByLoginIdIn(allLoginIds); + Set existingLoginIds = new java.util.HashSet<>(); + for (Member m : existingMembers) { + existingLoginIds.add(m.getLoginId()); + } + List membersToSave = new ArrayList<>(); + Random random = new Random(); + for (int i = 1; i <= 1000; i++) { + String loginId = "dummy" + i + "@test.com"; + if (!existingLoginIds.contains(loginId)) { + int age = 14 + random.nextInt(67); // 14~60 + Gender gender = (i % 2 == 0) ? Gender.MALE : Gender.FEMALE; + Member member = Member.builder() + .loginId(loginId) + .password("password") + .age(age) + .gender(gender) + .name("투표자" + i) + .build(); + membersToSave.add(member); + } + } + if (!membersToSave.isEmpty()) { + memberRepository.saveAll(membersToSave); + } + System.out.println("더미 멤버 생성 완료"); + } else { + System.out.println("더미 멤버가 이미 존재합니다. 멤버 생성은 건너뜁니다."); + } + + // 게시글 중복 체크 및 생성 + if (!postRepository.existsByPostName("바로게시글 1")) { + List members = memberRepository.findAll(); + Random random = new Random(); + for (int i = 1; i <= 3; i++) { + PostRequestDto postDto = PostRequestDto.builder() + .postName("바로게시글 " + i) + .postContent("바로바로내용" + i) + .category("카테고리" + i) + .build(); + List pollOptionsDtos = new ArrayList<>(); + for (int j = 1; j <= 2; j++) { + pollOptionsDtos.add(PollOptionCreateDto.builder() + .content("바로투표 " + j) + .build()); + } + PollForPostDto pollDto = PollForPostDto.builder() + .voteTitle("더미 투표 " + i) + .reservedCloseAt(null) + .pollOptions(pollOptionsDtos) + .build(); + PostWithPollCreateDto createDto = PostWithPollCreateDto.builder() + .post(postDto) + .poll(pollDto) + .build(); + Member dummyMember1 = memberRepository.findByLoginId("dummy1@test.com").orElseThrow(); + Long memberId = dummyMember1.getMemberId(); + PostDetailDto postDetail = postService.createPostWithPoll(createDto, memberId); + Long postId = postDetail.getPost().getPostId(); + Post post = postRepository.findById(postId).orElseThrow(); + Poll poll = post.getPoll(); + List pollOptionsList = pollOptionsRepository.findByPoll_PollId(poll.getPollId()); + List votedMemberIds = pollVoteRepository.findMemberIdsByPoll(poll); + List votesToSave = new ArrayList<>(); + for (Member member : members) { + if (!votedMemberIds.contains(member.getMemberId())) { + PollOptions selectedOption = pollOptionsList.get(random.nextInt(pollOptionsList.size())); + PollVote pollVote = PollVote.builder() + .poll(poll) + .member(member) + .pollOptions(selectedOption) + .build(); + votesToSave.add(pollVote); + } + } + if (!votesToSave.isEmpty()) { + pollVoteRepository.saveAll(votesToSave); + } + } + System.out.println("더미 게시글/투표/투표자 생성 완료"); + } else { + List members = memberRepository.findAll(); + Random random = new Random(); + for (int i = 1; i <= 3; i++) { + List posts = postRepository.findByPostName("바로게시글 " + i); + Post post = posts.isEmpty() ? null : posts.get(0); + Poll poll = post != null ? post.getPoll() : null; + List pollOptionsList = poll != null ? pollOptionsRepository.findByPoll_PollId(poll.getPollId()) : new ArrayList<>(); + for (Member member : members) { + PollOptions selectedOption = pollOptionsList.isEmpty() ? null : pollOptionsList.get(random.nextInt(pollOptionsList.size())); + if (poll != null && selectedOption != null && !pollVoteRepository.existsByPollAndMember(poll, member)) { + PollVote pollVote = PollVote.builder() + .poll(poll) + .member(member) + .pollOptions(selectedOption) + .build(); + pollVoteRepository.save(pollVote); + } + } + } + System.out.println("기존 더미 게시글 1~3에 모든 멤버 투표 추가 완료"); + } + } +} diff --git a/backend/src/main/java/com/ai/lawyer/global/security/SecurityConfig.java b/backend/src/main/java/com/ai/lawyer/global/security/SecurityConfig.java index 13792696..e9650a13 100644 --- a/backend/src/main/java/com/ai/lawyer/global/security/SecurityConfig.java +++ b/backend/src/main/java/com/ai/lawyer/global/security/SecurityConfig.java @@ -52,6 +52,7 @@ public class SecurityConfig { "/swagger-ui/**", // Swagger UI "/swagger-ui.html", // Swagger UI HTML "/api/posts/**", // 게시글 (공개) + "/api/polls/{pollId}/statics", // 투표 통계 (공개) "/api/precedent/**", // 판례 (공개) "/api/law/**", // 법령 (공개) "/api/law-word/**", // 법률 용어 (공개)