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
12 changes: 10 additions & 2 deletions src/main/java/com/payper/server/auth/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class AuthService {
private final JwtRefreshTokenUtil jwtRefreshTokenUtil;
private final JwtParseUtil jwtParseUtil;

public User findOrEnrollOAuthUser(OAuthUserInfo oauthUserInfo) {
private User findOrEnrollUser(OAuthUserInfo oauthUserInfo, UserRole userRole) {
//먼저 검증
Optional<User> user = userService.getActiveOAuthUser(oauthUserInfo);

Expand All @@ -52,7 +52,7 @@ public User findOrEnrollOAuthUser(OAuthUserInfo oauthUserInfo) {
AuthType.KAKAO,
oauthUserInfo.getName(),
oauthUserInfo.getOauthId(),
UserRole.USER,
userRole, // 매개변수 사용
true
)
);
Expand All @@ -65,6 +65,14 @@ public User findOrEnrollOAuthUser(OAuthUserInfo oauthUserInfo) {
);
}

public User findOrEnrollOAuthUser(OAuthUserInfo oauthUserInfo) {
return findOrEnrollUser(oauthUserInfo, UserRole.USER);
}

public User findOrEnrollOAuthAdminUser(OAuthUserInfo oauthUserInfo) {
return findOrEnrollUser(oauthUserInfo, UserRole.ADMIN);
}

public OAuthUserInfo findOAuthUserInfo(String oauthToken, AuthType authType) {
return switch (authType) {
case AuthType.KAKAO -> kakaoOAuthUtil.getUserInfoFromOAuthToken(oauthToken);
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/payper/server/auth/util/AuthDummyInit.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,26 @@ public void run(ApplicationArguments args) throws Exception {
"7777",
AuthType.KAKAO
);
OAuthUserInfo adminDummyOAuth1=new OAuthUserInfo(
"관리자",
"2222",
AuthType.KAKAO
);

User dummyUser1 = authService.findOrEnrollOAuthUser(dummyOAuth1);
User dummyUser2 = authService.findOrEnrollOAuthUser(dummyOAuth2);
User dummyUser3 = authService.findOrEnrollOAuthUser(dummyOAuth3);
User dummyUser4 = authService.findOrEnrollOAuthAdminUser(adminDummyOAuth1);

String accessToken1 = authService.enrollNewAuthTokens(dummyUser1, null);
String accessToken2 = authService.enrollNewAuthTokens(dummyUser2, null);
String accessToken3 = authService.enrollNewAuthTokens(dummyUser3, null);
String accessToken4 = authService.enrollNewAuthTokens(dummyUser4, null);

log.info("du1: name = {}, at = {}",dummyUser1.getName(),accessToken1);
log.info("du2: name = {}, at = {}",dummyUser2.getName(),accessToken2);
log.info("du3: name = {}, at = {}",dummyUser3.getName(),accessToken3);
log.info("admin du1: name = {}, at = {}",dummyUser4.getName(),accessToken4);
}


Expand Down
10 changes: 8 additions & 2 deletions src/main/java/com/payper/server/comment/entity/Comment.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import lombok.*;

import java.time.LocalDateTime;
import java.time.ZoneId;

@Entity
@Getter
Expand Down Expand Up @@ -89,8 +88,8 @@ public static Comment create(Post post, User user, Comment parentComment, String
.user(user)
.parentComment(parentComment)
.content(content)
.likeCount(0)
.isDeleted(false)
.deletedAt(null)
.build();
}

Expand All @@ -100,4 +99,11 @@ public static Comment create(Post post, User user, Comment parentComment, String
public void update(String content) {
this.content = content;
}

/**
* 댓글 작성자인지 판단
*/
public boolean isAuthor(Long userId) {
return this.user.getId().equals(userId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public void updateComment(Long userId, Long commentId, CommentRequest.UpdateComm
.orElseThrow(() -> new ApiException(ErrorCode.COMMENT_NOT_FOUND));

// 댓글 수정 권한 조회
if(!userId.equals(comment.getUser().getId())) {
if(!comment.isAuthor(userId)) {
throw new ApiException(ErrorCode.NOT_COMMENT_AUTHOR);
}

Expand All @@ -105,7 +105,7 @@ public void deleteComment(Long userId, Long commentId) {
.orElseThrow(() -> new ApiException(ErrorCode.COMMENT_NOT_FOUND));

// 댓글 삭제 권한 조회
if(!userId.equals(comment.getUser().getId())) {
if(!comment.isAuthor(userId)) {
throw new ApiException(ErrorCode.NOT_COMMENT_AUTHOR);
}

Expand Down Expand Up @@ -162,6 +162,9 @@ public CommentResponse.CommentList getPostComments(Long postId, Long cursorId, i
return CommentResponse.CommentList.from(comments.getContent(), nextCursor, comments.hasNext());
}

/**
* 자식 댓글 조회
*/
@Transactional(readOnly = true)
public CommentResponse.CommentList getReplies(Long parentId, Long cursorId, int size) {

Expand Down
11 changes: 10 additions & 1 deletion src/main/java/com/payper/server/global/response/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public enum ErrorCode {

// USER
USER_NOT_FOUND("USER-001", HttpStatus.NOT_FOUND, "User Not Found"),
NOT_AN_ADMIN("USER-002", HttpStatus.FORBIDDEN, "Not An Admin"),

// POST
POST_NOT_FOUND("POST-001", HttpStatus.NOT_FOUND, "Post Not Found"),
Expand All @@ -47,7 +48,15 @@ public enum ErrorCode {
INVALID_PARENT_COMMENT("COMMENT-004", HttpStatus.BAD_REQUEST, "Invalid parent comment"),

// MERCHANT
MERCHANT_NOT_FOUND("MERCHANT-001", HttpStatus.NOT_FOUND, "Merchant Not Found")
MERCHANT_NOT_FOUND("MERCHANT-001", HttpStatus.NOT_FOUND, "Merchant Not Found"),
MERCHANT_ALREADY_EXISTS("MERCHANT-002", HttpStatus.CONFLICT, "Merchant Already Exists"),

// CATEGORY
CATEGORY_NOT_FOUND("CATEGORY-001", HttpStatus.NOT_FOUND, "Category Not Found"),
CATEGORY_ALREADY_EXISTS("CATEGORY-002", HttpStatus.CONFLICT, "Category Already Exists"),
CATEGORY_DEPTH_EXCEEDED("CATEGORY-003", HttpStatus.BAD_REQUEST, "Category Depth Exceeded"),
CATEGORY_CANNOT_BE_SELF_PARENT("CATEGORY-004", HttpStatus.BAD_REQUEST, "Category Cannot Be Self Parent"),
PARENT_CATEGORY_CANNOT_HAVE_PARENT("CATEGORY-005", HttpStatus.BAD_REQUEST, "Parent Category Cannot Be Changed To A Child"),

;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.payper.server.merchant.controller;

import com.payper.server.global.response.ApiResponse;
import com.payper.server.merchant.dto.CategoryRequest;
import com.payper.server.merchant.dto.CategoryResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;

import java.util.List;

@Tag(name = "카테고리", description = "카테고리 등록/수정/조회 API")
public interface CategoryApi {

@Operation(summary = "카테고리 등록", description = "관리자만 등록 가능. depth는 최대 2.")
@SecurityRequirement(name = "bearerAuth")
ResponseEntity<ApiResponse<Long>> registerCategory(
@RequestBody CategoryRequest.RegisterCategory request
);

@Operation(summary = "카테고리 수정", description = "관리자만 수정 가능. 부모 카테고리는 이름만, 자식 카테고리는 이름과 부모 변경 가능.")
@SecurityRequirement(name = "bearerAuth")
ResponseEntity<ApiResponse<Void>> updateCategory(
@Parameter(description = "카테고리 ID", required = true, example = "1") Long categoryId,
@RequestBody CategoryRequest.UpdateCategory request
);

@Operation(summary = "카테고리 조회", description = "부모 카테고리 ID로 필터링 가능. 파라미터 미지정 시 부모 카테고리만 조회. 카테고리명 오름차순 정렬.", security = {})
ResponseEntity<ApiResponse<List<CategoryResponse.CategoryItem>>> getCategories(
@Parameter(description = "부모 카테고리 ID 필터", required = false) Long parentCategoryId
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.payper.server.merchant.controller;

import com.payper.server.global.response.ApiResponse;
import com.payper.server.merchant.dto.CategoryRequest;
import com.payper.server.merchant.dto.CategoryResponse;
import com.payper.server.merchant.service.CategoryService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/v1/categories")
@RequiredArgsConstructor
public class CategoryController implements CategoryApi {
private final CategoryService categoryService;

/**
* 카테고리 등록
* 관리자만 등록 가능
* depth는 최대 2
*/
@PreAuthorize("hasRole('ADMIN')")
Comment thread
khyun9807 marked this conversation as resolved.
@PostMapping()
public ResponseEntity<ApiResponse<Long>> registerCategory(
@RequestBody @Valid CategoryRequest.RegisterCategory request
) {
Long categoryId = categoryService.registerCategory(request);
return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.created(categoryId));
}

/**
* 카테고리 수정 (depth는 수정할 수 없음)
* 관리자만 수정 가능
* 부모 카테고리 -> 이름만 변경 가능
* 자식 카테고리 -> 이름, 부모 변경 가능
*/
@PreAuthorize("hasRole('ADMIN')")
@PutMapping("/{categoryId}")
public ResponseEntity<ApiResponse<Void>> updateCategory(
@PathVariable Long categoryId,
@RequestBody @Valid CategoryRequest.UpdateCategory request
) {
categoryService.updateCategory(categoryId, request);
return ResponseEntity.ok(ApiResponse.ok());
}

/**
* 카테고리 조회
*
* 필터링 조건
* 부모 카테고리
* 파라미터 안 넣으면 부모 카테고리만 보임
*
* 정렬 조건
* 카테고리명, 오름차순
*/
@GetMapping()
public ResponseEntity<ApiResponse<List<CategoryResponse.CategoryItem>>> getCategories(
@RequestParam(required = false) Long parentCategoryId
) {
List<CategoryResponse.CategoryItem> response = categoryService.getCategories(parentCategoryId);
return ResponseEntity.ok(ApiResponse.ok(response));
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,45 @@
package com.payper.server.merchant.controller;

import com.payper.server.global.response.ApiResponse;
import com.payper.server.merchant.dto.MerchantRequest;
import com.payper.server.merchant.dto.MerchantResponse;
import com.payper.server.post.dto.PostRequest;
import com.payper.server.security.CustomUserDetails;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;

@Tag(name = "가맹점", description = "가맹점 관련 API")
import java.util.List;

@Tag(name = "가맹점", description = "가맹점 등록/수정/조회 및 게시글 작성 API")
public interface MerchantApi {

@Operation(summary = "가맹점 등록", description = "관리자만 등록 가능. 카테고리를 선택하여 가맹점을 등록합니다.")
@SecurityRequirement(name = "bearerAuth")
ResponseEntity<ApiResponse<Long>> registerMerchant(
@RequestBody MerchantRequest.RegisterMerchant request
);

@Operation(summary = "가맹점 수정", description = "관리자만 수정 가능")
@SecurityRequirement(name = "bearerAuth")
ResponseEntity<ApiResponse<Void>> updateMerchant(
@Parameter(description = "가맹점 ID", required = true, example = "1") Long merchantId,
@RequestBody MerchantRequest.UpdateMerchant request
);

@Operation(summary = "가맹점 조회", description = "카테고리 ID로 필터링 가능. 가맹점명 오름차순 정렬.", security = {})
ResponseEntity<ApiResponse<List<MerchantResponse.MerchantItem>>> getMerchants(
@Parameter(description = "카테고리 ID 필터", required = false) Long categoryId
);

@Operation(summary = "게시글 작성", description = "가맹점에 대한 게시글을 작성합니다.")
@SecurityRequirement(name = "bearerAuth")
ResponseEntity<ApiResponse<Long>> createPost(
CustomUserDetails user,
@Parameter(description = "가맹점 ID", example = "1") Long merchantId,
PostRequest.CreatePost request
@Parameter(description = "가맹점 ID", example = "1", required = true) Long merchantId,
@RequestBody PostRequest.CreatePost request
);
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,75 @@
package com.payper.server.merchant.controller;

import com.payper.server.global.response.ApiResponse;
import com.payper.server.merchant.dto.MerchantRequest;
import com.payper.server.merchant.dto.MerchantResponse;
import com.payper.server.merchant.service.MerchantService;
import com.payper.server.post.dto.PostRequest;
import com.payper.server.post.service.PostService;
import com.payper.server.security.CustomUserDetails;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/v1/merchants")
@RequiredArgsConstructor
public class MerchantController implements MerchantApi {
private final MerchantService merchantService;
private final PostService postService;

/**
* 가맹점 등록
*
* 관리자만 등록 가능
* 카테고리 리스트에서 카테고리를 선택해서 해당 카테고리의 id를 넘겨 받음
*/
@PreAuthorize("hasRole('ADMIN')")
@PostMapping()
public ResponseEntity<ApiResponse<Long>> registerMerchant(
@RequestBody @Valid MerchantRequest.RegisterMerchant request
) {
Long merchantId = merchantService.registerMerchant(request);
return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.created(merchantId));
}

/**
* 가맹점 수정
* 관리자만 수정 가능
*/
@PreAuthorize("hasRole('ADMIN')")
@PutMapping("/{merchantId}")
public ResponseEntity<ApiResponse<Void>> updateMerchant(
@PathVariable Long merchantId,
@RequestBody @Valid MerchantRequest.UpdateMerchant request
) {
merchantService.updateMerchant(merchantId, request);
return ResponseEntity.ok(ApiResponse.ok());
}

/**
* 가맹점 조회
*
* 필터링 조건
* 카테고리
*
* 정렬 조건
* 가맹점명, 오름차순
*/
@GetMapping()
public ResponseEntity<ApiResponse<List<MerchantResponse.MerchantItem>>> getMerchants(
@RequestParam(required = false) Long categoryId
) {
List<MerchantResponse.MerchantItem> response = merchantService.getMerchants(categoryId);
return ResponseEntity.ok(ApiResponse.ok(response));
}

/**
* 게시글 작성
* 가맹점에 대해 글을 작성함
Expand All @@ -31,6 +85,6 @@ public ResponseEntity<ApiResponse<Long>> createPost(
@RequestBody @Valid PostRequest.CreatePost request
) {
Long postId = postService.createPost(user.getId(), merchantId, request);
return ResponseEntity.status(201).body(ApiResponse.created(postId));
return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.created(postId));
}
}
}
Loading