Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Artscope 3.1.4 릴리즈 #164

Merged
merged 119 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
ddef45e
chore: Add PULL_REQUEST_TEMPLATE.md
Hoon9901 Mar 22, 2024
ff091e1
feat: sql문 작성
haroya01 Mar 24, 2024
83422a7
feat: 변경된 MagazineCategory entity jpa 매핑
haroya01 Mar 24, 2024
efce981
feat: magazineRequest,response 변경 사항에 맞게 dto 변경
haroya01 Mar 24, 2024
04f84ff
feat: magazineCategory api 추가
haroya01 Mar 24, 2024
3a5bfbd
test: 변경된 내용에 맞게 테스트 코드 수정
haroya01 Mar 24, 2024
ed0e1a0
test: 변경된 내용에 맞게 테스트 코드 수정
haroya01 Mar 25, 2024
5b5a4f6
feat: 부모 카테고리도 함께 반환하도록 추가
haroya01 Mar 25, 2024
743375c
refactor: 카테고리 생성, 수정시 반환하는 response 분할에 따른 로직 변경
haroya01 Mar 25, 2024
c0c64f4
feat: 카테고리 삭제, 생성시 조건 추가
haroya01 Mar 25, 2024
60f0a52
test: 테스트 코드 수정
haroya01 Mar 25, 2024
c8fdb21
test: 테스트 코드 랜덤 조건 수정
haroya01 Mar 25, 2024
e11c836
test: 테스트 코드 랜덤 조건 수정
haroya01 Mar 25, 2024
cb09c27
test: 테스트 코드 랜덤으로 생성한 categorySlug 올바르게 생성하도록 수정
haroya01 Mar 25, 2024
5c9d856
test: 카테고리 깊이가 3단계 이상 생성시 에러 검증 테스트 코드 추가
haroya01 Mar 26, 2024
2b24cb8
refactor: magazineCategory 부모 변경 매서드 이름 변경
haroya01 Mar 26, 2024
32715e6
refactor: 슬러그 중복 카테고리 검증 로직 변경
haroya01 Mar 26, 2024
1064dcd
test: 테스트 코드 수정 및 추가
haroya01 Mar 26, 2024
d3cbdc6
feat: 메거진 수정시 categoryId를 수정할수 있도록 변경
haroya01 Mar 26, 2024
c1483a0
refactor: 사용하지 않는 매서드 제거
haroya01 Mar 26, 2024
33a2c4f
test: 테스트 코드 추가
haroya01 Mar 26, 2024
067daa7
refactor: magazine 생성, 수정시 categorySlug를 받도록 변경
haroya01 Mar 27, 2024
26188d3
test: 테스트 코드 수정
haroya01 Mar 27, 2024
09900bf
test: 테스트 코드 추가
haroya01 Mar 27, 2024
45c8d56
Merge branch 'develop' into ART-159-be-카테고리-계층화
haroya01 Mar 27, 2024
210f1e0
Merge pull request #154 from Media-XI/ART-159-be-카테고리-계층화
haroya01 Mar 27, 2024
c4868c1
feat: group,group_user 테이블 생성
haroya01 Mar 28, 2024
61761c7
feat: 추가된 테이블에 대한 entity 클래스 작성
haroya01 Mar 28, 2024
c8c6cb5
refactor: 누락된 변경 내용 추가
haroya01 Mar 28, 2024
00af055
refactor: @WHERE이 @Deprecated에 따라 soft-delete 전략 변경
haroya01 Mar 28, 2024
5156004
feat: Group -> Team 으로 변경됨에 따른 SQL 스크립트 수정
Hoon9901 Mar 28, 2024
243c1bb
feat: Group -> Team 으로 변경됨에 따른 도메인 관련 클래스 수정
Hoon9901 Mar 28, 2024
55d84d1
test: Team SoftDelete 테스트 코드 작성
Hoon9901 Mar 28, 2024
0ba84a8
merge
Hoon9901 Mar 28, 2024
916b344
feat: 팀 팔로잉 기능을 위한 DDL 스크립트 작성
Hoon9901 Mar 31, 2024
b9d72c2
feat: 팀 팔로잉 기능을 위한 기존 팔로잉 엔티티 코드 변경
Hoon9901 Mar 31, 2024
caba3e4
fix: V202403051155__application.sql 누락된 DDL 스크립트 추가
Hoon9901 Mar 31, 2024
8faf358
feat: 엔티티 클래스 작성
haroya01 Mar 31, 2024
15145ab
feat: Team 관련 crud 작성
haroya01 Mar 31, 2024
d3ab2e1
feat: TeamUser 관련 crud 작성
haroya01 Mar 31, 2024
0cd7ea3
feat: member 삭제시 본인이 팀장인 팀이 있으면 에러를 반환하도록 추가
haroya01 Mar 31, 2024
7751e0c
test: 테스트 코드 작성
haroya01 Mar 31, 2024
46698ca
test: testUser관련 테스트 코드 추가
haroya01 Apr 1, 2024
63d8439
refactor: restful 하게 api 변경
haroya01 Apr 1, 2024
f3ace61
test: 변경된 api에 맞게 테스트 코드 수정
haroya01 Apr 1, 2024
b253513
refactor: FollowIds 복합키 제거에 따른 리팩터링
Hoon9901 Apr 2, 2024
d148c00
refactor: Following -> FollowingMember 변수명 변경에 따른 리팩터링
Hoon9901 Apr 2, 2024
c0e8c2f
refactor: Follow API 리팩터링 및 테스트 코드 추가
Hoon9901 Apr 2, 2024
fb7b040
feat: 팔로잉/팔로우 팀 기능 확장 및 리팩터링 / API 호출 개선
Hoon9901 Apr 2, 2024
33bcaa7
merge: ART-169-그룹-crud-그룹-인가-로직 -> ART-174-be-그룹-팔로잉-기능
Hoon9901 Apr 2, 2024
cb18d4a
feat: Member 팔로잉 관련 양방향 제거
Hoon9901 Apr 2, 2024
f774343
refactor: 팔로우 API 리팩터링
Hoon9901 Apr 2, 2024
dc4f098
test: Follow API 테스트 코드 작성
Hoon9901 Apr 2, 2024
849aece
feat: 팀 팔로우로 인한 팔로우 목록 조회쿼리 변경 및 관련 DTO 수정
Hoon9901 Apr 2, 2024
82b9b92
test: 팀 팔로잉에 따른 테스트 코드 수정
Hoon9901 Apr 2, 2024
51e4b53
feat: FollowEntityUrn 예외처리 메시지 변경
Hoon9901 Apr 2, 2024
4e342c7
feat: 팔로우 여부 예외처리 메시지 수정
Hoon9901 Apr 2, 2024
465343b
feat: 팔로우 API Swagger Metadata 작성
Hoon9901 Apr 2, 2024
02f5571
Merge pull request #155 from Media-XI/ART-169-그룹-crud-그룹-인가-로직
Hoon9901 Apr 2, 2024
8f21dfa
Merge branch 'develop' into ART-174-be-그룹-팔로잉-기능
Hoon9901 Apr 2, 2024
2f35a4c
Merge pull request #156 from Media-XI/ART-174-be-그룹-팔로잉-기능
Hoon9901 Apr 3, 2024
ab638fb
feat: sql문 작성
haroya01 Apr 7, 2024
603809b
feat: team_id에 대한 jpa 매핑
haroya01 Apr 7, 2024
c8a4d48
feat: MagazineRequest.Create dto에 urn값을 받을수 있도록 추가
haroya01 Apr 7, 2024
3363ec1
feat: 매거진 관련 api에 팀 기능 추가
haroya01 Apr 7, 2024
a8af558
feat: 중복 매거진 생성 요청을 방지하는 AOP로직 추가
haroya01 Apr 7, 2024
dbd80e3
test: 테스트 코드 수정 및 추가
haroya01 Apr 7, 2024
f685a15
refactor: 매거진 생성시 잘못 작성된 swagger 스키마 수정
haroya01 Apr 7, 2024
27dce7b
feat: SecurityUtil getLoginUsername() 메서드 추가
Hoon9901 Apr 9, 2024
6244ce2
feat: MagazineWithIsLiked 엔티티 추가 및 MagazineRepository 좋아요 여부를 포함하는 쿼리…
Hoon9901 Apr 9, 2024
20c42af
feat: MagazineService 전체 조회 및 단일 조회 로직 변경
Hoon9901 Apr 9, 2024
37c2e4a
test: 매거진 좋아요 여부에 따른 조회 관련 유스케이스 테스트 코드 작성
Hoon9901 Apr 9, 2024
7915c85
feat: @CheckDuplicatedRequest에 기본값 추가
haroya01 Apr 9, 2024
50177dd
feat: CheckDuplicatedRequestAspect 관련 로직 변경
haroya01 Apr 9, 2024
ca6b216
refactor: 매거진 생성, 조회시 api 변경
haroya01 Apr 9, 2024
c0a5ffe
test: 테스트 코드 변경 및 추가
haroya01 Apr 9, 2024
2e27721
refactor: CheckDuplicatedRequestAspectMock 관련 변경
haroya01 Apr 10, 2024
bb07c70
chore: MagazineRepository 클래스 잘못된 메서드명 변경
Hoon9901 Apr 10, 2024
cb6af65
Merge pull request #158 from Media-XI/ART-176-be-좋아요한-매거진-표시-기능
Hoon9901 Apr 10, 2024
52cef9a
Merge branch 'develop' into ART-175-be-메거진-팀-글쓰기-기능
Hoon9901 Apr 10, 2024
216f9c5
Merge pull request #157 from Media-XI/ART-175-be-메거진-팀-글쓰기-기능
Hoon9901 Apr 10, 2024
33d3c31
feat: 사용자가 속한 팀 리스트 반환 api 추가
haroya01 Apr 12, 2024
0c40e52
test: 테스트 코드 추가
haroya01 Apr 12, 2024
52f9123
Merge pull request #159 from Media-XI/ART-180-be-자신이-속한-팀-리스트-반환
haroya01 Apr 12, 2024
ab83a5e
feat: 팀 프로파일 조회 dto 추가
haroya01 Apr 16, 2024
0f281cf
feat: TeamUserResponse.Get에 teamId 반환값 추가
haroya01 Apr 16, 2024
383fb0d
refactor: @Transactional springfamework에서 지원하는 어노테이션으로 변경
haroya01 Apr 16, 2024
de1f0f5
feat: MemberResponseDTO에 팀 정보도 반환하도록 추가
haroya01 Apr 16, 2024
7b51598
test: 테스트 코드 작성
haroya01 Apr 16, 2024
9384045
fix: TeamUserResponse가 제대로 된 teamId를 반환하도록 변경
haroya01 Apr 16, 2024
52f4229
refactor: member엔티티의 teamUserRoles를 teamUser로 변경
haroya01 Apr 16, 2024
c33020a
refactor: teamUser과 member간의 양방향
haroya01 Apr 16, 2024
af22f2c
refactor: MemberResponseDTO 변경
haroya01 Apr 16, 2024
ec775cc
Merge pull request #160 from Media-XI/ART-181-be-팀-정보-반환-기능
haroya01 Apr 17, 2024
a1cb764
feat: 내 정보 조회 API -> AuthController 로 이관 및 URL 변경
Hoon9901 Apr 18, 2024
db4cdd1
chore: 사용하지 않는 API 주석 처리
Hoon9901 Apr 18, 2024
14ffdb7
refactor: MemberResponseDTO 이메일 속성 제거
Hoon9901 Apr 18, 2024
957fe77
chore: MemberControllerTest API 변경에 따른 테스트 코드 수정
Hoon9901 Apr 18, 2024
e4ec1e2
chore: code formatting
Hoon9901 Apr 18, 2024
d7c96e0
feat: git action test.yaml added codecov token
Hoon9901 Apr 18, 2024
a7f5cee
Merge pull request #162 from Media-XI/feat/내-정보-조회-이관-및-사용자-정보조회-개인정보…
Hoon9901 Apr 19, 2024
83382de
feat: TeamResponse.ProfileGet 변경
haroya01 Apr 20, 2024
96162f0
refactor: 팀 정보에 정렬에 대한 변경
haroya01 Apr 20, 2024
7efdeed
refactor: 변경된 dto에 맞게 수정
haroya01 Apr 20, 2024
fa4003d
refactor: 변경된 요구사항에 맞게 get teams/{username} response 변경
haroya01 Apr 20, 2024
a3a7fd9
test: 테스트 코드 수정
haroya01 Apr 20, 2024
1d02de1
refactor: Member에서 연관관계 teamUser OrderBy 정렬 조건 제거
haroya01 Apr 21, 2024
3571b4a
refactor: 보다 명확한 도메인으로 api 이관
haroya01 Apr 21, 2024
d754235
refactor: dto가 key value의 형태를 취할수 있도록 수정
haroya01 Apr 21, 2024
05abc12
refactor: 불필요한 dto 제거
haroya01 Apr 21, 2024
c9f15a0
refactor: api위치가 변경됨에 따라 로직 변경
haroya01 Apr 21, 2024
82ff5f7
test: 테스트 코드 변경
haroya01 Apr 21, 2024
7cba374
refactor: 일관성을 위한 teamUser정렬조건 추가
haroya01 Apr 21, 2024
b8707e8
refactor: 불 필요한 정렬 조건 제거
haroya01 Apr 21, 2024
37fd829
refactor: collect를 tolist로 변경
haroya01 Apr 21, 2024
6b8a5ba
feat: MemberResponseDTO 내부 dto들의 @schema 작성
haroya01 Apr 21, 2024
16bdb2a
Merge branch 'develop' into ART-184-be-내가-속한-팀-정보-api-응답-데이터-수정
haroya01 Apr 21, 2024
fd48f9c
Merge pull request #163 from Media-XI/ART-184-be-내가-속한-팀-정보-api-응답-데이…
haroya01 Apr 22, 2024
31d4db8
Merge branch 'main' into develop
Hoon9901 Apr 23, 2024
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
14 changes: 14 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## 📝 작업 내용
> 이번 PR에서 작업한 내용을 간단하게 설명해주세요.
>
> 고민한 내용이나, 문제를 어떻게 해결했는지 작성해주는것도 좋습니다.
>
> ![이미지 첨부하면 더 좋아요]()

## 🦾 연관된 이슈
> ex) JIRA링크, #이슈번호

## 💬리뷰 요구사항
> 리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요
>
> ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?
2 changes: 2 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ jobs:

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.1.1
with:
token: ${{ secrets.CODECOV_TOKEN }}

- name: Cleanup Gradle Cache
if: ${{ always() }}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.codebase.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckDuplicatedRequest {
String target() default "";

int aliveMillisecondTime() default 3000;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.example.codebase.aop;

import com.example.codebase.annotation.CheckDuplicatedRequest;
import com.example.codebase.annotation.LoginOnly;
import com.example.codebase.annotation.UserAdminOnly;
import com.example.codebase.annotation.UserOnly;
import com.example.codebase.exception.DuplicatedRequestException;
import com.example.codebase.exception.LoginRequiredException;
import com.example.codebase.util.RedisUtil;
import com.example.codebase.util.SecurityUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component
@Profile("!test")
public class CheckDuplicatedRequestAspect {

private final RedisUtil redisUtil;

@Autowired
protected CheckDuplicatedRequestAspect(RedisUtil redisUtil) {
this.redisUtil = redisUtil;
}

@Before("@annotation(com.example.codebase.annotation.CheckDuplicatedRequest)")
public void checkDuplicateRequest(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
CheckDuplicatedRequest annotation = method.getAnnotation(CheckDuplicatedRequest.class);

if (!isValidAnnotation(method)) return;

String key = SecurityUtil.getCurrentUsername().orElseThrow(LoginRequiredException::new);

if (key.isEmpty()) return;

String target = annotation.target().isEmpty() ? String.valueOf(method) : annotation.target();

String uniqueKey = key + "->" + target;
if (redisUtil.getData(uniqueKey).isPresent()) {
throw new DuplicatedRequestException();
}
redisUtil.setDataAndExpire(uniqueKey, String.valueOf(LocalDateTime.now()), annotation.aliveMillisecondTime());
}

private boolean isValidAnnotation(Method method) {
return method.isAnnotationPresent(LoginOnly.class)
|| method.isAnnotationPresent(UserOnly.class)
|| method.isAnnotationPresent(UserAdminOnly.class);
}
}
55 changes: 38 additions & 17 deletions src/main/java/com/example/codebase/controller/AuthController.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
package com.example.codebase.controller;

import static com.example.codebase.util.SecurityUtil.getCookieAccessTokenValue;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.example.codebase.domain.auth.dto.LoginDTO;
import com.example.codebase.domain.auth.dto.TokenResponseDTO;
import com.example.codebase.domain.auth.service.AuthService;
import com.example.codebase.domain.member.dto.MemberResponseDTO;
import com.example.codebase.domain.member.service.MemberService;
import com.example.codebase.jwt.TokenProvider;
import com.example.codebase.util.SecurityUtil;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;

import static com.example.codebase.util.SecurityUtil.getCookieAccessTokenValue;

@Tag(name = "Auth", description = "인증 API")
@RestController
@RequestMapping("/api")
Expand All @@ -27,9 +36,12 @@ public class AuthController {

private final AuthService authService;

public AuthController(TokenProvider tokenProvider, AuthService authService) {
private final MemberService memberService;

public AuthController(TokenProvider tokenProvider, AuthService authService, MemberService memberService) {
this.tokenProvider = tokenProvider;
this.authService = authService;
this.memberService = memberService;
}

@Operation(summary = "로그인", description = "로그인")
Expand All @@ -39,8 +51,8 @@ public ResponseEntity login(@Valid @RequestBody LoginDTO loginDTO) {

// Set Cookie
return ResponseEntity.ok()
.header("Set-Cookie", getCookieAccessTokenValue(responseDTO))
.body(responseDTO);
.header("Set-Cookie", getCookieAccessTokenValue(responseDTO))
.body(responseDTO);
}

@Operation(summary = "로그아웃", description = "로그아웃")
Expand All @@ -57,20 +69,29 @@ public ResponseEntity logout() {
public ResponseEntity refresh(@RequestBody String refreshToken) {
TokenResponseDTO responseDTO = tokenProvider.regenerateToken(refreshToken);
return ResponseEntity.ok()
.header("Set-Cookie", getCookieAccessTokenValue(responseDTO))
.body(responseDTO);
.header("Set-Cookie", getCookieAccessTokenValue(responseDTO))
.body(responseDTO);
}

@Operation(summary = "이메일 인증", description = "이메일 인증")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "이메일 인증 성공"),
@ApiResponse(responseCode = "400", description = "이메일 인증 실패")
@ApiResponse(responseCode = "200", description = "이메일 인증 성공"),
@ApiResponse(responseCode = "400", description = "이메일 인증 실패")
})
@PreAuthorize("permitAll()")
@GetMapping("/mail/authenticate")
public ResponseEntity authenticateMailLink(
@RequestParam String code) {
@RequestParam String code) {
authService.authenticateMail(code);
return new ResponseEntity("이메일 인증되었습니다.", HttpStatus.OK);
}
}

@Operation(summary = "내 프로필 조회", description = "[USER] 내 프로필을 조회합니다.")
@PreAuthorize("isAuthenticated() and hasAnyRole('ROLE_USER')")
@GetMapping("/auth/me")
public ResponseEntity getProfile() {
String username = SecurityUtil.getCurrentUsernameValue();
MemberResponseDTO member = memberService.getProfile(username);
return new ResponseEntity(member, HttpStatus.OK);
}
}
80 changes: 62 additions & 18 deletions src/main/java/com/example/codebase/controller/FollowController.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package com.example.codebase.controller;

import com.example.codebase.domain.follow.dto.FollowMembersResponseDTO;
import com.example.codebase.domain.follow.dto.FollowRequest;
import com.example.codebase.domain.follow.dto.FollowResponseDTO;
import com.example.codebase.domain.follow.service.FollowService;
import com.example.codebase.domain.notification.entity.NotificationType;
import com.example.codebase.domain.notification.service.NotificationSendService;
import com.example.codebase.exception.LoginRequiredException;
import com.example.codebase.util.SecurityUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.PositiveOrZero;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
Expand Down Expand Up @@ -35,49 +41,87 @@ public FollowController(FollowService followService, NotificationSendService not
this.notificationService = notificationService;
}

@Operation(summary = "팔로우", description = "상대방을 팔로잉 합니다")
@Operation(summary = "팔로우/언팔로우", description = "상대방을 팔로우/언팔로우 합니다.",
parameters = @Parameter(name = "action", description = "follow: 팔로우, unfollow: 언팔로우", required = true, example = "follow"),
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "팔로우할 대상 URN", required = true, content = @io.swagger.v3.oas.annotations.media.Content(
schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = FollowRequest.Create.class),
examples = @io.swagger.v3.oas.annotations.media.ExampleObject(value = "{\"urn\": \"urn:member:admin\"}"))
)
)
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "팔로우 성공"),
@ApiResponse(responseCode = "200", description = "언팔로우 성공")
})
@PreAuthorize("isAuthenticated() and hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
@PostMapping("{username}")
public ResponseEntity followMember(@PathVariable("username") String followUser) {
@PostMapping
public ResponseEntity follow(
@RequestParam("action") @Pattern(regexp = "follow|unfollow", message = "잘못된 action 값입니다.") String action,
@RequestBody @Valid FollowRequest.Create request
) {
String username = SecurityUtil.getCurrentUsername().orElseThrow(LoginRequiredException::new);
followService.followMember(username, followUser);
notificationService.send(username, followUser, NotificationType.NEW_FOLLOWER);
FollowRequest.FollowEntityUrn entityUrn = FollowRequest.FollowEntityUrn.from(request.getUrn());

return new ResponseEntity("팔로잉 했습니다.", HttpStatus.CREATED);
if (action.equals("unfollow")) {
return unfollow(username, entityUrn);
}
return follow(username, entityUrn);
}

@Operation(summary = "언팔로우" , description = "상대방을 언 팔로잉 합니다")
@PreAuthorize("isAuthenticated() and hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
@DeleteMapping("{username}")
public ResponseEntity unfollowMember(@PathVariable("username") String followUser) {
String username = SecurityUtil.getCurrentUsername().orElseThrow(LoginRequiredException::new);
followService.unfollowMember(username, followUser);
private ResponseEntity follow(String username, FollowRequest.FollowEntityUrn entityUrn) {
switch (entityUrn) {
case MEMBER -> {
checkSameMember(username, entityUrn.getId(), "팔로우");
followService.followMember(username, entityUrn.getId());
notificationService.send(username, entityUrn.getId(), NotificationType.NEW_FOLLOWER);
}
case TEAM -> {
followService.followTeam(username, entityUrn.getId());
}
}
return new ResponseEntity("팔로잉 했습니다.", HttpStatus.CREATED);
}

return new ResponseEntity("언팔로잉 했습니다.", HttpStatus.NO_CONTENT);
private ResponseEntity unfollow(String username, FollowRequest.FollowEntityUrn entityUrn) {
switch (entityUrn) {
case MEMBER -> {
checkSameMember(username, entityUrn.getId(), "언팔로우");
followService.unfollowMember(username, entityUrn.getId());
}
case TEAM -> {
followService.unfollowTeam(username, entityUrn.getId());
}
}
return new ResponseEntity("언팔로잉 했습니다.", HttpStatus.OK);
}

private void checkSameMember(String username1, String username2, String message) {
if (username1.equals(username2)) {
throw new RuntimeException("자기 자신을 %s 할 수 없습니다".formatted(message));
}
}

@Operation(summary = "팔로잉", description = "해당 유저가 팔로잉 하는 사람 목록을 조회 합니다")
@Operation(summary = "팔로잉 조회", description = "해당 유저가 팔로잉 하는 사람 목록을 조회 합니다")
@GetMapping("/{username}/following")
public ResponseEntity getFollowingList(@PathVariable("username") String username,
@PositiveOrZero @RequestParam(defaultValue = "0") int page,
@PositiveOrZero @RequestParam(defaultValue = "10") int size) {
Optional<String> loginUsername = SecurityUtil.getCurrentUsername();
PageRequest pageRequest = PageRequest.of(page, size);
FollowMembersResponseDTO followingListResponse = followService.getFollowingList(loginUsername, username, pageRequest);
FollowResponseDTO followingListResponse = followService.getFollowingList(loginUsername, username, pageRequest);

return new ResponseEntity(followingListResponse, HttpStatus.OK);
}


@Operation(summary = "팔로워", description = "해당 유저를 팔로워 하는 사람 목록을 조회 합니다")
@Operation(summary = "팔로워 조회", description = "해당 유저를 팔로워 하는 사람 목록을 조회 합니다")
@GetMapping("{username}/follower")
public ResponseEntity getFollowerList(@PathVariable("username") String username,
@PositiveOrZero @RequestParam(defaultValue = "0") int page,
@PositiveOrZero @RequestParam(defaultValue = "10") int size) {
Optional<String> loginUsername = SecurityUtil.getCurrentUsername();
PageRequest pageRequest = PageRequest.of(page, size);
FollowMembersResponseDTO followingListResponse = followService.getFollowerList(loginUsername, username, pageRequest);
FollowResponseDTO followingListResponse = followService.getFollowerList(loginUsername, username, pageRequest);

return new ResponseEntity(followingListResponse, HttpStatus.OK);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@


import com.example.codebase.annotation.AdminOnly;
import com.example.codebase.domain.magazine.dto.MagazineCategoryRequest;
import com.example.codebase.domain.magazine.dto.MagazineCategoryResponse;
import com.example.codebase.domain.magazine.service.MagazineCategoryService;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

@Tag(name = "매거진 카테고리 API", description = "매거진 카테고리 관련 API")
@RestController
Expand All @@ -25,15 +24,35 @@ public MagazineCategoryController(MagazineCategoryService magazineCategoryServic

@PostMapping
@AdminOnly
public ResponseEntity createCategory(String name) {
MagazineCategoryResponse.Get category = magazineCategoryService.createCategory(name);
public ResponseEntity createCategory(@RequestBody @Valid MagazineCategoryRequest.Create request) {
MagazineCategoryResponse.Create category = magazineCategoryService.createCategory(request);
return new ResponseEntity(category, HttpStatus.CREATED);
}

@GetMapping
public ResponseEntity getCategories() {
public ResponseEntity getAllCategories() {
MagazineCategoryResponse.GetAll allCategory = magazineCategoryService.getAllCategory();
return new ResponseEntity(allCategory, HttpStatus.OK);
}

@GetMapping("/{slug}")
public ResponseEntity getSubCategories(@PathVariable String slug) {
MagazineCategoryResponse.GetAll subCategory = magazineCategoryService.getSubCategories(slug);
return new ResponseEntity(subCategory, HttpStatus.OK);
}

@DeleteMapping("/{categoryId}")
@AdminOnly
public ResponseEntity deleteCategory(@PathVariable Long categoryId) {
magazineCategoryService.deleteCategory(categoryId);
return new ResponseEntity(HttpStatus.NO_CONTENT);
}

@PutMapping("/{categoryId}")
@AdminOnly
public ResponseEntity updateCategory(@PathVariable Long categoryId, @RequestBody @Valid MagazineCategoryRequest.Update request) {
MagazineCategoryResponse.Get category = magazineCategoryService.updateCategory(categoryId, request);
return new ResponseEntity(category, HttpStatus.OK);
}

}
Loading
Loading