Skip to content
This repository was archived by the owner on Jan 11, 2026. It is now read-only.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.example.spot.common.config;

import com.example.spot.study.domain.aggregate.Theme;
import com.example.spot.study.domain.association.Theme;
import com.example.spot.study.domain.enums.ThemeType;
import com.example.spot.study.domain.repository.RegionRepository;
import com.example.spot.study.domain.aggregate.Region;
import com.example.spot.study.domain.association.Region;
import com.example.spot.study.domain.repository.ThemeRepository;
import java.io.IOException;
import java.io.InputStreamReader;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,64 +1,20 @@
package com.example.spot.member.application.legacy;

import com.example.spot.common.api.code.status.ErrorStatus;
import com.example.spot.common.api.exception.GeneralException;
import com.example.spot.common.api.exception.handler.MemberHandler;
import com.example.spot.member.domain.association.StudyJoinReason;
import com.example.spot.member.domain.enums.Gender;
import com.example.spot.member.domain.enums.LoginType;
import com.example.spot.member.domain.enums.Reason;
import com.example.spot.member.domain.enums.Status;
import com.example.spot.study.domain.enums.ThemeType;
import com.example.spot.member.domain.association.StudyJoinReasonRepository;
import com.example.spot.common.security.utils.JwtTokenProvider;
import com.example.spot.member.domain.Member;
import com.example.spot.member.domain.MemberRepository;
import com.example.spot.member.presentation.dto.MemberRequestDTO;
import com.example.spot.member.presentation.dto.MemberRequestDTO.MemberReasonDTO;
import com.example.spot.auth.domain.CustomUserDetails;
import com.example.spot.auth.domain.RefreshToken;
import com.example.spot.auth.domain.RefreshTokenRepository;
import com.example.spot.auth.infrastructure.kakao.KakaoOAuthClient;
import com.example.spot.member.presentation.dto.MemberResponseDTO;
import com.example.spot.member.presentation.dto.MemberResponseDTO.MemberRegionDTO.RegionDTO;
import com.example.spot.member.presentation.dto.MemberResponseDTO.MemberSignInDTO;
import com.example.spot.member.presentation.dto.MemberResponseDTO.MemberStudyReasonDTO;
import com.example.spot.member.presentation.dto.MemberResponseDTO.MemberTestDTO;
import com.example.spot.member.presentation.dto.MemberResponseDTO.SocialLoginSignInDTO;
import com.example.spot.auth.presentation.dto.kakao.KaKaoOAuthToken.KaKaoOAuthTokenDTO;
import com.example.spot.auth.presentation.dto.kakao.KaKaoUser;
import com.example.spot.auth.presentation.dto.token.TokenResponseDTO.TokenDTO;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import com.example.spot.study.domain.aggregate.Region;
import com.example.spot.study.domain.aggregate.Theme;
import com.example.spot.member.domain.association.MemberTheme;
import com.example.spot.member.domain.association.PreferredRegion;
import com.example.spot.member.domain.association.MemberThemeRepository;
import com.example.spot.member.domain.association.PreferredRegionRepository;
import com.example.spot.study.domain.repository.RegionRepository;
import com.example.spot.study.domain.repository.ThemeRepository;
import com.example.spot.member.presentation.dto.MemberRequestDTO.MemberInfoListDTO;
import com.example.spot.member.presentation.dto.MemberRequestDTO.MemberRegionDTO;
import com.example.spot.member.presentation.dto.MemberRequestDTO.MemberThemeDTO;
import com.example.spot.member.presentation.dto.MemberResponseDTO.MemberUpdateDTO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;


// TODO 추후 삭제 예정 -> 구글 로그인 관련 로직이 남아있음

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import com.example.spot.member.domain.enums.Reason;
import com.example.spot.member.presentation.dto.MemberRequestDTO;
import com.example.spot.member.presentation.dto.MemberResponseDTO;
import com.example.spot.study.domain.aggregate.Region;
import com.example.spot.study.domain.aggregate.Theme;
import com.example.spot.study.domain.association.Region;
import com.example.spot.study.domain.association.Theme;
import com.example.spot.study.domain.enums.ThemeType;
import com.example.spot.study.domain.repository.RegionRepository;
import com.example.spot.study.domain.repository.ThemeRepository;
Expand Down
14 changes: 7 additions & 7 deletions src/main/java/com/example/spot/member/domain/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@
import com.example.spot.report.domain.MemberReport;
import com.example.spot.report.domain.PostReport;
import com.example.spot.schedule.domain.Schedule;
import com.example.spot.schedule.domain.aggregate.Quiz;
import com.example.spot.schedule.domain.association.Quiz;
import com.example.spot.story.domain.Story;
import com.example.spot.story.domain.aggregate.LikedStoryComment;
import com.example.spot.story.domain.aggregate.LikedStory;
import com.example.spot.story.domain.association.LikedStoryComment;
import com.example.spot.story.domain.association.LikedStory;
import com.example.spot.member.domain.association.StudyJoinReason;
import com.example.spot.common.entity.BaseEntity;
import com.example.spot.member.domain.enums.Carrier;
import com.example.spot.member.domain.enums.Gender;
import com.example.spot.member.domain.enums.LoginType;
import com.example.spot.member.domain.enums.Status;
import com.example.spot.schedule.domain.aggregate.QuizSubmission;
import com.example.spot.schedule.domain.association.QuizSubmission;
import com.example.spot.post.domain.association.MemberScrap;
import com.example.spot.study.domain.aggregate.StudyMember;
import com.example.spot.study.domain.association.StudyMember;
import com.example.spot.member.domain.association.MemberTheme;
import com.example.spot.todo.domain.ToDo;
import com.example.spot.vote.domain.Vote;
import com.example.spot.vote.domain.aggregate.VoteParticipant;
import com.example.spot.vote.domain.association.VoteParticipant;
import com.example.spot.member.domain.association.PreferredRegion;
import com.example.spot.member.domain.association.PreferredStudy;
import com.example.spot.story.domain.aggregate.StoryComment;
import com.example.spot.story.domain.association.StoryComment;
import com.example.spot.member.presentation.dto.MemberRequestDTO.MemberUpdateDTO;
import jakarta.persistence.*;
import java.util.ArrayList;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.example.spot.member.domain.association;

import com.example.spot.member.domain.Member;
import com.example.spot.study.domain.aggregate.Theme;
import com.example.spot.study.domain.association.Theme;
import com.example.spot.common.entity.BaseEntity;
import jakarta.persistence.*;
import lombok.AccessLevel;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.example.spot.member.domain.association;

import com.example.spot.study.domain.aggregate.Region;
import com.example.spot.study.domain.association.Region;
import com.example.spot.member.domain.Member;
import com.example.spot.common.entity.BaseEntity;
import jakarta.persistence.*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.example.spot.common.api.code.status.ErrorStatus;
import com.example.spot.common.api.exception.GeneralException;
import com.example.spot.notification.domain.Notification;
import com.example.spot.study.domain.aggregate.StudyMember;
import com.example.spot.study.domain.association.StudyMember;
import com.example.spot.study.domain.enums.StudyApplicationStatus;
import com.example.spot.notification.domain.enums.NotifyType;
import com.example.spot.study.domain.repository.StudyMemberRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,4 @@ public interface PostCommandService {

//게시글 스크랩 모두 취소
ScrapsPostDeleteResponse cancelPostScraps(ScrapAllDeleteRequest request);

//게시글 신고
PostReportResponse reportPost(Long postId, Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -599,32 +599,4 @@ public ScrapsPostDeleteResponse cancelPostScraps(ScrapAllDeleteRequest request)
.cancelScraps(deletePostResponses)
.build();
}

@Override
public PostReportResponse reportPost(Long postId, Long memberId) {

// 동일한 게시글에 대한 중복 신고 방지
if (postReportRepository.existsByPostIdAndMemberId(postId, memberId)) {
throw new PostHandler(ErrorStatus._POST_ALREADY_REPORTED);
}

Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberHandler(ErrorStatus._MEMBER_NOT_FOUND));

Post post = postRepository.findById(postId)
.orElseThrow(() -> new PostHandler(ErrorStatus._POST_NOT_FOUND));

if (post.getMember().getId().equals(memberId)) {
throw new PostHandler(ErrorStatus._POST_REPORT_SELF);
}

PostReport postReport = PostReport.builder()
.postStatus(PostStatus.신고접수)
.post(post)
.member(member).build();

postReportRepository.save(postReport);

return PostReportResponse.toDTO(postId, memberId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -343,15 +343,4 @@ public ApiResponse<ScrapsPostDeleteResponse> deleteAllPostScrap(
ScrapsPostDeleteResponse response = postCommandService.cancelPostScraps(request);
return ApiResponse.onSuccess(SuccessStatus._NO_CONTENT, response);
}

@Tag(name = "게시글 신고", description = "게시글 신고 관련 API")
@Operation(summary = "[게시판] 게시글 신고 API", description = "게시글 ID와 회원 ID를 받아 게시글을 신고합니다.")
@PostMapping("/{postId}/report")
public ApiResponse<PostReportResponse> reportPost(
@PathVariable @ExistPost Long postId
) {
PostReportResponse response = postCommandService.reportPost(postId, SecurityUtils.getCurrentUserId());
return ApiResponse.onSuccess(SuccessStatus._OK, response);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.spot.report.application;

import com.example.spot.member.presentation.dto.MemberResponseDTO;
import com.example.spot.report.presentation.dto.PostReportResponse;
import com.example.spot.story.web.dto.response.StoryResDTO;
import com.example.spot.study.presentation.dto.request.StudyMemberReportDTO;
import jakarta.validation.Valid;

public interface ReportCommandService {

// 게시글 신고
PostReportResponse reportPost(Long postId, Long memberId);

// 스터디 회원 신고
MemberResponseDTO.ReportedMemberDTO reportStudyMember(Long studyId, Long memberId, @Valid StudyMemberReportDTO studyMemberReportDTO);

// 스터디 게시글 신고
StoryResDTO.PostPreviewDTO reportStudyPost(Long studyId, Long postId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package com.example.spot.report.application;

import com.example.spot.common.api.code.status.ErrorStatus;
import com.example.spot.common.api.exception.handler.MemberHandler;
import com.example.spot.common.api.exception.handler.PostHandler;
import com.example.spot.common.api.exception.handler.StudyHandler;
import com.example.spot.common.security.utils.SecurityUtils;
import com.example.spot.member.domain.Member;
import com.example.spot.member.domain.MemberRepository;
import com.example.spot.member.presentation.dto.MemberResponseDTO;
import com.example.spot.post.domain.Post;
import com.example.spot.post.domain.PostRepository;
import com.example.spot.post.domain.enums.PostStatus;
import com.example.spot.report.domain.*;
import com.example.spot.report.presentation.dto.PostReportResponse;
import com.example.spot.story.domain.Story;
import com.example.spot.story.domain.StoryRepository;
import com.example.spot.story.web.dto.response.StoryResDTO;
import com.example.spot.study.domain.Study;
import com.example.spot.study.domain.StudyRepository;
import com.example.spot.study.domain.enums.StudyApplicationStatus;
import com.example.spot.study.domain.repository.StudyMemberRepository;
import com.example.spot.study.presentation.dto.request.StudyMemberReportDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
@RequiredArgsConstructor
public class ReportCommandServiceImpl implements ReportCommandService {

private final MemberRepository memberRepository;
private final PostRepository postRepository;
private final StudyRepository studyRepository;
private final StudyMemberRepository studyMemberRepository;
private final StoryRepository storyRepository;

private final MemberReportRepository memberReportRepository;
private final StoryReportRepository storyReportRepository;
private final PostReportRepository postReportRepository;

@Override
public PostReportResponse reportPost(Long postId, Long memberId) {

// 동일한 게시글에 대한 중복 신고 방지
if (postReportRepository.existsByPostIdAndMemberId(postId, memberId)) {
throw new PostHandler(ErrorStatus._POST_ALREADY_REPORTED);
}

Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberHandler(ErrorStatus._MEMBER_NOT_FOUND));

Post post = postRepository.findById(postId)
.orElseThrow(() -> new PostHandler(ErrorStatus._POST_NOT_FOUND));

if (post.getMember().getId().equals(memberId)) {
throw new PostHandler(ErrorStatus._POST_REPORT_SELF);
}

PostReport postReport = PostReport.builder()
.postStatus(PostStatus.신고접수)
.post(post)
.member(member).build();

postReportRepository.save(postReport);

return PostReportResponse.toDTO(postId, memberId);
}

/**
* 스터디원을 신고하고 신고 내역을 저장하는 메서드입니다.
* @param studyId 타겟 스터디의 아이디를 입력 받습니다.
* @param memberId 신고할 회원의 아이디를 입력 받습니다.
* @param studyMemberReportDTO 신고 사유를 입력 받습니다.
* @return 신고를 당한 회원의 아이디와 이름을 반환합니다.
*/
@Override
public MemberResponseDTO.ReportedMemberDTO reportStudyMember(Long studyId, Long memberId, StudyMemberReportDTO studyMemberReportDTO) {

//=== Exception ===//
Long reporterId = SecurityUtils.getCurrentUserId();
SecurityUtils.verifyUserId(reporterId);

Member reporter = memberRepository.findById(reporterId)
.orElseThrow(() -> new MemberHandler(ErrorStatus._MEMBER_NOT_FOUND));
Study study = studyRepository.findById(studyId)
.orElseThrow(() -> new StudyHandler(ErrorStatus._STUDY_NOT_FOUND));
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberHandler(ErrorStatus._MEMBER_NOT_FOUND));

// 로그인한 회원이 스터디 회원인지 확인
studyMemberRepository.findByMemberIdAndStudyIdAndStatus(reporterId, studyId, StudyApplicationStatus.APPROVED)
.orElseThrow(() -> new StudyHandler(ErrorStatus._STUDY_MEMBER_NOT_FOUND));

// 신고당한 회원이 스터디 회원인지 확인
studyMemberRepository.findByMemberIdAndStudyIdAndStatus(memberId, studyId, StudyApplicationStatus.APPROVED)
.orElseThrow(() -> new StudyHandler(ErrorStatus._STUDY_MEMBER_NOT_FOUND));

// 자기 자신을 신고할 수 없음
if (reporterId.equals(memberId)) {
throw new StudyHandler(ErrorStatus._STUDY_MEMBER_REPORT_INVALID);
}


//=== Feature ===//
MemberReport memberReport = MemberReport.builder()
.content(studyMemberReportDTO.getContent())
.member(member)
.build();

memberReport = memberReportRepository.save(memberReport);
member.addMemberReport(memberReport);

return MemberResponseDTO.ReportedMemberDTO.toDTO(member);
}

/**
* 스터디 게시글을 신고하고 신고 내역을 저장하는 메서드입니다.
* @param studyId 타겟 스터디의 아이디를 입력합니다.
* @param postId 신고할 게시글의 아이디를 입력합니다.
* @return 신고를 당한 스터디 게시글의 아이디와 제목을 반환합니다.
*/
@Override
public StoryResDTO.PostPreviewDTO reportStudyPost(Long studyId, Long postId) {

//=== Exception ===//
Long reporterId = SecurityUtils.getCurrentUserId();
SecurityUtils.verifyUserId(reporterId);

memberRepository.findById(reporterId)
.orElseThrow(() -> new MemberHandler(ErrorStatus._MEMBER_NOT_FOUND));
studyRepository.findById(studyId)
.orElseThrow(() -> new StudyHandler(ErrorStatus._STUDY_NOT_FOUND));
Story story = storyRepository.findById(postId)
.orElseThrow(() -> new StudyHandler(ErrorStatus._STUDY_NOT_FOUND));

// 로그인한 회원이 스터디 회원인지 확인
studyMemberRepository.findByMemberIdAndStudyIdAndStatus(reporterId, studyId, StudyApplicationStatus.APPROVED)
.orElseThrow(() -> new StudyHandler(ErrorStatus._STUDY_MEMBER_NOT_FOUND));

// 해당 스터디의 게시글인지 확인
storyRepository.findByIdAndStudyId(postId, studyId)
.orElseThrow(() -> new StudyHandler(ErrorStatus._STUDY_POST_NOT_FOUND));

//=== Feature ===//
StoryReport storyReport = StoryReport.builder()
.story(story)
.build();

storyReport = storyReportRepository.save(storyReport);
story.addStudyPostReport(storyReport);

return StoryResDTO.PostPreviewDTO.toDTO(story);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.spot.story.domain.aggregate;
package com.example.spot.report.domain;

import com.example.spot.story.domain.Story;
import jakarta.persistence.*;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.example.spot.story.domain.repository;
package com.example.spot.report.domain;

import com.example.spot.story.domain.aggregate.StoryReport;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

Expand Down
Loading