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

[Test] Category 데드락 관련 이슈를 찾기 위한 테스트 및 낙관적 락 적용 진행. #254

Open
wants to merge 42 commits into
base: test
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
0db4e02
merge: 충돌해결
sss4920 Sep 14, 2024
42f8fb7
[#240] feature: 팝업 관련 기능 구현
sss4920 Sep 15, 2024
8634a22
[#240] chore: build.gradle 충돌흔적 제거
sss4920 Sep 15, 2024
027e8d3
[#240] refactor: 컨트롤러 수정 후 토큰 테스트 완료
sss4920 Sep 16, 2024
78b036d
[#240] feature: user 회원탈퇴 시 manager도 비우도록 설정
sss4920 Sep 16, 2024
c4e9509
#240 feature: popup 1일닫기, 7일닫기 구현
sss4920 Sep 22, 2024
1086d1f
Merge pull request #241 from Link-MIND/feature/#240
sss4920 Sep 24, 2024
c732542
[#242] feature: 카테고리 이동 구현
sss4920 Oct 4, 2024
5f5bd5b
[#242] feature: 최근 저장한 3개 토스트 및 패키지 구조 리팩토링
sss4920 Oct 6, 2024
e049bd6
[#242] fix: 안올라간 dto 추가
sss4920 Oct 9, 2024
822547f
[#243] feat: 디스코드 회원가입 알림
mmihye Oct 10, 2024
fce6727
[#243] feat: 디스코드 회원가입 + 에러 알림
mmihye Oct 10, 2024
522c69d
[#242] refactor: not null추가 및 리팩토링
sss4920 Oct 12, 2024
18aa6a1
[#242] refactor: toastid 오타수정
sss4920 Oct 12, 2024
08c03b0
Merge pull request #244 from Link-MIND/feature/#242
sss4920 Oct 14, 2024
41edf26
[#245] refactor: 토스트 제목 수정 validation 수정 및 그룹설정
sss4920 Oct 14, 2024
83e5387
[#243] feat: 로컬에서는 에러메시지 전송되지 않도록 수정
mmihye Oct 15, 2024
f947bdf
[#243] fix: 오타수정
mmihye Oct 16, 2024
81f6717
[#243] fix: 회원가입시 디스코드 알림 에러 예외처리
mmihye Oct 16, 2024
c89b4b5
Merge pull request #246 from Link-MIND/refactor/#245
sss4920 Oct 17, 2024
a0f568f
[#243] fix: 오타수정
mmihye Oct 22, 2024
ad8cbd5
[#243] feat: TransactionalEventListener 추가
mmihye Oct 22, 2024
fcc6b29
Merge branch 'develop' into feature/#243
sss4920 Oct 23, 2024
d8bb06f
[#243] feat: TransactionalEventListener 적용 및 DiscordClient 통합
mmihye Oct 24, 2024
6cc7f8b
Merge remote-tracking branch 'origin/feature/#243' into feature/#243
mmihye Oct 24, 2024
898fa9d
[#243] fix: 필요없는 import 삭제
mmihye Oct 24, 2024
23837ad
Merge pull request #247 from Link-MIND/feature/#243
mmihye Oct 24, 2024
2e52fba
[#245] fix: crawler 방지 exception 추가
sss4920 Oct 25, 2024
0cbd396
Merge pull request #249 from Link-MIND/docs/#248
sss4920 Oct 25, 2024
95cf8e9
[#248] docs: readme 및 erd 변경
sss4920 Oct 25, 2024
0d27603
[#250] refactor: link 패키지 구조 변경
sss4920 Oct 25, 2024
0d98f7b
[#250] refactor: 타이머 패키지 구조 변경
sss4920 Oct 25, 2024
86a90bd
[#250] refactor: 추천사이트 패키지 이동 및 timer service이동
sss4920 Oct 25, 2024
29a7d3a
[#250] refactor: parsing service 분리
sss4920 Oct 25, 2024
a2ffb04
[#250] refactor: auth, user 패키지 구조 이동
sss4920 Oct 25, 2024
2ce8144
[#250] refactor: category 패키지 구조 이동
sss4920 Oct 25, 2024
4b1db8f
[#250] refactor: search, mainpage 패키지 구조 이동
sss4920 Oct 25, 2024
9ae3f10
[#250] refactor: 공통 패키지 구조 이동
sss4920 Oct 25, 2024
30910ee
[#250] refactor: link id 오타 수정
sss4920 Oct 25, 2024
1cb6af6
[#250] chore: delete .DS_Store
sss4920 Oct 25, 2024
17c9bd4
Merge pull request #251 from Link-MIND/refactor/#250
sss4920 Oct 30, 2024
e94d5ac
[#252] test: 동시 수정을 진행했을 때 정합성이 깨지지 않도록 낙관적 락 테스트 추가
sss4920 Dec 3, 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
Binary file removed .DS_Store
Binary file not shown.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# TOASTER-SERVER
![Frame 31](https://github.com/Link-MIND/TOASTER-Server/assets/92644651/c88432e0-5cb3-423f-9986-137fa4dfd5e1)
![image](https://github.com/user-attachments/assets/627ffad2-6206-4c96-bfce-7ae7574b3237)


더 이상 **링크**를 태우지 마세요. **토스트 먹듯이 간단하게!**

Expand Down Expand Up @@ -33,7 +34,8 @@


## 📦 ERD
<img width="780" alt="스크린샷 2024-01-19 오후 10 31 57" src="https://github.com/Link-MIND/TOASTER-Server/assets/92644651/c641f995-92b3-41fb-9e29-19b4062cad14">
![image](https://github.com/user-attachments/assets/46eed52a-e4bb-4001-9d6d-20246ca4ad1b)


<br><br>

Expand Down
116 changes: 102 additions & 14 deletions linkmind/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,36 @@ dependencies {
implementation 'mysql:mysql-connector-java:8.0.32'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

runtimeOnly 'com.h2database:h2'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
runtimeOnly 'com.mysql:mysql-connector-j'
implementation 'org.springframework.boot:spring-boot-starter-validation'
testImplementation group: 'com.h2database', name: 'h2', version: '2.2.224'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'

implementation 'io.sentry:sentry-spring-boot-starter:5.7.0'
//JWT
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.2'
implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2'
implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.2'
runtimeOnly 'com.mysql:mysql-connector-j'
implementation 'org.springframework.boot:spring-boot-starter-validation'

implementation 'io.sentry:sentry-spring-boot-starter:5.7.0'
//JWT
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.2'
implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2'
implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.2'


// FCM
implementation 'com.google.firebase:firebase-admin:9.1.1'
implementation 'com.squareup.okhttp3:okhttp:4.10.0' // Firebase 서버로 푸시 메시지 전송 시 필요

implementation 'org.springframework.boot:spring-boot-starter-actuator'

//Query DSL
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta"
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
implementation 'org.springframework.boot:spring-boot-starter-actuator'

//Query DSL
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta"
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"

// S3 AWS
implementation("software.amazon.awssdk:bom:2.21.0")
Expand All @@ -71,9 +79,89 @@ dependencies {

implementation 'io.sentry:sentry-spring-boot-starter:5.7.0'

// openfeign
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

}

dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:2023.0.3")
}
}
//sourceSets {
// main {
// java {
// srcDirs = ["$projectDir/src/main/java", "$projectDir/build/generated"]
// }
// }
//}
//compileJava { options.compilerArgs << '-parameters'}


tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform()
// finalizedBy 'jacocoTestReport' // test가 끝나면 jacocoTestReport 동작
}
//// jacoco report 설정
//jacocoTestReport {
// reports {
// // html로 report 생성하기
// // 빌드경로/jacoco/report.html 폴더 내부로 경로 설정
// html.destination file("$jacoco/report.html")
// }
//
// // jacocoTestReport가 끝나면 jacocoTestCoverageVerification 동작
// finalizedBy 'jacocoTestCoverageVerification'
//}
//
//// jacoco 커버리지 검증 설정
//jacocoTestCoverageVerification {
// violationRules {
// rule {
// enabled = true // 커버리지 적용 여부
// element = 'CLASS' // 커버리지 적용 단위
//
// // 라인 커버리지 설정
// // 적용 대상 전체 소스 코드들을 한줄 한줄 따졌을 때 테스트 코드가 작성되어 있는 줄의 빈도
// // 테스트 코드가 작성되어 있는 비율이 90% 이상이어야 함
// limit {
// counter = 'LINE'
// value = 'COVEREDRATIO'
// minimum = 0.10
// }
//
// // 브랜치 커버리지 설정
// // if-else 등을 활용하여 발생되는 분기들 중 테스트 코드가 작성되어 있는 빈도
// // 테스트 코드가 작성되어 있는 비율이 90% 이상이어야 함
// limit {
// counter = 'BRANCH'
// value = 'COVEREDRATIO'
// minimum = 0.00
// }
//
// // 라인 최대 갯수 설정
// // 빈 줄을 제외하고 하나의 자바 파일에서 작성될 수 있는 최대 라인 갯수
// // 한 파일에 최대 500줄까지 작성되어야 함
// limit {
// counter = 'LINE'
// value = 'TOTALCOUNT'
// maximum = 500
// }
// // 커버리지 체크를 제외할 클래스들
// excludes = [
// // '*.test.*',
// '*.common.*',
// '*.config.*',
// '*.controller.*',
// '*.domain.*',
// '*.exception.*',
// '*.external.*',
// '*.infrastructure.*',
// '*.auth.*',
// '*.service.*'
//
// ]
// }
// }
//}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cglib.core.Local;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

import javax.annotation.PostConstruct;
import java.time.LocalTime;
import java.util.TimeZone;

@SpringBootApplication
@EnableFeignClients
@EnableJpaAuditing
public class ToasterApplication {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.toaster.controller;
package com.app.toaster.auth.controller;

import java.io.IOException;

Expand All @@ -13,13 +13,13 @@

import com.app.toaster.common.dto.ApiResponse;
// import com.app.toaster.config.UserId;
import com.app.toaster.config.UserId;
import com.app.toaster.controller.request.auth.SignInRequestDto;
import com.app.toaster.controller.response.auth.SignInResponseDto;
import com.app.toaster.controller.response.auth.TokenHealthDto;
import com.app.toaster.controller.response.auth.TokenResponseDto;
import com.app.toaster.common.config.UserId;
import com.app.toaster.auth.controller.request.SignInRequestDto;
import com.app.toaster.auth.controller.response.SignInResponseDto;
import com.app.toaster.auth.controller.response.TokenHealthDto;
import com.app.toaster.auth.controller.response.TokenResponseDto;
import com.app.toaster.exception.Success;
import com.app.toaster.service.auth.AuthService;
import com.app.toaster.auth.service.AuthService;

import lombok.RequiredArgsConstructor;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.toaster.controller.request.auth;
package com.app.toaster.auth.controller.request;

public record SignInRequestDto(String socialType, String fcmToken) {
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.toaster.controller.response.auth;
package com.app.toaster.auth.controller.response;

public record SignInResponseDto(Long userId, String accessToken, String refreshToken, String fcmToken, Boolean isRegistered,Boolean fcmIsAllowed, String profile) {
public static SignInResponseDto of(Long userId, String accessToken, String refreshToken, String fcmToken,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.toaster.controller.response.auth;
package com.app.toaster.auth.controller.response;

public record TokenHealthDto(boolean tokenHealth) {
public static TokenHealthDto of(boolean tokenHealth){return new TokenHealthDto(tokenHealth);}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.toaster.controller.response.auth;
package com.app.toaster.auth.controller.response;

public record TokenResponseDto(String accessToken, String refreshToken) {
public static TokenResponseDto of(String accessToken, String refreshToken){
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,41 @@
package com.app.toaster.service.auth;
package com.app.toaster.auth.service;

import java.io.IOException;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import com.app.toaster.common.dto.ApiResponse;
import com.app.toaster.config.jwt.JwtService;
import com.app.toaster.controller.request.auth.SignInRequestDto;
import com.app.toaster.controller.response.auth.SignInResponseDto;
import com.app.toaster.controller.response.auth.TokenHealthDto;
import com.app.toaster.controller.response.auth.TokenResponseDto;
import com.app.toaster.domain.SocialType;
import com.app.toaster.domain.User;


import com.app.toaster.common.config.jwt.JwtService;
import com.app.toaster.auth.controller.request.SignInRequestDto;
import com.app.toaster.auth.controller.response.SignInResponseDto;
import com.app.toaster.auth.controller.response.TokenHealthDto;
import com.app.toaster.auth.controller.response.TokenResponseDto;
import com.app.toaster.user.domain.SocialType;
import com.app.toaster.user.domain.User;
import com.app.toaster.exception.Error;
import com.app.toaster.exception.Success;
import com.app.toaster.exception.model.BadRequestException;
import com.app.toaster.exception.model.CustomException;
import com.app.toaster.exception.model.NotFoundException;
import com.app.toaster.exception.model.UnprocessableEntityException;
import com.app.toaster.external.client.discord.DiscordMessageProvider;
import com.app.toaster.external.client.discord.NotificationDto;
import com.app.toaster.external.client.discord.NotificationType;
import com.app.toaster.external.client.slack.SlackApi;
import com.app.toaster.infrastructure.CategoryRepository;
import com.app.toaster.infrastructure.TimerRepository;
import com.app.toaster.infrastructure.ToastRepository;
import com.app.toaster.infrastructure.UserRepository;
import com.app.toaster.service.auth.apple.AppleSignInService;
import com.app.toaster.service.auth.kakao.KakaoSignInService;
import com.app.toaster.service.auth.kakao.LoginResult;
import com.app.toaster.service.toast.ToastService;
import com.app.toaster.category.infrastructure.CategoryRepository;
import com.app.toaster.timer.infrastructure.TimerRepository;
import com.app.toaster.toast.infrastructure.ToastRepository;
import com.app.toaster.user.infrastructure.UserRepository;
import com.app.toaster.popup.infrastructure.PopupManagerRepository;
import com.app.toaster.auth.service.apple.AppleSignInService;
import com.app.toaster.auth.service.kakao.KakaoSignInService;
import com.app.toaster.auth.service.kakao.LoginResult;
import com.app.toaster.toast.service.ToastService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class AuthService {
Expand All @@ -43,8 +46,10 @@ public class AuthService {

private final UserRepository userRepository;
private final CategoryRepository categoryRepository;
private final PopupManagerRepository popupManagerRepository;

private final SlackApi slackApi;
private final DiscordMessageProvider discordMessageProvider;


private final Long TOKEN_EXPIRATION_TIME_ACCESS = 7*24*60 * 60 * 1000L; //7일
Expand Down Expand Up @@ -73,7 +78,8 @@ public SignInResponseDto signIn(String socialAccessToken, SignInRequestDto reque
.socialType(socialType).build();
newUser.updateFcmIsAllowed(true); //신규 유저면 true박고
userRepository.save(newUser);
slackApi.sendSuccess(Success.LOGIN_SUCCESS);

discordMessageProvider.sendNotification(new NotificationDto(NotificationType.SIGNUP,null,null));
}

User user = userRepository.findBySocialIdAndSocialType(socialId, socialType)
Expand Down Expand Up @@ -149,6 +155,7 @@ public void withdraw(Long userId) {
}
timerRepository.deleteAllByUser(user);
categoryRepository.deleteAllByUser(user);
popupManagerRepository.deleteAllByUserId(userId);

Long res = userRepository.deleteByUserId(userId); //res가 삭제된 컬럼의 개수 즉, 1이 아니면 뭔가 알 수 없는 에러.

Expand All @@ -163,4 +170,5 @@ public TokenHealthDto checkHealthOfToken(String refreshToken){
return TokenHealthDto.of(jwtService.verifyToken(refreshToken));
}


}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.toaster.service.auth.apple;
package com.app.toaster.auth.service.apple;

import java.security.PublicKey;
import java.util.Map;
Expand All @@ -7,11 +7,10 @@
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;

import com.app.toaster.service.auth.apple.response.ApplePublicKeys;
import com.app.toaster.service.auth.apple.verify.AppleJwtParser;
import com.app.toaster.service.auth.apple.verify.PublicKeyGenerator;
import com.app.toaster.service.auth.kakao.LoginResult;
import com.mysql.cj.log.Log;
import com.app.toaster.auth.service.apple.response.ApplePublicKeys;
import com.app.toaster.auth.service.apple.verify.AppleJwtParser;
import com.app.toaster.auth.service.apple.verify.PublicKeyGenerator;
import com.app.toaster.auth.service.kakao.LoginResult;

import io.jsonwebtoken.Claims;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.toaster.service.auth.apple.response;
package com.app.toaster.auth.service.apple.response;

public record ApplePublicKey(
String kty,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package com.app.toaster.service.auth.apple.response;
package com.app.toaster.auth.service.apple.response;

import java.util.List;

import com.app.toaster.exception.Error;
import com.app.toaster.exception.model.CustomException;

import lombok.extern.slf4j.Slf4j;

public record ApplePublicKeys(List<ApplePublicKey> keys) {

public ApplePublicKey getMatchesKey(String alg, String kid) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.toaster.service.auth.apple.verify;
package com.app.toaster.auth.service.apple.verify;

import java.security.PublicKey;
import java.util.Base64;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.toaster.service.auth.apple.verify;
package com.app.toaster.auth.service.apple.verify;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.toaster.service.auth.apple.verify;
package com.app.toaster.auth.service.apple.verify;

import java.math.BigInteger;
import java.security.KeyFactory;
Expand All @@ -13,10 +13,8 @@

import com.app.toaster.exception.Error;
import com.app.toaster.exception.model.CustomException;
import com.app.toaster.service.auth.apple.response.ApplePublicKey;
import com.app.toaster.service.auth.apple.response.ApplePublicKeys;

import lombok.extern.slf4j.Slf4j;
import com.app.toaster.auth.service.apple.response.ApplePublicKey;
import com.app.toaster.auth.service.apple.response.ApplePublicKeys;

@Component
public class PublicKeyGenerator {
Expand Down
Loading