diff --git a/build.gradle b/build.gradle index 72bda1e5..3211b39d 100644 --- a/build.gradle +++ b/build.gradle @@ -44,6 +44,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation 'io.jsonwebtoken:jjwt:0.9.1' // 자바 jwt 라이브러리 implementation 'io.jsonwebtoken:jjwt-api:0.11.2' + annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" implementation 'javax.xml.bind:jaxb-api:2.3.1' // XML 문서와 Java 객체 간 매핑을 자동화 implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' // aws s3 diff --git a/config b/config index 80f8e462..d8e0093e 160000 --- a/config +++ b/config @@ -1 +1 @@ -Subproject commit 80f8e4625eeb7370198551642b111a3eca7e6b84 +Subproject commit d8e0093ed7c949c75286aa6ad1486698ec240eff diff --git a/src/main/java/com/example/ReviewZIP/domain/follow/Follows.java b/src/main/java/com/example/ReviewZIP/domain/follow/Follows.java index 50164dfa..2cb275cd 100644 --- a/src/main/java/com/example/ReviewZIP/domain/follow/Follows.java +++ b/src/main/java/com/example/ReviewZIP/domain/follow/Follows.java @@ -3,13 +3,13 @@ import com.example.ReviewZIP.domain.user.Users; import com.example.ReviewZIP.global.entity.BaseEntity; import jakarta.persistence.*; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.*; @Entity @Getter @Setter +@Builder +@AllArgsConstructor @NoArgsConstructor @Table(name = "follows") public class Follows extends BaseEntity { diff --git a/src/main/java/com/example/ReviewZIP/domain/follow/FollowsController.java b/src/main/java/com/example/ReviewZIP/domain/follow/FollowsController.java new file mode 100644 index 00000000..f96dfa71 --- /dev/null +++ b/src/main/java/com/example/ReviewZIP/domain/follow/FollowsController.java @@ -0,0 +1,52 @@ +package com.example.ReviewZIP.domain.follow; + +import com.example.ReviewZIP.global.response.ApiResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/v1/follows") +public class FollowsController { + private final FollowsService followsService; + + @PostMapping("/users/{userId}") + @Operation(summary = "유저 팔로우 하기 API",description = "유저의 id를 받아 해당 유저 팔로우") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "USER404", description = "팔로우 할 유저가 존재하지 않습니다",content = @Content(schema = @Schema(implementation = ApiResponse.class))), + }) + @Parameters({ + @Parameter(name = "userId", description = "팔로우할 유저의 아이디"), + }) + public ApiResponse follow(@PathVariable(name="userId") Long userId) { + Follows follows = followsService.createFollowing(userId); + + return ApiResponse.onSuccess(null); + } + + @DeleteMapping("/users/{userId}") + @Operation(summary = " 유저 언팔로우 하기 API",description = "유저의 id를 받아 해당 유저 언팔로우") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "USER404", description = "언팔로우 할 유저가 존재하지 않습니다",content = @Content(schema = @Schema(implementation = ApiResponse.class))), + }) + @Parameters({ + @Parameter(name = "userId", description = "팔로우 취소할 유저의 아이디"), + }) + public ApiResponse unfollowUser(@PathVariable(name="userId")Long userId){ + followsService.unfollowUser(userId); + + return ApiResponse.onSuccess(null); + } +} diff --git a/src/main/java/com/example/ReviewZIP/domain/follow/FollowsConverter.java b/src/main/java/com/example/ReviewZIP/domain/follow/FollowsConverter.java new file mode 100644 index 00000000..f4729a91 --- /dev/null +++ b/src/main/java/com/example/ReviewZIP/domain/follow/FollowsConverter.java @@ -0,0 +1,13 @@ +package com.example.ReviewZIP.domain.follow; + +import com.example.ReviewZIP.domain.user.Users; + +public class FollowsConverter { + public static Follows toFollows(Users sender, Users receiver){ + return Follows.builder() + .sender(sender) + .receiver(receiver) + .build(); + } + +} diff --git a/src/main/java/com/example/ReviewZIP/domain/follow/FollowsRepository.java b/src/main/java/com/example/ReviewZIP/domain/follow/FollowsRepository.java index ca54f865..0dd44594 100644 --- a/src/main/java/com/example/ReviewZIP/domain/follow/FollowsRepository.java +++ b/src/main/java/com/example/ReviewZIP/domain/follow/FollowsRepository.java @@ -6,8 +6,11 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; + @Repository public interface FollowsRepository extends JpaRepository { Page findAllBySender(Users sender, PageRequest pageRequest); Page findAllByReceiver(Users user, PageRequest pageRequest); + + Follows getBySenderAndReceiver(Users sender, Users receiver); } diff --git a/src/main/java/com/example/ReviewZIP/domain/follow/FollowsService.java b/src/main/java/com/example/ReviewZIP/domain/follow/FollowsService.java new file mode 100644 index 00000000..22fe2ae9 --- /dev/null +++ b/src/main/java/com/example/ReviewZIP/domain/follow/FollowsService.java @@ -0,0 +1,38 @@ +package com.example.ReviewZIP.domain.follow; + + +import com.example.ReviewZIP.domain.user.Users; +import com.example.ReviewZIP.domain.user.UsersRepository; +import com.example.ReviewZIP.global.response.code.resultCode.ErrorStatus; +import com.example.ReviewZIP.global.response.exception.handler.UsersHandler; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class FollowsService { + private final FollowsRepository followsRepository; + private final UsersRepository usersRepository; + + + @Transactional + public Follows createFollowing(Long userId) { + Users sender = usersRepository.getById(1L); + Users receiver = usersRepository.findById(userId).orElseThrow(() -> new UsersHandler(ErrorStatus.USER_NOT_FOUND)); + + Follows newFollow = FollowsConverter.toFollows(sender, receiver); + return followsRepository.save(newFollow); + } + + @Transactional + public void unfollowUser(Long userId){ + Users sender = usersRepository.findById(1L).orElseThrow(()->new UsersHandler(ErrorStatus.USER_NOT_FOUND)); + Users receiver = usersRepository.findById(userId).orElseThrow(()->new UsersHandler(ErrorStatus.USER_NOT_FOUND)); + + Follows unfollow = followsRepository.getBySenderAndReceiver(sender, receiver); + + followsRepository.delete(unfollow); + } +} diff --git a/src/main/java/com/example/ReviewZIP/domain/jwt/JwtProperties.java b/src/main/java/com/example/ReviewZIP/domain/jwt/JwtProperties.java new file mode 100644 index 00000000..72723b6a --- /dev/null +++ b/src/main/java/com/example/ReviewZIP/domain/jwt/JwtProperties.java @@ -0,0 +1,20 @@ +package com.example.ReviewZIP.domain.jwt; + +import lombok.Getter; +import lombok.Setter; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@Component +@ConfigurationProperties("jwt") +public class JwtProperties { + @Value("${jwt.issuer}") + private String issuer; + + @Value("${jwt.secretKey}") + private String secretKey; +} diff --git a/src/main/java/com/example/ReviewZIP/domain/jwt/TokenProvider.java b/src/main/java/com/example/ReviewZIP/domain/jwt/TokenProvider.java new file mode 100644 index 00000000..816f0512 --- /dev/null +++ b/src/main/java/com/example/ReviewZIP/domain/jwt/TokenProvider.java @@ -0,0 +1,54 @@ +package com.example.ReviewZIP.domain.jwt; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Header; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Date; + +@RequiredArgsConstructor +@Service +public class TokenProvider { + private final JwtProperties jwtProperties; + + public String makeToken(Long userId){ + Date now = new Date(); + Date exp = new Date(now.getTime() + 3600000); //1시간 만료 기준 + Claims claims = Jwts.claims(); + claims.put("userid", userId); + + return Jwts.builder() + .setHeaderParam(Header.TYPE, Header.JWT_TYPE) + .setIssuer(jwtProperties.getIssuer()) + .setIssuedAt(now) + .setExpiration(exp) + .setClaims(claims) + //.setSubject(userId.toString()) + .signWith(SignatureAlgorithm.HS256, jwtProperties.getSecretKey()) + .compact(); + } + + public Long getUserId(String token){ + Claims claims = Jwts.parser() + .setSigningKey(jwtProperties.getSecretKey()) + .parseClaimsJws(token) + .getBody(); + return claims.get("userId", Long.class); + } + + public boolean validToken(String token){ + try{ + Jwts.parser() + .setSigningKey(jwtProperties.getSecretKey()) + .parseClaimsJws(token); + return true; + } catch(Exception e){ + return false; + } + } + + +} diff --git a/src/main/java/com/example/ReviewZIP/domain/oauth/KakaoController.java b/src/main/java/com/example/ReviewZIP/domain/oauth/KakaoController.java new file mode 100644 index 00000000..7ecfee96 --- /dev/null +++ b/src/main/java/com/example/ReviewZIP/domain/oauth/KakaoController.java @@ -0,0 +1,29 @@ +package com.example.ReviewZIP.domain.oauth; + +import com.example.ReviewZIP.domain.jwt.TokenProvider; +import com.example.ReviewZIP.domain.oauth.dto.request.OauthRequestDto; +import com.example.ReviewZIP.global.response.ApiResponse; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/v1/oauth") +public class KakaoController { + + private final OauthService oauthService; + + // 유저 관련 token 받은 후 해당 정보로 accessToken 발급 + @PostMapping("/kakao") + public ApiResponse> sendAccessToken(@RequestBody OauthRequestDto.kakaoTokenRequest request) throws JsonProcessingException { + + List kakaoUserInfoList = oauthService.getKakaoUserInfo(request); + + return ApiResponse.onSuccess(oauthService.generateAccessToken(kakaoUserInfoList.get(0),kakaoUserInfoList.get(1) , kakaoUserInfoList.get(2))); + + } +} diff --git a/src/main/java/com/example/ReviewZIP/domain/oauth/OauthService.java b/src/main/java/com/example/ReviewZIP/domain/oauth/OauthService.java new file mode 100644 index 00000000..f5ec4f74 --- /dev/null +++ b/src/main/java/com/example/ReviewZIP/domain/oauth/OauthService.java @@ -0,0 +1,92 @@ +package com.example.ReviewZIP.domain.oauth; + +import com.example.ReviewZIP.domain.jwt.TokenProvider; +import com.example.ReviewZIP.domain.oauth.dto.request.OauthRequestDto; +import com.example.ReviewZIP.domain.user.Users; +import com.example.ReviewZIP.domain.user.UsersRepository; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import java.util.*; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class OauthService { + private final UsersRepository usersRepository; + private final TokenProvider tokenProvider; + + @Transactional + public Long createUser(String id, String nickname, String email){ + Users newUser = Users.builder() + .social(id) + .nickname(nickname) + .name(nickname) + .email(email) + .build(); + usersRepository.save(newUser); + + return newUser.getId(); + } + + @Transactional + public Map generateAccessToken(String id, String nickname, String email){ + boolean exist = usersRepository.existsBySocial(id); + Long userId; + + if(!exist) { + // 유저가 존재하지 않을때 -> 유저 생성 + userId = createUser(id, nickname, email); + } else { + // 존재할 경우 해당 유저의 userId 반환 + userId = usersRepository.getBySocial(id).getId(); + } + + String accessToken = tokenProvider.makeToken(userId); + + Map map = new LinkedHashMap<>(); + map.put("accessToken", accessToken); + + return map; + } + + public List getKakaoUserInfo(OauthRequestDto.kakaoTokenRequest request) throws JsonProcessingException { + String token = request.getToken(); + + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); + headers.set("Authorization", "Bearer " + token); + + HttpEntity> kakaoProfileRequest = new HttpEntity<>(null, headers); + + RestTemplate restTemplate = new RestTemplate(); + + ResponseEntity response = restTemplate.exchange( + "https://kapi.kakao.com/v2/user/me", + HttpMethod.POST, + kakaoProfileRequest, + String.class + ); + + ObjectMapper objectMapper = new ObjectMapper(); + String responseBody = response.getBody(); + JsonNode jsonNode = objectMapper.readTree(responseBody); + String id = jsonNode.get("id").asText(); + String nickname = jsonNode.get("properties").get("nickname").asText(); + String email = jsonNode.get("kakao_account").get("email").asText(); + + List kakaoUserInfoList = Arrays.asList(id, nickname, email); + + return kakaoUserInfoList; + } +} diff --git a/src/main/java/com/example/ReviewZIP/domain/oauth/dto/Response/OauthResponseDto.java b/src/main/java/com/example/ReviewZIP/domain/oauth/dto/Response/OauthResponseDto.java new file mode 100644 index 00000000..945907a7 --- /dev/null +++ b/src/main/java/com/example/ReviewZIP/domain/oauth/dto/Response/OauthResponseDto.java @@ -0,0 +1,9 @@ +package com.example.ReviewZIP.domain.oauth.dto.Response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + + +public class OauthResponseDto { + +} diff --git a/src/main/java/com/example/ReviewZIP/domain/oauth/dto/request/OauthRequestDto.java b/src/main/java/com/example/ReviewZIP/domain/oauth/dto/request/OauthRequestDto.java new file mode 100644 index 00000000..0a121d8d --- /dev/null +++ b/src/main/java/com/example/ReviewZIP/domain/oauth/dto/request/OauthRequestDto.java @@ -0,0 +1,12 @@ +package com.example.ReviewZIP.domain.oauth.dto.request; + +import lombok.Getter; + + +public class OauthRequestDto { + + @Getter + public static class kakaoTokenRequest{ + String token; + } +} diff --git a/src/main/java/com/example/ReviewZIP/domain/post/Posts.java b/src/main/java/com/example/ReviewZIP/domain/post/Posts.java index d15fe779..b97003d7 100644 --- a/src/main/java/com/example/ReviewZIP/domain/post/Posts.java +++ b/src/main/java/com/example/ReviewZIP/domain/post/Posts.java @@ -7,6 +7,7 @@ import com.example.ReviewZIP.domain.store.Stores; import com.example.ReviewZIP.domain.user.Users; import com.example.ReviewZIP.global.entity.BaseEntity; + import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; @@ -21,6 +22,7 @@ @NoArgsConstructor @Table(name = "posts") public class Posts extends BaseEntity { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") diff --git a/src/main/java/com/example/ReviewZIP/domain/post/PostsController.java b/src/main/java/com/example/ReviewZIP/domain/post/PostsController.java index a96d7b43..a473ca68 100644 --- a/src/main/java/com/example/ReviewZIP/domain/post/PostsController.java +++ b/src/main/java/com/example/ReviewZIP/domain/post/PostsController.java @@ -32,7 +32,7 @@ public class PostsController { @Operation(summary = "특정 게시글의 정보 가져오기 API",description = "게시글의 id를 이용하여 상세정보 출력, UserInfoDto & ImageListDto & PostInfoDto 이용") @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "POST401", description = "해당 게시물이 존재하지 않음",content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "POST401", description = "해당 게시물이 존재하지 않습니다.",content = @Content(schema = @Schema(implementation = ApiResponse.class))), }) @Parameters({ @Parameter(name = "postId", description = "게시글의 아이디"), diff --git a/src/main/java/com/example/ReviewZIP/domain/post/PostsService.java b/src/main/java/com/example/ReviewZIP/domain/post/PostsService.java index 1675046d..3ee7ab54 100644 --- a/src/main/java/com/example/ReviewZIP/domain/post/PostsService.java +++ b/src/main/java/com/example/ReviewZIP/domain/post/PostsService.java @@ -103,4 +103,6 @@ public PostResponseDto.PostInfoDto getPostInfoDto(Long postId){ return PostsConverter.toPostInfoResultDto(post, checkLike, checkScrab); } + + } \ No newline at end of file diff --git a/src/main/java/com/example/ReviewZIP/domain/scrab/Scrabs.java b/src/main/java/com/example/ReviewZIP/domain/scrab/Scrabs.java index 96d4fe23..db1fe445 100644 --- a/src/main/java/com/example/ReviewZIP/domain/scrab/Scrabs.java +++ b/src/main/java/com/example/ReviewZIP/domain/scrab/Scrabs.java @@ -3,6 +3,7 @@ import com.example.ReviewZIP.domain.user.Users; import com.example.ReviewZIP.global.entity.BaseEntity; import com.example.ReviewZIP.domain.post.Posts; + import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; diff --git a/src/main/java/com/example/ReviewZIP/domain/user/Users.java b/src/main/java/com/example/ReviewZIP/domain/user/Users.java index 7b84047a..0265fde0 100644 --- a/src/main/java/com/example/ReviewZIP/domain/user/Users.java +++ b/src/main/java/com/example/ReviewZIP/domain/user/Users.java @@ -6,9 +6,9 @@ import com.example.ReviewZIP.domain.scrab.Scrabs; import com.example.ReviewZIP.global.entity.BaseEntity; import jakarta.persistence.*; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.*; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.Where; import java.util.ArrayList; import java.util.List; @@ -16,6 +16,10 @@ @Entity @Getter @Setter +@Builder +@AllArgsConstructor +@Where(clause = "status = 'ENABLED'") +@SQLDelete(sql = "UPDATE reviewzip.users SET status = 'DISABLED' WHERE id = ?") @NoArgsConstructor @Table(name = "users") public class Users extends BaseEntity { diff --git a/src/main/java/com/example/ReviewZIP/domain/user/UsersController.java b/src/main/java/com/example/ReviewZIP/domain/user/UsersController.java index f9e2e978..6284e640 100644 --- a/src/main/java/com/example/ReviewZIP/domain/user/UsersController.java +++ b/src/main/java/com/example/ReviewZIP/domain/user/UsersController.java @@ -1,7 +1,13 @@ package com.example.ReviewZIP.domain.user; +import com.example.ReviewZIP.domain.follow.Follows; +import com.example.ReviewZIP.domain.post.Posts; +import com.example.ReviewZIP.domain.scrab.Scrabs; +import com.example.ReviewZIP.domain.user.dto.response.FollowResponseDto; import com.example.ReviewZIP.domain.user.dto.response.UserResponseDto; import com.example.ReviewZIP.global.response.ApiResponse; +import com.example.ReviewZIP.global.response.code.resultCode.ErrorStatus; +import com.example.ReviewZIP.global.response.exception.handler.PostsHandler; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; @@ -10,17 +16,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import com.example.ReviewZIP.domain.follow.Follows; -import com.example.ReviewZIP.domain.post.Posts; -import com.example.ReviewZIP.domain.scrab.Scrabs; -import com.example.ReviewZIP.global.response.code.resultCode.ErrorStatus; -import com.example.ReviewZIP.global.response.exception.handler.PostsHandler; import org.springframework.web.bind.annotation.*; -import com.example.ReviewZIP.domain.user.dto.response.FollowResponseDto; @RestController @RequiredArgsConstructor @@ -60,7 +56,6 @@ public ApiResponse searchUsersByNickname(@Re @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"), @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "USER404", description = "유저가 존재하지 않습니다",content = @Content(schema = @Schema(implementation = ApiResponse.class))), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "USER406", description = "팔로잉 목록이 존재하지 않습니다",content = @Content(schema = @Schema(implementation = ApiResponse.class))), }) @Parameters({ @Parameter(name = "userId", description = "유저의 아이디"), @@ -79,7 +74,6 @@ public ApiResponse getOtherFollowingL @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"), @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "USER404", description = "유저가 존재하지 않습니다",content = @Content(schema = @Schema(implementation = ApiResponse.class))), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "POST405", description = "팔로워 목록이 존재하지 않습니다",content = @Content(schema = @Schema(implementation = ApiResponse.class))), }) @Parameters({ @Parameter(name = "userId", description = "유저의 아이디"), @@ -99,7 +93,6 @@ public ApiResponse getOtherFollowerLis @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"), @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "USER404", description = "유저가 존재하지 않습니다",content = @Content(schema = @Schema(implementation = ApiResponse.class))), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "POST406", description = "게시글 목록이 존재하지 않습니다",content = @Content(schema = @Schema(implementation = ApiResponse.class))), }) @Parameters({ @Parameter(name = "userId", description = "유저의 아이디"), @@ -124,19 +117,31 @@ public ApiResponse getOtherPostList(@PathVar @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"), @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "USER404", description = "유저가 존재하지 않습니다",content = @Content(schema = @Schema(implementation = ApiResponse.class))), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "POST406", description = "게시글 목록이 존재하지 않습니다",content = @Content(schema = @Schema(implementation = ApiResponse.class))), }) @Parameters({ @Parameter(name = "userId", description = "유저의 아이디"), @Parameter(name = "page", description = "페이지 번호"), @Parameter(name = "size", description = "페이징 사이즈") }) - public ApiResponse getOtherScrabList(@PathVariable(name = "userId") Long userId, @RequestParam(name = "page")Integer page, @RequestParam(name = "size") Integer size){ - Page UserPage = usersService.getOtherScrabList(userId,page, size); + public ApiResponse getOtherScrabList(@PathVariable(name = "userId") Long userId, @RequestParam(name = "page")Integer page, @RequestParam(name = "size") Integer size) { + Page UserPage = usersService.getOtherScrabList(userId, page, size); - if(UserPage.isEmpty()){ - throw new PostsHandler(ErrorStatus.SCRAB_LIST_NOT_FOUND); - } - return ApiResponse.onSuccess(UsersConverter.toScrabPreviewListDto(UserPage)); + return ApiResponse.onSuccess(UsersConverter.toScrabPreviewListDto(UserPage)); + } + + // 유저 삭제하기 + @DeleteMapping("/{userId}") + @Operation(summary = "유저 삭제하기 API",description = "유저를 삭제") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공"), + }) + @Parameters({ + @Parameter(name = "userId", description = "유저의 아이디"), + @Parameter(name = "page", description = "페이지 번호"), + @Parameter(name = "size", description = "페이징 사이즈") + }) + public ApiResponse deleteUser(@PathVariable(name = "userId")Long userId) { + usersService.deleteUser(userId); + return ApiResponse.onSuccess(null); } } diff --git a/src/main/java/com/example/ReviewZIP/domain/user/UsersRepository.java b/src/main/java/com/example/ReviewZIP/domain/user/UsersRepository.java index 1a9aa7e5..6b5d8a6b 100644 --- a/src/main/java/com/example/ReviewZIP/domain/user/UsersRepository.java +++ b/src/main/java/com/example/ReviewZIP/domain/user/UsersRepository.java @@ -10,4 +10,8 @@ public interface UsersRepository extends JpaRepository { Page findByName(String name, Pageable pageable); Page findByNickname(String nickname, Pageable pageable); + + boolean existsBySocial(String id); + + Users getBySocial(String userId); } diff --git a/src/main/java/com/example/ReviewZIP/domain/user/UsersService.java b/src/main/java/com/example/ReviewZIP/domain/user/UsersService.java index 6d683ca4..3f8e5e8f 100644 --- a/src/main/java/com/example/ReviewZIP/domain/user/UsersService.java +++ b/src/main/java/com/example/ReviewZIP/domain/user/UsersService.java @@ -103,4 +103,13 @@ public Page getOtherScrabList(Long userId, Integer page, Integer size){ return UserPage; } + + // 해당 유저가 맞는지에 대한 검증 필요, 원래 1L 필요하나 일단 데이터베이스 확인을 위하여 다음과 같이 진행 + @Transactional + public void deleteUser(Long userId){ + Users user = usersRepository.findById(userId).orElseThrow(()->new UsersHandler(ErrorStatus.USER_NOT_FOUND)); + + usersRepository.deleteById(userId); + + } } diff --git a/src/main/java/com/example/ReviewZIP/global/response/code/resultCode/ErrorStatus.java b/src/main/java/com/example/ReviewZIP/global/response/code/resultCode/ErrorStatus.java index 809dd9c5..176e61bb 100644 --- a/src/main/java/com/example/ReviewZIP/global/response/code/resultCode/ErrorStatus.java +++ b/src/main/java/com/example/ReviewZIP/global/response/code/resultCode/ErrorStatus.java @@ -29,6 +29,7 @@ public enum ErrorStatus implements BaseErrorCode { NICKNAME_NOT_FOUND(HttpStatus.NOT_FOUND, "USER407", "존재하지 않는 유저 닉네임입니다."), NAME_NOT_FOUND(HttpStatus.NOT_FOUND, "USER408", "존재하지 않는 유저 이름입니다."), USER_CREATE_FAIL(HttpStatus.BAD_REQUEST,"USER409", "유저 생성에 실패하였습니다."), + USER_DELETE_FAIL(HttpStatus.BAD_REQUEST,"USER410", "유저 삭제에 실패하였습니다."), // Post @@ -48,9 +49,10 @@ public enum ErrorStatus implements BaseErrorCode { // Image IMAGE_NOT_FOUND(HttpStatus.NOT_FOUND, "IMAGE401", "파일이 존재하지 않습니다."), - IMAGE_UPLOAD_FAIL(HttpStatus.BAD_REQUEST, "IMAGE402", "이미지 업로드에 실패하였습니다."); - + IMAGE_UPLOAD_FAIL(HttpStatus.BAD_REQUEST, "IMAGE402", "이미지 업로드에 실패하였습니다."), + // Follow + FOLLOW_ALREADY(HttpStatus.BAD_REQUEST, "FOLLOW401", "이미 팔로우한 상태입니다."); private final HttpStatus httpStatus; private final String code;