Skip to content

Commit b53aad5

Browse files
authored
Merge branch 'develop' into CLAP-118
2 parents dda6110 + 0716af2 commit b53aad5

File tree

364 files changed

+8378
-1504
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

364 files changed

+8378
-1504
lines changed

.github/workflows/dev-cd.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,7 @@ jobs:
6262
script: |
6363
docker rm -f taskflow
6464
docker image rm ${{ secrets.DOCKER_REPO }} -f
65-
docker run --name taskflow -d -p 9090:9090 ${{ secrets.DOCKER_REPO }} --restart on-failure
65+
docker run --name taskflow -d -p 9090:9090 \
66+
--env-file /home/ubuntu/.env \
67+
${{ secrets.DOCKER_REPO }} \
68+
--restart on-failure

.github/workflows/dev-ci.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ permissions:
1313

1414
jobs:
1515
DEV_CI:
16-
if: github.event.action == 'opened' || github.event.action == 'synchronize'
1716
runs-on: ubuntu-latest
1817
steps:
1918
- uses: actions/checkout@v3
@@ -22,7 +21,9 @@ jobs:
2221
with:
2322
java-version: '17'
2423
distribution: 'temurin' # https://github.com/actions/setup-java
25-
24+
- run: touch ./src/test/resources/application.yml
25+
- run: echo "${{ secrets.S3_PROPERTIES }}" > ./src/test/resources/application.yml
26+
2627
# gradle caching - 빌드 시간 향상
2728
- name: Gradle Caching
2829
uses: actions/cache@v4

build.gradle

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ repositories {
2424
}
2525

2626
dependencies {
27+
implementation 'org.springframework.boot:spring-boot-starter'
2728
implementation 'org.springframework.boot:spring-boot-starter-web'
29+
implementation 'org.springframework.boot:spring-boot-starter'
2830

2931
//ElasticSearch
3032
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
@@ -90,9 +92,21 @@ dependencies {
9092
// Email Sender
9193
implementation 'org.springframework.boot:spring-boot-starter-mail'
9294

95+
// Thymeleaf
96+
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
97+
9398
// Spring aop
9499
implementation 'org.springframework.boot:spring-boot-starter-aop'
95100

101+
// S3
102+
implementation platform('software.amazon.awssdk:bom:2.23.7')
103+
implementation 'software.amazon.awssdk:s3'
104+
implementation 'ch.qos.logback:logback-classic:1.4.12'
105+
106+
// Apache Tika
107+
implementation 'org.apache.tika:tika-core:2.9.0'
108+
implementation 'org.apache.tika:tika-parsers:2.9.0'
109+
96110
}
97111

98112
tasks.named('test') {

src/main/java/clap/server/adapter/inbound/security/LoginAttemptFilter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import clap.server.application.service.auth.LoginAttemptService;
44
import clap.server.exception.AuthException;
5-
import clap.server.exception.code.CommonErrorCode;
5+
import clap.server.exception.code.GlobalErrorCode;
66
import jakarta.servlet.FilterChain;
77
import jakarta.servlet.ServletException;
88
import jakarta.servlet.http.HttpServletRequest;
@@ -35,7 +35,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
3535

3636
if (request.getRequestURI().equals(LOGIN_ENDPOINT)) {
3737
if (sessionId == null) {
38-
throw new AuthException(CommonErrorCode.BAD_REQUEST);
38+
throw new AuthException(GlobalErrorCode.BAD_REQUEST);
3939
}
4040
loginAttemptService.checkAccountIsLocked(sessionId);
4141
}

src/main/java/clap/server/adapter/inbound/security/filter/JwtAuthenticationFilter.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import clap.server.adapter.outbound.jwt.JwtClaims;
44
import clap.server.adapter.outbound.jwt.access.AccessTokenClaimKeys;
5+
import clap.server.application.port.outbound.auth.ForbiddenTokenPort;
56
import clap.server.application.port.outbound.auth.JwtProvider;
67
import clap.server.exception.JwtException;
78
import clap.server.exception.code.AuthErrorCode;
@@ -27,7 +28,6 @@
2728

2829
import java.io.IOException;
2930

30-
// 요청에서 JWT 토큰을 추출하고 유효성을 검사합니다.
3131
@Slf4j
3232
@Component
3333
@RequiredArgsConstructor
@@ -37,6 +37,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
3737
private final JwtProvider accessTokenProvider;
3838
private final JwtProvider temporaryTokenProvider;
3939
private final AccessDeniedHandler accessDeniedHandler;
40+
private final ForbiddenTokenPort forbiddenTokenPort;
4041

4142
@Override
4243
protected void doFilterInternal(
@@ -70,15 +71,15 @@ private String resolveAccessToken(
7071
HttpServletRequest request
7172
) throws ServletException {
7273
String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
73-
String token = accessTokenProvider.resolveToken(authHeader);
74+
String accessToken = accessTokenProvider.resolveToken(authHeader);
7475

75-
if (!StringUtils.hasText(token)) {
76+
if (!StringUtils.hasText(accessToken)) {
7677
log.error("EMPTY_ACCESS_TOKEN");
7778
handleAuthException(AuthErrorCode.EMPTY_ACCESS_KEY);
7879
}
7980

8081
String requestUrl = request.getRequestURI();
81-
boolean isTemporaryToken = isTemporaryToken(token);
82+
boolean isTemporaryToken = isTemporaryToken(accessToken);
8283
JwtProvider tokenProvider = isTemporaryToken ? temporaryTokenProvider : accessTokenProvider;
8384

8485
log.info("Token is Temporary {}", isTemporaryToken);
@@ -88,14 +89,17 @@ private String resolveAccessToken(
8889
handleAuthException(AuthErrorCode.FORBIDDEN_ACCESS_TOKEN);
8990
}
9091

91-
// TODO: 블랙리스트 토큰 처리 로직 추가 필요
92+
if (forbiddenTokenPort.getIsForbidden(accessToken)) {
93+
log.error("FORBIDDEN_ACCESS_TOKEN");
94+
handleAuthException(AuthErrorCode.FORBIDDEN_ACCESS_TOKEN);
95+
}
9296

93-
if (tokenProvider.isTokenExpired(token)) {
97+
if (tokenProvider.isTokenExpired(accessToken)) {
9498
log.error("EXPIRED_TOKEN");
9599
handleAuthException(AuthErrorCode.EXPIRED_TOKEN);
96100
}
97101

98-
return token;
102+
return accessToken;
99103
}
100104

101105

src/main/java/clap/server/adapter/inbound/security/filter/JwtErrorCodeUtil.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import clap.server.exception.JwtException;
33
import clap.server.exception.code.AuthErrorCode;
44
import clap.server.exception.code.BaseErrorCode;
5-
import clap.server.exception.code.CommonErrorCode;
5+
import clap.server.exception.code.GlobalErrorCode;
66
import io.jsonwebtoken.ExpiredJwtException;
77
import io.jsonwebtoken.MalformedJwtException;
88
import io.jsonwebtoken.UnsupportedJwtException;
@@ -36,7 +36,7 @@ public static BaseErrorCode determineErrorCode(Exception exception, BaseErrorCod
3636
public static JwtException determineAuthErrorException(Exception exception) {
3737
return findAuthErrorException(exception).orElseGet(
3838
() -> {
39-
BaseErrorCode errorCode = determineErrorCode(exception, CommonErrorCode.INTERNAL_SERVER_ERROR);
39+
BaseErrorCode errorCode = determineErrorCode(exception, GlobalErrorCode.INTERNAL_SERVER_ERROR);
4040
log.debug(exception.getMessage(), exception);
4141
return new JwtException(errorCode);
4242
}
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package clap.server.adapter.inbound.web.admin;
22

33
import clap.server.adapter.inbound.security.SecurityUserDetails;
4-
import clap.server.adapter.inbound.web.dto.AddSubCategoryRequest;
54
import clap.server.adapter.inbound.web.dto.admin.AddMainCategoryRequest;
6-
import clap.server.application.port.inbound.management.AddMainCategoryUsecase;
7-
import clap.server.application.port.inbound.management.AddSubCategoryUsecase;
5+
import clap.server.adapter.inbound.web.dto.admin.AddSubCategoryRequest;
6+
import clap.server.application.port.inbound.admin.AddCategoryUsecase;
87
import clap.server.common.annotation.architecture.WebAdapter;
98
import io.swagger.v3.oas.annotations.Operation;
109
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -14,26 +13,27 @@
1413
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1514
import org.springframework.web.bind.annotation.PostMapping;
1615
import org.springframework.web.bind.annotation.RequestBody;
16+
import org.springframework.web.bind.annotation.RequestMapping;
1717

18-
@Tag(name = "카테고리 추가")
18+
@Tag(name = "05. Admin")
1919
@WebAdapter
2020
@RequiredArgsConstructor
21+
@RequestMapping("/api/managements")
2122
public class AddCategoryController {
22-
private final AddMainCategoryUsecase addMainCategoryUsecase;
23-
private final AddSubCategoryUsecase addSubCategoryUsecase;
23+
private final AddCategoryUsecase addCategoryUsecase;
2424

2525
@Operation(summary = "1차 카테고리 추가")
26-
@PostMapping("/api/maincategory")
26+
@PostMapping("/main-category")
2727
@Secured("ROLE_ADMIN")
2828
public void addMainCategory(@AuthenticationPrincipal SecurityUserDetails userInfo, @Valid @RequestBody AddMainCategoryRequest addMainCategoryRequest) {
29-
addMainCategoryUsecase.addMainCategory(userInfo.getUserId(), addMainCategoryRequest.code(), addMainCategoryRequest.name());
29+
addCategoryUsecase.addMainCategory(userInfo.getUserId(), addMainCategoryRequest.code(), addMainCategoryRequest.name());
3030
}
3131

3232
@Operation(summary = "2차 카테고리 추가")
33-
@PostMapping("/api/subcategory")
33+
@PostMapping("/sub-category")
3434
@Secured("ROLE_ADMIN")
3535
public void addSubCategory(@AuthenticationPrincipal SecurityUserDetails userInfo, @Valid @RequestBody AddSubCategoryRequest addCategoryRequest) {
36-
addSubCategoryUsecase.addSubCategory(userInfo.getUserId(), addCategoryRequest.mainCategoryId(), addCategoryRequest.code(), addCategoryRequest.name());
36+
addCategoryUsecase.addSubCategory(userInfo.getUserId(), addCategoryRequest.mainCategoryId(), addCategoryRequest.code(), addCategoryRequest.name());
3737
}
3838

3939
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package clap.server.adapter.inbound.web.admin;
2+
3+
import clap.server.adapter.inbound.security.SecurityUserDetails;
4+
import clap.server.application.port.inbound.admin.DeleteCategoryUsecase;
5+
import clap.server.common.annotation.architecture.WebAdapter;
6+
import io.swagger.v3.oas.annotations.Operation;
7+
import io.swagger.v3.oas.annotations.tags.Tag;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.security.access.annotation.Secured;
10+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
11+
import org.springframework.web.bind.annotation.DeleteMapping;
12+
import org.springframework.web.bind.annotation.PathVariable;
13+
import org.springframework.web.bind.annotation.RequestMapping;
14+
15+
@Tag(name = "05. Admin")
16+
@WebAdapter
17+
@RequiredArgsConstructor
18+
@RequestMapping("/api/managements")
19+
public class DeleteCategoryController {
20+
private final DeleteCategoryUsecase deleteCategoryUsecase;
21+
22+
@Operation(summary = "카테고리 삭제")
23+
@DeleteMapping("/categories/{categoryId}")
24+
@Secured("ROLE_ADMIN")
25+
public void deleteCategory(@AuthenticationPrincipal SecurityUserDetails userInfo, @PathVariable Long categoryId) {
26+
deleteCategoryUsecase.deleteCategory(userInfo.getUserId(), categoryId);
27+
}
28+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package clap.server.adapter.inbound.web.admin;
2+
3+
import clap.server.application.port.inbound.admin.DeleteMemberUsecase;
4+
import clap.server.common.annotation.architecture.WebAdapter;
5+
import io.swagger.v3.oas.annotations.Operation;
6+
import io.swagger.v3.oas.annotations.tags.Tag;
7+
import lombok.RequiredArgsConstructor;
8+
import org.springframework.security.access.annotation.Secured;
9+
import org.springframework.web.bind.annotation.PatchMapping;
10+
import org.springframework.web.bind.annotation.PathVariable;
11+
import org.springframework.web.bind.annotation.RequestMapping;
12+
13+
@Tag(name = "05. Admin")
14+
@WebAdapter
15+
@RequiredArgsConstructor
16+
@RequestMapping("/api/managements")
17+
public class DeleteMemberController {
18+
private final DeleteMemberUsecase deleteMemberUsecase;
19+
20+
@Operation(summary = "회원 삭제 API")
21+
@Secured("ROLE_ADMIN")
22+
@PatchMapping("/members/{memberId}")
23+
public void deleteMember(@PathVariable Long memberId) {
24+
deleteMemberUsecase.deleteMember(memberId);
25+
}
26+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package clap.server.adapter.inbound.web.admin;
2+
3+
import clap.server.adapter.inbound.web.dto.admin.FindAllCategoryResponse;
4+
import clap.server.adapter.inbound.web.dto.admin.FindMainCategoryResponse;
5+
import clap.server.adapter.inbound.web.dto.admin.FindSubCategoryResponse;
6+
import clap.server.application.port.inbound.admin.FindAllCategoryUsecase;
7+
import clap.server.application.port.inbound.admin.FindMainCategoryUsecase;
8+
import clap.server.application.port.inbound.admin.FindSubCategoryUsecase;
9+
import clap.server.common.annotation.architecture.WebAdapter;
10+
import io.swagger.v3.oas.annotations.Operation;
11+
import io.swagger.v3.oas.annotations.tags.Tag;
12+
import lombok.RequiredArgsConstructor;
13+
import org.springframework.http.ResponseEntity;
14+
import org.springframework.web.bind.annotation.GetMapping;
15+
import org.springframework.web.bind.annotation.RequestMapping;
16+
17+
import java.util.List;
18+
19+
@Tag(name = "카테고리 조회")
20+
@WebAdapter
21+
@RequiredArgsConstructor
22+
@RequestMapping("/api")
23+
public class FindCategoryController {
24+
private final FindAllCategoryUsecase findAllCategoryUsecase;
25+
private final FindMainCategoryUsecase findmainCategoryUsecase;
26+
private final FindSubCategoryUsecase findsubCategoryUsecase;
27+
28+
@Operation(summary = "모든 카테고리 조회")
29+
@GetMapping("/category")
30+
public ResponseEntity<List<FindAllCategoryResponse>> findAllCategory() {
31+
return ResponseEntity.ok(findAllCategoryUsecase.findAllCategory());
32+
}
33+
34+
@Operation(summary = "1차 카테고리 조회")
35+
@GetMapping("/main-category")
36+
public ResponseEntity<List<FindMainCategoryResponse>> findMainCategory() {
37+
return ResponseEntity.ok(findmainCategoryUsecase.findMainCategory());
38+
}
39+
40+
@Operation(summary = "2차 카테고리 조회")
41+
@GetMapping("/sub-category")
42+
public ResponseEntity<List<FindSubCategoryResponse>> findSubCategory() {
43+
return ResponseEntity.ok(findsubCategoryUsecase.findSubCategory());
44+
}
45+
}

0 commit comments

Comments
 (0)