-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- 섹션별, 질문별 모아보기 기능이 추가되었습니다. - 모아보기 페이지에서 형광펜을 사용할 수 있습니다.
- Loading branch information
Showing
286 changed files
with
8,483 additions
and
948 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
name: "[test] Zero Downtime Deploy Test CD" | ||
|
||
on: | ||
workflow_dispatch: | ||
|
||
env: | ||
APPLICATION_DIRECTORY: /home/ubuntu/review-me | ||
|
||
jobs: | ||
build: | ||
name: Build Dockerfile and push to DockerHub | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout to current repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Setup JDK Corretto using cached gradle dependencies | ||
uses: actions/setup-java@v4 | ||
with: | ||
distribution: 'corretto' | ||
java-version: 17 | ||
cache: 'gradle' | ||
|
||
- name: Setup Gradle | ||
uses: gradle/actions/setup-gradle@v3 | ||
with: | ||
gradle-version: 8.8 | ||
|
||
- name: Build and test with gradle | ||
run: | | ||
cd ./backend | ||
./gradlew clean bootJar | ||
- name: Login to DockerHub | ||
uses: docker/login-action@v3 | ||
with: | ||
username: ${{ secrets.DOCKERHUB_ID }} | ||
password: ${{ secrets.DOCKERHUB_TOKEN }} | ||
|
||
- name: Set up Docker Buildx | ||
uses: docker/setup-buildx-action@v3 | ||
|
||
- name: Build and push | ||
uses: docker/build-push-action@v6 | ||
with: | ||
context: ./backend | ||
platforms: linux/amd64,linux/arm64 | ||
push: true | ||
tags: ${{ secrets.DOCKERHUB_ID }}/review-me-app:develop | ||
|
||
deploy: | ||
name: Deploy via self-hosted runner | ||
needs: build | ||
runs-on: [self-hosted, dev] | ||
|
||
steps: | ||
- name: Checkout to secret repository | ||
uses: actions/checkout@v4 | ||
with: | ||
repository: ${{ secrets.PRIVATE_REPOSITORY_URL }} | ||
token: ${{ secrets.PRIVATE_REPOSITORY_TOKEN }} | ||
|
||
- name: Move application-related files to local | ||
run: | | ||
mkdir -p ${{ env.APPLICATION_DIRECTORY }}/app | ||
mv ./app/* ./app/.* ${{ env.APPLICATION_DIRECTORY }}/app | ||
- name: Login to DockerHub | ||
uses: docker/login-action@v3 | ||
with: | ||
username: ${{ secrets.DOCKERHUB_ID }} | ||
password: ${{ secrets.DOCKERHUB_TOKEN }} | ||
|
||
- name: Deploy new version # 변경 부분 | ||
env: | ||
PROFILE_VAR: "dev" | ||
run: | | ||
chmod +x ./deploy.sh | ||
sudo -E ./deploy.sh | ||
working-directory: ${{ env.APPLICATION_DIRECTORY }}/app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
==== 리뷰 하이라이트 변경 (추가, 삭제, 수정 포함) | ||
|
||
operation::highlight-answer[snippets="curl-request,request-cookies,http-response,request-fields"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
==== 섹션 이름 목록 가져오기 | ||
|
||
operation::get-session-names[snippets="curl-request,request-cookies,http-response,response-fields"] | ||
|
||
==== 받은 리뷰 섹션별 모아보기 | ||
|
||
operation::received-review-by-section[snippets="curl-request,request-cookies,query-parameters,http-response,response-fields"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
==== 자신이 받은 리뷰 요약 조회 | ||
|
||
operation::received-review-summary[snippets="curl-request,request-cookies,http-response,response-fields"] |
13 changes: 13 additions & 0 deletions
13
backend/src/main/java/reviewme/config/RequestLimitProperties.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package reviewme.config; | ||
|
||
import java.time.Duration; | ||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
|
||
@ConfigurationProperties(prefix = "request-limit") | ||
public record RequestLimitProperties( | ||
long threshold, | ||
Duration duration, | ||
String host, | ||
int port | ||
) { | ||
} |
34 changes: 34 additions & 0 deletions
34
backend/src/main/java/reviewme/config/RequestLimitRedisConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package reviewme.config; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.data.redis.connection.RedisConnectionFactory; | ||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; | ||
import org.springframework.data.redis.core.RedisTemplate; | ||
import org.springframework.data.redis.serializer.GenericToStringSerializer; | ||
|
||
@Configuration | ||
@EnableConfigurationProperties(RequestLimitProperties.class) | ||
@RequiredArgsConstructor | ||
public class RequestLimitRedisConfig { | ||
|
||
private final RequestLimitProperties requestLimitProperties; | ||
|
||
@Bean | ||
public RedisConnectionFactory redisConnectionFactory() { | ||
return new LettuceConnectionFactory( | ||
requestLimitProperties.host(), requestLimitProperties.port() | ||
); | ||
} | ||
|
||
@Bean | ||
public RedisTemplate<String, Long> requestLimitRedisTemplate() { | ||
RedisTemplate<String, Long> redisTemplate = new RedisTemplate<>(); | ||
redisTemplate.setConnectionFactory(redisConnectionFactory()); | ||
redisTemplate.setValueSerializer(new GenericToStringSerializer<>(Long.class)); | ||
|
||
return redisTemplate; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,31 @@ | ||
package reviewme.config; | ||
|
||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.data.redis.core.RedisTemplate; | ||
import org.springframework.web.method.support.HandlerMethodArgumentResolver; | ||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; | ||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
import reviewme.global.HeaderPropertyArgumentResolver; | ||
import reviewme.global.RequestLimitInterceptor; | ||
import reviewme.reviewgroup.controller.ReviewGroupSessionResolver; | ||
import reviewme.reviewgroup.service.ReviewGroupService; | ||
|
||
@Configuration | ||
@RequiredArgsConstructor | ||
public class WebConfig implements WebMvcConfigurer { | ||
|
||
private final ReviewGroupService reviewGroupService; | ||
private final RedisTemplate<String, Long> redisTemplate; | ||
private final RequestLimitProperties requestLimitProperties; | ||
|
||
@Override | ||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { | ||
resolvers.add(new HeaderPropertyArgumentResolver()); | ||
resolvers.add(new ReviewGroupSessionResolver(reviewGroupService)); | ||
} | ||
|
||
@Override | ||
public void addInterceptors(InterceptorRegistry registry) { | ||
registry.addInterceptor(new RequestLimitInterceptor(redisTemplate, requestLimitProperties)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
32 changes: 0 additions & 32 deletions
32
backend/src/main/java/reviewme/global/HeaderPropertyArgumentResolver.java
This file was deleted.
Oops, something went wrong.
50 changes: 50 additions & 0 deletions
50
backend/src/main/java/reviewme/global/RequestLimitInterceptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package reviewme.global; | ||
|
||
import static org.springframework.http.HttpHeaders.USER_AGENT; | ||
|
||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
import org.springframework.data.redis.core.RedisTemplate; | ||
import org.springframework.data.redis.core.ValueOperations; | ||
import org.springframework.http.HttpMethod; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.servlet.HandlerInterceptor; | ||
import reviewme.config.RequestLimitProperties; | ||
import reviewme.global.exception.TooManyRequestException; | ||
|
||
@Component | ||
@EnableConfigurationProperties(RequestLimitProperties.class) | ||
@RequiredArgsConstructor | ||
public class RequestLimitInterceptor implements HandlerInterceptor { | ||
|
||
private final RedisTemplate<String, Long> redisTemplate; | ||
private final RequestLimitProperties requestLimitProperties; | ||
|
||
@Override | ||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { | ||
if (!HttpMethod.POST.matches(request.getMethod())) { | ||
return true; | ||
} | ||
|
||
String key = generateRequestKey(request); | ||
ValueOperations<String, Long> valueOperations = redisTemplate.opsForValue(); | ||
valueOperations.setIfAbsent(key, 0L, requestLimitProperties.duration()); | ||
redisTemplate.expire(key, requestLimitProperties.duration()); | ||
|
||
long requestCount = valueOperations.increment(key); | ||
if (requestCount > requestLimitProperties.threshold()) { | ||
throw new TooManyRequestException(key); | ||
} | ||
return true; | ||
} | ||
|
||
private String generateRequestKey(HttpServletRequest request) { | ||
String requestURI = request.getRequestURI(); | ||
String remoteAddr = request.getRemoteAddr(); | ||
String userAgent = request.getHeader(USER_AGENT); | ||
|
||
return String.format("RequestURI: %s, RemoteAddr: %s, UserAgent: %s", requestURI, remoteAddr, userAgent); | ||
} | ||
} |
12 changes: 0 additions & 12 deletions
12
backend/src/main/java/reviewme/global/exception/MissingHeaderPropertyException.java
This file was deleted.
Oops, something went wrong.
12 changes: 12 additions & 0 deletions
12
backend/src/main/java/reviewme/global/exception/TooManyRequestException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package reviewme.global.exception; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
|
||
@Slf4j | ||
public class TooManyRequestException extends ReviewMeException { | ||
|
||
public TooManyRequestException(String requestKey) { | ||
super("짧은 시간 안에 너무 많은 동일한 요청이 일어났어요. 잠시 후 다시 시도해주세요."); | ||
log.warn("Too many request received - request: {}", requestKey); | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
backend/src/main/java/reviewme/highlight/controller/HighlightController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package reviewme.highlight.controller; | ||
|
||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import reviewme.highlight.service.HighlightService; | ||
import reviewme.highlight.service.dto.HighlightsRequest; | ||
import reviewme.reviewgroup.controller.ReviewGroupSession; | ||
import reviewme.reviewgroup.domain.ReviewGroup; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
public class HighlightController { | ||
|
||
private final HighlightService highlightService; | ||
|
||
@PostMapping("/v2/highlight") | ||
public ResponseEntity<Void> highlight( | ||
@Valid @RequestBody HighlightsRequest request, | ||
@ReviewGroupSession ReviewGroup reviewGroup | ||
) { | ||
highlightService.editHighlight(request, reviewGroup); | ||
return ResponseEntity.ok().build(); | ||
} | ||
} |
Oops, something went wrong.