Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/docs/asciidoc/user-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,18 @@ include::{snippetsDir}/userInfoUpdate/1/response-fields.adoc[]
실패1.
include::{snippetsDir}/userInfoUpdate/2/http-response.adoc[]
실패 2
include::{snippetsDir}/userInfoUpdate/3/http-response.adoc[]
include::{snippetsDir}/userInfoUpdate/3/http-response.adoc[]


=== **9. 회원 탈퇴 api**

회원 탈퇴를 진행

==== Request
include::{snippetsDir}/userExit/1/http-request.adoc[]

==== 성공 Response
include::{snippetsDir}/userExit/1/http-response.adoc[]

==== Response Body Fields
include::{snippetsDir}/userExit/1/response-fields.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.ftm.server.adapter.in.web.user.controller;

import com.ftm.server.application.command.user.DeleteUserByIdCommand;
import com.ftm.server.application.port.in.user.UserExitUseCase;
import com.ftm.server.common.response.ApiResponse;
import com.ftm.server.common.response.enums.SuccessResponseCode;
import com.ftm.server.infrastructure.security.UserPrincipal;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class UserExitController {

private final UserExitUseCase userExitUseCase;

@DeleteMapping("api/users")
public ResponseEntity<ApiResponse> userExit(
@AuthenticationPrincipal UserPrincipal user, HttpServletRequest request) {
// 회원 탈퇴
userExitUseCase.execute(DeleteUserByIdCommand.of(user.getId()));
// 로그아웃 처리
request.getSession().invalidate();
SecurityContextHolder.clearContext();
return ResponseEntity.status(HttpStatus.OK)
.body(ApiResponse.success(SuccessResponseCode.OK));
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
package com.ftm.server.adapter.out.persistence.adapter.user;

import com.ftm.server.adapter.out.persistence.mapper.EmailVerificationLogsMapper;
import com.ftm.server.adapter.out.persistence.mapper.PostMapper;
import com.ftm.server.adapter.out.persistence.mapper.UserImageMapper;
import com.ftm.server.adapter.out.persistence.mapper.UserMapper;
import com.ftm.server.adapter.out.persistence.model.EmailVerificationLogsJpaEntity;
import com.ftm.server.adapter.out.persistence.model.GroomingLevelJpaEntity;
import com.ftm.server.adapter.out.persistence.model.UserImageJpaEntity;
import com.ftm.server.adapter.out.persistence.model.UserJpaEntity;
import com.ftm.server.adapter.out.persistence.repository.EmailVerificationLogsRepository;
import com.ftm.server.adapter.out.persistence.repository.GroomingLevelRepository;
import com.ftm.server.adapter.out.persistence.repository.UserImageRepository;
import com.ftm.server.adapter.out.persistence.repository.UserRepository;
import com.ftm.server.application.command.user.EmailVerificationLogCreationCommand;
import com.ftm.server.adapter.out.persistence.model.*;
import com.ftm.server.adapter.out.persistence.repository.*;
import com.ftm.server.application.command.user.*;
import com.ftm.server.application.port.out.persistence.user.*;
import com.ftm.server.application.query.*;
import com.ftm.server.common.annotation.Adapter;
import com.ftm.server.common.exception.CustomException;
import com.ftm.server.domain.entity.EmailVerificationLogs;
import com.ftm.server.domain.entity.User;
import com.ftm.server.domain.entity.UserImage;
import com.ftm.server.domain.entity.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -35,19 +31,29 @@ public class UserDomainPersistenceAdapter
SaveUserImagePort,
LoadUserPort,
LoadUserImagePort,
UpdateUserInfoPort,
UpdateUserImagePort {
UpdateUserPort,
UpdateUserImagePort,
LoadPostUserDomainPort,
UpdatePostUserDomainPort,
DeleteUserImagePort,
DeleteGroomingTestResultPort,
DeleteUserPort,
DeleteBookmarkPort {

// repository
private final EmailVerificationLogsRepository emailVerificationLogsRepository;
private final UserRepository userRepository;
private final GroomingLevelRepository groomingLevelRepository;
private final UserImageRepository userImageRepository;
private final PostRepository postRepository;
private final BookmarkRepository bookmarkRepository;
private final GroomingTestResultRepository groomingTestResultRepository;

// mapper
private final EmailVerificationLogsMapper emailVerificationLogsMapper;
private final UserMapper userMapper;
private final UserImageMapper userImageMapper;
private final PostMapper postMapper;

@Override
public Optional<EmailVerificationLogs> loadEmailVerificationLogByEmail(FindByEmailQuery query) {
Expand Down Expand Up @@ -115,11 +121,27 @@ public User saveSocialUser(User user) {
public User loadUserById(FindByUserIdQuery query) {
UserJpaEntity userJpaEntity =
userRepository
.findById(query.getUserId())
.findByIdAndIsDeleted(query.getUserId(), false)
.orElseThrow(() -> CustomException.USER_NOT_FOUND);
return userMapper.toDomainEntity(userJpaEntity);
}

@Override
public User loadUserByRole(FindUserByRoleQuery query) {
UserJpaEntity userJpaEntity = userRepository.findByRole(query.getUserRole()).get();
return userMapper.toDomainEntity(userJpaEntity);
}

@Override
public List<User> loadUserByDeleteOption(FindUserByDeleteOptionQuery query) {
return userRepository
.findAllByDeletedBefore(
query.getIsDeleted(), query.getDeletedAt().atTime(23, 59, 59))
.stream()
.map(userMapper::toDomainEntity)
.toList();
}

@Override
public UserImage loadUserImageByUserId(FindByUserIdQuery query) {
UserImageJpaEntity userImageJpaEntity =
Expand All @@ -131,7 +153,7 @@ public UserImage loadUserImageByUserId(FindByUserIdQuery query) {
}

@Override
public void updateUserInfo(User user) {
public void updateUser(User user) {
UserJpaEntity savedUser =
userRepository
.findById(user.getId())
Expand All @@ -156,4 +178,49 @@ public void updateUserImage(UserImage userImage) {

userImageJpaEntity.updateFromDomainEntity(userImage);
}

@Override
public List<Post> loadPostListByUser(FindByUserIdQuery query) {
return postRepository.findByUserId(query.getUserId()).stream()
.map(postMapper::toDomainEntity)
.toList();
}

@Override
public void updatePostListBySystemUser(List<Post> postList) {
UserJpaEntity systemUser = userRepository.findById(postList.get(0).getUserId()).get();

Map<Long, Post> map = new HashMap<>();
postList.forEach(p -> map.put(p.getId(), p));

List<PostJpaEntity> postJpaEntityList =
postRepository.findAllById(postList.stream().map(Post::getId).toList());

postJpaEntityList.forEach(
pj -> pj.updatePostForDomainEntity(map.get(pj.getId()), systemUser));
}

@Override
public void deleteGroomingTestResultByUserList(
DeleteGroomingTestResultByUserIdCommand command) {
groomingTestResultRepository.deleteAllByUserIdList(command.getUserIdList());
}

@Override
public List<String> deleteUserImageByUserList(DeleteUserImageByUserIdCommand command) {
List<String> imageKeyList =
userImageRepository.findAllByUserIdList(command.getUserIdList());
userImageRepository.deleteAllByUserIdList(command.getUserIdList());
return imageKeyList;
}

@Override
public void deleteAllUserByIdList(DeleteAllUserByIdListCommand command) {
userRepository.deleteAllByUserIdList(command.getUserIdList());
}

@Override
public void deleteBookmarkByUserList(DeleteBookmarkByUserIdCommand command) {
bookmarkRepository.deleteAllByUserIdList(command.getUserIdList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,16 @@ public void updatePostForDomainEntity(Post post) {
this.isDeleted = post.getIsDeleted();
this.deletedAt = post.getDeletedAt();
}

public void updatePostForDomainEntity(Post post, UserJpaEntity user) {
this.title = post.getTitle();
this.user = user;
this.content = post.getContent();
this.groomingCategory = post.getGroomingCategory();
this.hashtags = post.getHashtags();
this.viewCount = post.getViewCount();
this.likeCount = post.getLikeCount();
this.isDeleted = post.getIsDeleted();
this.deletedAt = post.getDeletedAt();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
package com.ftm.server.adapter.out.persistence.repository;

import com.ftm.server.adapter.out.persistence.model.BookmarkJpaEntity;
import java.util.List;
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.repository.query.Param;

public interface BookmarkRepository extends JpaRepository<BookmarkJpaEntity, Long> {}
public interface BookmarkRepository extends JpaRepository<BookmarkJpaEntity, Long> {
@Modifying
@Query("DELETE FROM BookmarkJpaEntity b WHERE b.user.id in (:userIds)")
void deleteAllByUserIdList(@Param("userIds") List<Long> userIds);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
package com.ftm.server.adapter.out.persistence.repository;

import com.ftm.server.adapter.out.persistence.model.GroomingTestResultJpaEntity;
import java.util.List;
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.repository.query.Param;

public interface GroomingTestResultRepository
extends JpaRepository<GroomingTestResultJpaEntity, Long>,
GroomingTestResultCustomRepository {}
GroomingTestResultCustomRepository {
@Modifying
@Query("DELETE FROM GroomingTestResultJpaEntity g WHERE g.user.id in (:userIds)")
void deleteAllByUserIdList(@Param("userIds") List<Long> userIds);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.ftm.server.adapter.out.persistence.repository;

import com.ftm.server.adapter.out.persistence.model.PostJpaEntity;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PostRepository extends JpaRepository<PostJpaEntity, Long> {}
public interface PostRepository extends JpaRepository<PostJpaEntity, Long> {

List<PostJpaEntity> findByUserId(Long userId);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
package com.ftm.server.adapter.out.persistence.repository;

import com.ftm.server.adapter.out.persistence.model.UserImageJpaEntity;
import java.util.List;
import java.util.Optional;
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.repository.query.Param;

public interface UserImageRepository extends JpaRepository<UserImageJpaEntity, Long> {

Optional<UserImageJpaEntity> findByUserId(Long userId);

@Modifying
@Query("DELETE FROM UserImageJpaEntity u WHERE u.user.id in (:userIds)")
void deleteAllByUserIdList(@Param("userIds") List<Long> userIds);

@Query("SELECT ui.objectKey FROM UserImageJpaEntity ui WHERE ui.user.id in (:userIds)")
List<String> findAllByUserIdList(@Param("userIds") List<Long> userIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@

import com.ftm.server.adapter.out.persistence.model.UserJpaEntity;
import com.ftm.server.domain.enums.SocialProvider;
import com.ftm.server.domain.enums.UserRole;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
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.repository.query.Param;

public interface UserRepository extends JpaRepository<UserJpaEntity, Long> {

Optional<UserJpaEntity> findByIdAndIsDeleted(Long userId, Boolean isDeleted);

Boolean existsByEmail(String email);

Optional<UserJpaEntity> findByEmail(String email);
Expand All @@ -15,4 +23,14 @@ Optional<UserJpaEntity> findBySocialProviderAndSocialId(
SocialProvider socialProvider, String socialId);

Boolean existsBySocialIdAndSocialProvider(String socialId, SocialProvider socialProvider);

Optional<UserJpaEntity> findByRole(UserRole role);

@Modifying
@Query("DELETE FROM UserJpaEntity u WHERE u.id in (:userIds)")
void deleteAllByUserIdList(@Param("userIds") List<Long> userIds);

@Query("SELECT u FROM UserJpaEntity u WHERE u.isDeleted = :isDeleted And u.deletedAt <=:end")
List<UserJpaEntity> findAllByDeletedBefore(
@Param("isDeleted") Boolean isDeleted, @Param("end") LocalDateTime end);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.ftm.server.adapter.out.scheduler;

import com.ftm.server.application.port.in.user.UserHardDeleteUseCase;
import com.ftm.server.common.annotation.Adapter;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;

@Adapter
@RequiredArgsConstructor
public class UserHardDeleteScheduler {

private final UserHardDeleteUseCase userHardDeleteUseCase;

// 매일 새벽 3시 hard delete 진행
@Scheduled(cron = "0 0 3 * * *")
public void run() {
userHardDeleteUseCase.execute();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.ftm.server.application.command.user;

import java.util.*;
import lombok.Data;

@Data
public class DeleteAllUserByIdListCommand {
private final List<Long> userIdList;

public static DeleteAllUserByIdListCommand of(List<Long> userIdList) {
return new DeleteAllUserByIdListCommand(userIdList);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.ftm.server.application.command.user;

import java.util.List;
import lombok.Data;

@Data
public class DeleteBookmarkByUserIdCommand {
private final List<Long> userIdList;

public static DeleteBookmarkByUserIdCommand of(List<Long> userIdList) {
return new DeleteBookmarkByUserIdCommand(userIdList);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.ftm.server.application.command.user;

import java.util.List;
import lombok.Data;

@Data
public class DeleteGroomingTestResultByUserIdCommand {
private final List<Long> userIdList;

public static DeleteGroomingTestResultByUserIdCommand of(List<Long> userIdList) {
return new DeleteGroomingTestResultByUserIdCommand(userIdList);
}
}
Loading
Loading