Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ecolink.core.bookmark.repository;

import java.util.List;
import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -13,7 +14,10 @@ public interface BookmarkRepository extends JpaRepository<Bookmark, Long> {
+ "where b.avatar.id = :avatarId "
+ "and b.store.id = :storeId")
boolean existsByAvatarAndStore(@Param("avatarId") Long avatarId, @Param("storeId") Long storeId);

Optional<Bookmark> findBookmarkByAvatarIdAndStoreId(Long avatarId, Long storeId);

List<Bookmark> findAllByAvatarId(Long avatarId);
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.ecolink.core.common.config.scheduler;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
@Configuration
public class SchedulerConfig {
}
1 change: 1 addition & 0 deletions src/main/java/com/ecolink/core/common/error/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public enum ErrorCode {
APPLICATION_IS_PENDING(HttpStatus.BAD_REQUEST, "M-001", "해당 유저는 대표 신청 후 승인 대기중 상태입니다."),
MANAGER_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "M-002", "주어진 유저로 매니저를 찾을 수 없습니다."),
NOT_MANAGER_OF_STORE(HttpStatus.FORBIDDEN, "M-003", "해당 매장을 관리할 수 있는 권한이 없습니다."),
MANAGER_WITHDRAWAL_DENIED(HttpStatus.FORBIDDEN, "M-004", "매니저는 회원 탈퇴 기능을 쓸 수 없습니다."),

/**
* 상점 관련 오류
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ public interface ReviewLikeRepository extends JpaRepository<ReviewLike, Long> {
List<ReviewLike> findAllByReviewList(@Param("reviewIds") List<Long> reviewIds,
@Param("avatarId") Long avatarId);

@Query("select l from ReviewLike l "
+ "where l.avatar.id = :avatarId")
List<ReviewLike> findAllByAvatarId(@Param("avatarId") Long avatarId);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.ecolink.core.review.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -26,4 +28,8 @@ public interface ReviewRepository extends JpaRepository<Review, Long> {
Page<Review> findByStoreAndAvatar(@Param("storeId") Long storeId, @Param("avatarId") Long avatarId,
Pageable pageable);

@Query("select r from Review r "
+ "where r.writer.id = :writerId")
List<Review> findAllByAvatarId(@Param("writerId") Long writerId);

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
package com.ecolink.core.review.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import com.ecolink.core.review.domain.ReviewTag;

public interface ReviewTagRepository extends JpaRepository<ReviewTag, Long> {
@Query("select rt "
+ "from ReviewTag rt "
+ "where rt.review.writer.id = :writerId")
List<ReviewTag> findAllByAvatarId(@Param("writerId") Long writerId);
}
3 changes: 2 additions & 1 deletion src/main/java/com/ecolink/core/user/constant/RoleType.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ public enum RoleType {
GUEST("ROLE_GUEST"),
USER("ROLE_USER"),
MANAGER("ROLE_MANAGER"),
ADMIN("ROLE_ADMIN");
ADMIN("ROLE_ADMIN"),
WITHDRAWN_USER("ROLE_WITHDRAWN_USER");

private final String authority;

Expand Down
36 changes: 36 additions & 0 deletions src/main/java/com/ecolink/core/user/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.ecolink.core.user.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.ecolink.core.auth.token.UserPrincipal;
import com.ecolink.core.common.response.ApiResponse;
import com.ecolink.core.user.service.WithdrawService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@RestController
@RequestMapping("${api.prefix}/users")
public class UserController {

private final WithdrawService withdrawService;

@Tag(name = "${swagger.tag.account}")
@Operation(summary = "회원 탈퇴 API - 인증 필요",
description = "회원 탈퇴 - 인증 필요",
security = {@SecurityRequirement(name = "session-token")})
@PreAuthorize("hasRole('USER')")
@DeleteMapping("/withdraw")
public ApiResponse<Void> withdraw(
@AuthenticationPrincipal UserPrincipal principal) {
withdrawService.withdraw(principal.getUserId());
return ApiResponse.ok();
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/ecolink/core/user/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,9 @@ public void addAvatar(Avatar avatar) {
this.avatars.add(avatar);
}

public void withdraw(Role role) {
this.withdrawn = true;
this.withdrawnDate = LocalDateTime.now();
this.role = role;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ecolink.core.user.repository;

import java.util.List;
import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -23,4 +24,8 @@ public interface UserRepository extends JpaRepository<User, Long> {
+ "where u.id = :id")
Optional<User> findUserGraphById(@Param("id") Long id);

@Query("select u from User u "
+ "where u.withdrawn = true")
List<User> findAllByWithdrawn();

}
6 changes: 6 additions & 0 deletions src/main/java/com/ecolink/core/user/service/RoleService.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ public Role getUserRole() {
return roleRepository.findByType(RoleType.USER)
.orElseGet(() -> roleRepository.save(new Role(RoleType.USER)));
}

@Transactional
public Role getWithdrawnUserRole() {
return roleRepository.findByType(RoleType.WITHDRAWN_USER)
.orElseGet(() -> roleRepository.save(new Role(RoleType.WITHDRAWN_USER)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.ecolink.core.user.service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ecolink.core.user.domain.User;
import com.ecolink.core.user.repository.UserRepository;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Transactional(readOnly = true)
@Service
public class UserScheduleService {

private final UserRepository userRepository;
private final WithdrawService withdrawService;

@Transactional
@Scheduled(cron = "0 0 5 * * *")
public void delete() {
List<User> withdrawnUsers = userRepository.findAllByWithdrawn();
withdrawnUsers.stream()
.filter(user -> Duration.between(user.getWithdrawnDate(), LocalDateTime.now()).getSeconds() >= 604800)
.forEach(withdrawService::delete);
}
}
57 changes: 57 additions & 0 deletions src/main/java/com/ecolink/core/user/service/WithdrawService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.ecolink.core.user.service;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ecolink.core.avatar.repository.AvatarRepository;
import com.ecolink.core.bookmark.repository.BookmarkRepository;
import com.ecolink.core.common.error.ErrorCode;
import com.ecolink.core.common.error.exception.ManagerForbiddenException;
import com.ecolink.core.like.repository.ReviewLikeRepository;
import com.ecolink.core.review.repository.ReviewRepository;
import com.ecolink.core.review.repository.ReviewTagRepository;
import com.ecolink.core.store.repository.SearchHistoryRepository;
import com.ecolink.core.user.constant.RoleType;
import com.ecolink.core.user.domain.User;
import com.ecolink.core.user.repository.UserRepository;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Transactional(readOnly = true)
@Service
public class WithdrawService {

private final UserRepository userRepository;
private final AvatarRepository avatarRepository;
private final ReviewRepository reviewRepository;
private final ReviewLikeRepository reviewLikeRepository;
private final ReviewTagRepository reviewTagRepository;
private final BookmarkRepository bookmarkRepository;
private final SearchHistoryRepository searchHistoryRepository;
private final UserService userService;
private final RoleService roleService;

@Transactional
public void withdraw(Long userId) {
User user = userService.getUserGraphById(userId);
if (user.getRole().getType().equals(RoleType.MANAGER)) {
throw new ManagerForbiddenException(ErrorCode.MANAGER_WITHDRAWAL_DENIED);
}
user.withdraw(roleService.getWithdrawnUserRole());
}

@Transactional
public void delete(User user) {
user.getAvatars().forEach(avatar -> {
reviewTagRepository.deleteAllInBatch(reviewTagRepository.findAllByAvatarId(avatar.getId()));
reviewLikeRepository.deleteAllInBatch(reviewLikeRepository.findAllByAvatarId(avatar.getId()));
reviewRepository.deleteAllInBatch(reviewRepository.findAllByAvatarId(avatar.getId()));
bookmarkRepository.deleteAllInBatch(bookmarkRepository.findAllByAvatarId(avatar.getId()));
searchHistoryRepository.deleteAllInBatch(searchHistoryRepository.findAllByAvatarId(avatar.getId()));
});

avatarRepository.deleteAllInBatch(user.getAvatars());
userRepository.delete(user);
}
}