Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public enum ErrorStatus implements BaseErrorCode {
// Pot 관련 에러
POT_NOT_FOUND(HttpStatus.NOT_FOUND, "POT4004", "팟이 존재하지 않습니다."),
POT_FORBIDDEN(HttpStatus.FORBIDDEN, "POT4003", "팟 생성자가 아닙니다."),
POT_OWNERSHIP_TRANSFER_REQUIRED(HttpStatus.BAD_REQUEST, "POT4005", "권한을 위임하세요"),

// Pot Comment 관련 에러
POT_COMMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "POTCOMMENT4001", "Pot Comment를 찾을 수 없습니다"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,8 @@ public interface ChatRoomInfoRepository extends JpaRepository<ChatRoomInfo, Long
@Modifying
@Query("delete from ChatRoomInfo cri where cri.potMember.potMemberId in :potMemberIds")
void deleteByPotMemberIdIn(@Param("potMemberIds") List<Long> potMemberIds);
@Modifying
@Query("DELETE FROM ChatRoomInfo cri WHERE cri.potMember.id = :potMemberId AND cri.chatRoom.id IN :chatRoomIds")
void deleteByPotMemberIdAndChatRoomId(@Param("potMemberId") Long potMemberId, @Param("chatRoomIds") List<Long> chatRoomIds);

}
22 changes: 19 additions & 3 deletions src/main/java/stackpot/stackpot/feed/converter/FeedConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ public class FeedConverter{
public FeedResponseDto.FeedDto feedDto(Feed feed, Boolean isOwner, Boolean isLiked, Boolean isSaved, long saveCount) {

Long commentCount = feedCommentRepository.countByFeedId(feed.getFeedId());
String writerNickname = getWriterNickname(feed.getUser());

return FeedResponseDto.FeedDto.builder()
.feedId(feed.getFeedId())
.writerId(feed.getUser().getId())
.writer(feed.getUser().getNickname() + " 새싹")
.writer(writerNickname)
.writerRole(feed.getUser().getRole())
.title(feed.getTitle())
.content(feed.getContent())
Expand All @@ -55,6 +57,8 @@ public FeedResponseDto.CreatedFeedDto createFeedDto(Feed feed) {
"comment", feed.getSeries().getComment()
);
}
Long commentCount = feedCommentRepository.countByFeedId(feed.getFeedId());


return FeedResponseDto.CreatedFeedDto.builder()
.feedId(feed.getFeedId())
Expand Down Expand Up @@ -106,11 +110,11 @@ public FeedResponseDto.AuthorizedFeedDto toAuthorizedFeedDto(Feed feed, boolean
"comment", feed.getSeries().getComment()
);
}

String writerNickname = getWriterNickname(feed.getUser());
FeedResponseDto.CreatedFeedDto createdDto = FeedResponseDto.CreatedFeedDto.builder()
.feedId(feed.getFeedId())
.writerId(feed.getUser().getId())
.writer(feed.getUser().getNickname()+" 새싹")
.writer(writerNickname)
.writerRole(feed.getUser().getRole())
.title(feed.getTitle())
.content(feed.getContent())
Expand Down Expand Up @@ -163,6 +167,18 @@ public FeedCacheDto toFeedCacheDto(Feed feed) {
.createdAt(feed.getCreatedAt().toString())
.build();
}
public String getWriterNickname(User user) {
String writerNickname = user.getNickname();

// 사용자가 탈퇴한 경우 "새싹"을 제거
if (user.isDeleted()) {
writerNickname = writerNickname; // 탈퇴한 경우 "새싹" 제거
} else {
writerNickname += " 새싹"; // 탈퇴하지 않은 경우 "새싹" 추가
}

return writerNickname;
}


}
2 changes: 1 addition & 1 deletion src/main/java/stackpot/stackpot/pot/entity/Pot.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class Pot extends BaseEntity {
@JoinColumn(name = "user_id", nullable = false)
private User user;

@OneToMany(mappedBy = "pot")
@OneToMany(mappedBy = "pot",cascade = CascadeType.ALL, orphanRemoval = true)
private List<PotRecruitmentDetails> recruitmentDetails;

@OneToMany(mappedBy = "pot", cascade = CascadeType.REMOVE, orphanRemoval = true)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package stackpot.stackpot.pot.repository;

import jakarta.persistence.QueryHint;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.QueryHints;
import org.springframework.data.repository.query.Param;
import stackpot.stackpot.pot.entity.mapping.PotApplication;

Expand All @@ -22,4 +24,10 @@ public interface PotApplicationRepository extends JpaRepository<PotApplication,
@Query("DELETE FROM PotApplication f WHERE f.pot.potId = :potId")
void deleteByPotId(@Param("potId") Long potId);

@Modifying
@Query("DELETE FROM PotApplication pa WHERE pa.pot.potId IN :potIds")
@QueryHints({ @QueryHint(name = "javax.persistence.query.timeout", value = "5000") })
void deleteByPotIds(@Param("potIds") List<Long> potIds);


}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public interface PotMemberRepository extends JpaRepository<PotMember, Long> {

boolean existsByPotAndUser(Pot pot, User user);

// 특정 Pot에 속한 사용자(userId)의 역할(Role) 찾기
// 특정 Pot에 속한 사용자(userId)의 역할(Role) 찾기
@Query("SELECT pm.roleName FROM PotMember pm WHERE pm.pot.potId = :potId AND pm.user.id = :userId")
Optional<Role> findRoleByUserId(@Param("potId") Long potId, @Param("userId") Long userId);

Expand Down Expand Up @@ -89,4 +89,16 @@ public interface PotMemberRepository extends JpaRepository<PotMember, Long> {

@Query("SELECT pm.pot.potId FROM PotMember pm WHERE pm.user.id = :userId AND pm.pot.potId IN :potIds")
Set<Long> findPotIdsByUserIdAndPotIds(@Param("userId") Long userId, @Param("potIds") List<Long> potIds);

@Modifying
@Query("""
DELETE FROM PotMember pm
WHERE pm.pot.id IN :potIds
AND pm.user.id = :userId
""")
void deleteByPotIdsAndUserId(@Param("potIds") List<Long> potIds,
@Param("userId") Long userId);
@Modifying
@Query("DELETE FROM PotMember pm WHERE pm.pot.potId IN :potIds AND pm.user.id = :userId")
void deleteByUserIdAndPotIdIn(@Param("userId") Long userId, @Param("potIds") List<Long> potIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@
import org.springframework.data.repository.query.Param;
import stackpot.stackpot.pot.entity.PotRecruitmentDetails;

import java.util.List;

public interface PotRecruitmentDetailsRepository extends JpaRepository<PotRecruitmentDetails, Long> {
@Modifying
@Transactional
@Query("DELETE FROM PotRecruitmentDetails r WHERE r.pot.potId = :potId")
void deleteByPot_PotId(@Param("potId") Long potId);


@Modifying
@Query("DELETE FROM PotRecruitmentDetails prd WHERE prd.pot.potId IN :potIds")
void deleteByPotIds(@Param("potIds") List<Long> potIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ public interface PotRepository extends JpaRepository<Pot, Long> {
@Modifying
@Query("DELETE FROM Pot f WHERE f.user.id = :userId")
void deleteByUserId(@Param("userId") Long userId);

@Modifying
@Query("DELETE FROM Pot p WHERE p.user.id = :userId AND p.potId IN :potIds AND p.potStatus = 'RECRUITING'")
void deleteByUserIdAndPotIds(@Param("userId") Long userId, @Param("potIds") List<Long> potIds);
boolean existsByUserId(Long userId);

// 지원자 수 기준으로 모든 Pot 정렬
Expand All @@ -76,5 +78,11 @@ public interface PotRepository extends JpaRepository<Pot, Long> {

List<Pot> findByPotMembers_UserIdOrderByCreatedAtDesc(Long userId);

@Query("select p.potId from Pot p where p.user.id = :userId and p.potStatus = :status")
List<Long> findIdsByUserIdAndStatus(@Param("userId") Long userId,
@Param("status") String status);

@Query("select p.potId from Pot p where p.user.id = :userId and p.potStatus not in :statuses")
List<Long> findIdsByUserIdAndStatusNotIn(@Param("userId") Long userId,
@Param("statuses") List<String> statuses);
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,11 @@ default Map<Long, Integer> countSavesByPotIds(List<Long> potIds) {

@Query("SELECT ps.pot FROM PotSave ps WHERE ps.user.id = :userId")
Page<Pot> findSavedPotsByUserId(@Param("userId") Long userId, Pageable pageable);

@Modifying
@Transactional
@Query("DELETE FROM PotSave ps WHERE ps.user = :user AND ps.pot IN :pots")
void deleteAllByUserAndPots(@Param("user") User user, @Param("pots") List<Pot> pots);

List<PotSave> findByUser(User user);
}
3 changes: 3 additions & 0 deletions src/main/java/stackpot/stackpot/user/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ public void deleteUser() {
}
this.interests = new ArrayList<>(); // 새로운 관심사 목록 생성
this.interests.add("UNKNOWN"); // "UNKNOWN"을 관심사 목록에 추가
if (this.seriesList != null) {
this.seriesList.clear(); // 연관된 시리즈 비우기
}

this.userTemperature = null;
this.email = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import stackpot.stackpot.apiPayload.code.status.ErrorStatus;
import stackpot.stackpot.apiPayload.exception.GeneralException;
import stackpot.stackpot.apiPayload.exception.handler.PotHandler;
import stackpot.stackpot.apiPayload.exception.handler.TokenHandler;
import stackpot.stackpot.apiPayload.exception.handler.UserHandler;
import stackpot.stackpot.chat.repository.ChatRoomInfoRepository;
import stackpot.stackpot.common.util.AuthService;
import stackpot.stackpot.config.security.JwtTokenProvider;
import stackpot.stackpot.pot.entity.mapping.PotSave;
import stackpot.stackpot.pot.repository.*;
import stackpot.stackpot.task.repository.TaskRepository;
import stackpot.stackpot.task.repository.TaskboardRepository;
import stackpot.stackpot.user.converter.UserConverter;
Expand All @@ -29,14 +34,10 @@
import stackpot.stackpot.user.entity.enums.Provider;
import stackpot.stackpot.user.entity.enums.Role;
import stackpot.stackpot.pot.entity.mapping.PotMember;
import stackpot.stackpot.pot.repository.PotMemberRepository;
import stackpot.stackpot.pot.service.pot.PotSummarizationService;
import stackpot.stackpot.badge.repository.PotMemberBadgeRepository;
import stackpot.stackpot.todo.repository.UserTodoRepository;
import stackpot.stackpot.feed.repository.FeedRepository;
import stackpot.stackpot.pot.repository.PotApplicationRepository;
import stackpot.stackpot.pot.repository.PotRecruitmentDetailsRepository;
import stackpot.stackpot.pot.repository.PotRepository;
import stackpot.stackpot.user.entity.enums.UserType;
import stackpot.stackpot.user.repository.BlacklistRepository;
import stackpot.stackpot.user.repository.RefreshTokenRepository;
Expand Down Expand Up @@ -64,16 +65,17 @@ public class UserCommandServiceImpl implements UserCommandService {
private final TaskboardRepository taskboardRepository;
private final PotRecruitmentDetailsRepository potRecruitmentDetailsRepository;
private final PotMemberBadgeRepository potMemberBadgeRepository;

private final ChatRoomInfoRepository chatRoominfoRepository;
private final UserMypageConverter userMypageConverter;
private final TempUserRepository tempUserRepository;
private final PotSummarizationService potSummarizationService;
private final JwtTokenProvider jwtTokenProvider;
private final RefreshTokenRepository refreshTokenRepository;
private final BlacklistRepository blacklistRepository;
private final AuthService authService;

private final PotSaveRepository potSaveRepository;
private final EmailService emailService;
private final PotCommentRepository potCommentRepository;

@Override
@Transactional
Expand Down Expand Up @@ -311,14 +313,17 @@ public String deleteUser(String accessToken) {
blacklistRepository.addToBlacklist(token, jwtTokenProvider.getExpiration(token));

// Feed 관련 데이터 삭제
deleteFeedRelatedData(user.getId());
// deleteFeedRelatedData(user.getId());

// Todo 데이터 삭제
userTodoRepository.deleteByUserId(user.getId());

// Task 및 Taskboard 관련 데이터 삭제
deleteTaskRelatedData(user.getId());

// 사용자가 저장한 Pot 삭제
deleteUserSavedPots(user);

// Pot 관련 데이터 삭제
boolean isCreator = potRepository.existsByUserId(user.getId());
if (isCreator) {
Expand All @@ -339,7 +344,20 @@ private void deleteFeedRelatedData(Long userId) {
feedLikeRepository.deleteByUserId(userId);

// Feed 삭제
feedRepository.deleteByUserId(userId);
// feedRepository.deleteByUserId(userId);
}
@Transactional
public void deleteUserSavedPots(User user) {
// 사용자가 저장한 PotSave 목록을 조회
List<PotSave> userSavedPots = potSaveRepository.findByUser(user);

// 해당 PotSave 엔티티에서 Pot만 추출
List<Pot> potsToDelete = userSavedPots.stream()
.map(PotSave::getPot) // PotSave에서 Pot만 추출
.collect(Collectors.toList());

// 사용자가 저장한 PotSave만 삭제
potSaveRepository.deleteAllByUserAndPots(user, potsToDelete);
}

private void deleteTaskRelatedData(Long userId) {
Expand Down Expand Up @@ -372,25 +390,50 @@ private void deleteTaskRelatedData(Long userId) {
}
}

private void handleCreatorPotDeletion(User user) {
List<Pot> userPots = potRepository.findByUserId(user.getId());
@Transactional
public void handleCreatorPotDeletion(User user) {
Long userId = user.getId();


List<Long> completedPotIds = potRepository.findIdsByUserIdAndStatus(userId, "COMPLETED");
List<Long> recruitingPotIds = potRepository.findIdsByUserIdAndStatus(userId, "RECRUITING");
// 완료/모집중을 제외한 나머지(진행중 등)
List<Long> otherPotIds = potRepository.findIdsByUserIdAndStatusNotIn(
userId, List.of("COMPLETED", "RECRUITING")
);

// 2) 완료된 Pot → 현재 유저의 PotMember만 일괄 소프트 딜리트 (배치 UPDATE)
// if (!completedPotIds.isEmpty()) {
// potMemberRepository.softDeleteByPotIdsAndUserId(completedPotIds, userId);
// }

// 3) 모집중 Pot → 연관 정리 후 배치 삭제
if (!recruitingPotIds.isEmpty()) {
potRecruitmentDetailsRepository.deleteByPotIds(recruitingPotIds);
// PotApplication 삭제
potApplicationRepository.deleteByPotIds(recruitingPotIds);
potRepository.deleteByUserIdAndPotIds(userId, recruitingPotIds);
}

for (Pot pot : userPots) {
if (pot.getPotStatus().equals("COMPLETED")) {
// 완료된 Pot의 경우 PotMember만 소프트 딜리트
PotMember potMember = potMemberRepository.findByPotIdAndUserId(pot.getPotId(), user.getId());
potMember.deletePotMember();
potMemberRepository.save(potMember);
} else {
// 진행 중인 Pot 처리
deletePotAndRelatedData(pot);
}

// 4) 진행 중(기타 상태) → 권한 위임 요구 에러
if (!otherPotIds.isEmpty()) {
throw new PotHandler(ErrorStatus.POT_OWNERSHIP_TRANSFER_REQUIRED);
}

user.deleteUser(); // 소프트 딜리트
// 5) 유저 소프트 딜리트
user.deleteUser();
userRepository.save(user);
}

@Transactional
public void deletePotAndRelatedData(List<Long> potIds) {
List<Pot> pots = potRepository.findAllById(potIds);
for (Pot pot : pots) {
deletePotAndRelatedData(pot);
}
}

@Transactional
public void deletePotAndRelatedData(Pot pot) {

Expand Down Expand Up @@ -457,9 +500,24 @@ private void sendDeletionNotifications(List<PotMember> potMembers, Pot pot) {
}

private void handleNormalUserPotDeletion(User user) {
potMemberRepository.deleteByUserId(user.getId());
potApplicationRepository.deleteByUserId(user.getId());
userRepository.delete(user);
Long userId = user.getId();
// 1. 진행 중인 팟 IDs 조회
List<Long> ongoingPotIds = potRepository.findIdsByUserIdAndStatus(userId, "ONGOING");

// 2. 진행 중인 팟에 속한 PotMember만 삭제 (진행 중인 팟에 대해서만)
if (!ongoingPotIds.isEmpty()) {
// 해당 유저가 속한 진행 중인 팟에서 PotMember 삭제
potMemberRepository.deleteByUserIdAndPotIdIn(userId, ongoingPotIds); // 진행 중인 팟에 해당하는 PotMember만 삭제
}

// 3. 진행 중인 팟에 해당하는 채팅방 기록 삭제
if (!ongoingPotIds.isEmpty()) {
chatRoominfoRepository.deleteByPotMemberIdAndChatRoomId(userId, ongoingPotIds); // 진행 중인 팟에 해당하는 채팅방 삭제
}

// 4. PotApplication 삭제 (유저가 신청한 팟의 신청 내역 삭제)
potApplicationRepository.deleteByUserId(userId);

}

@Override
Expand Down