Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
53c8f1c
feat: 사용자 github repo 보유 여부 확인 로직 수정(#31)
Minjae-An May 15, 2025
b6117f5
feat: 예외명 형식에 맞게 수정(#31)
Minjae-An May 15, 2025
03e2ba3
feat: id 기반으로 객체 비교하도록 수정(#31)
Minjae-An May 15, 2025
add85d9
feat: 메서드명 및 로직 수정(#31)
Minjae-An May 15, 2025
f64ce2e
feat: 메서드명 변경에 따른 수정(#31)
Minjae-An May 15, 2025
9876ff9
feat: 메서드명 변경에 따른 수정(#31)
Minjae-An May 15, 2025
9aa8cc0
feat: 예외명 변경에 따른 수정(#31)
Minjae-An May 15, 2025
ef3f0b3
chore: ID 기반 github repo 조회 테스트 setup SQL 추가(#31)
Minjae-An May 15, 2025
a3c46b6
test: ID 기반 github repo 조회 테스트 추가(#31)
Minjae-An May 15, 2025
bd6335b
chore: jacoco 의존성 추가(#31)
Minjae-An May 15, 2025
4e34b1e
chore: 테스트 커버리지 측정 과정 추가(#31)
Minjae-An May 15, 2025
562f7e6
chore: 테스트 커버리지 생성에 불필요한 html 경로 삭제(#31)
Minjae-An May 15, 2025
42325b0
chore: PR에 테스트 커버리지 내용 추가를 위한 권한 설정(#31)
Minjae-An May 15, 2025
37760d8
chore: querydsl Qclass git 관리에서 제외(#31)
Minjae-An May 15, 2025
006158d
chore: 테스트 fixture setup용 SQL 추가(#31)
Minjae-An May 15, 2025
4d1f30b
feat: 파라미터타입 기본 타입으로 변경(#31)
Minjae-An May 15, 2025
873c231
feat: 불필요한 코드 중복 제거(#31)
Minjae-An May 15, 2025
94049ab
test: 사용자 ID, Repository ID 기반 조회 테스트 추가(#31)
Minjae-An May 15, 2025
596c4f3
feat: 메서드명 명확하게 변경(#31)
Minjae-An May 15, 2025
2b8ec40
feat: 메서드명 변경에 따른 수정(#31)
Minjae-An May 15, 2025
4c00115
test: 투표 사용자 토큰 연관 로직 테스트 추가(#31)
Minjae-An May 15, 2025
a8942e3
Merge branch 'dev' into test/31
Minjae-An May 16, 2025
d32e260
feat: 부적절한 예외 ENUM명 수정(#31)
Minjae-An May 16, 2025
13e2d63
feat: 메서드명 및 로직 수정(#31)
Minjae-An May 16, 2025
d3ba0a7
feat: 예외 ENUM명 변경에 따른 수정(#31)
Minjae-An May 16, 2025
7dc3757
test: 데이터 세팅/클렌징을 메서드 단위로 실행토록 수정(#31)
Minjae-An May 16, 2025
b295876
test: 투표 오픈 단위 테스트 추가(#31)
Minjae-An May 21, 2025
e2031d8
test: 투표 대상 이메일 조회 단위 테스트 추가(#31)
Minjae-An May 22, 2025
85b615f
test: 투표 폼 구성 데이터 제공 기능 단위 테스트 추가(#31)
Minjae-An May 22, 2025
3dd9bf9
feat: 사용하지 않는 DTO 삭제(#31)
Minjae-An May 22, 2025
966fa8d
test: 투표 요청 저장 기능 단위 테스트 추가(#31)
Minjae-An May 22, 2025
766775d
test: 투표 결과 저장 기능 단위 테스트 추가(#31)
Minjae-An May 22, 2025
66f782d
chore: cd 임시 비활성화(#31)
Minjae-An May 23, 2025
958770f
test: 투표 결과 조회 기능 단위 테스트 추가(#31)
Minjae-An May 23, 2025
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
1 change: 0 additions & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ name: cd
on:
push:
branches:
- dev
- main
paths-ignore:
- 'README.md'
Expand Down
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:

permissions:
contents: read
pull-requests: write

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down Expand Up @@ -36,4 +37,12 @@ jobs:
run: chmod +x gradlew

- name: gradlew test
run: ./gradlew test
run: ./gradlew test

- name : add coverage to PR
id: jacoco
uses: madrapps/[email protected]
with:
paths: |
${{ github.workspace }}/**/build/reports/jacoco/test/jacocoTestReport.xml
token: ${{ secrets.GITHUB_TOKEN }}
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,8 @@ out/
### VS Code ###
.vscode/

### properties/yml ###
### properties ###
/src/main/resources/conal-back-secret/*.properties

### querydsl Qclass ##
/src/main/generated/
52 changes: 52 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id 'java'
id 'org.springframework.boot' version '3.4.6-SNAPSHOT'
id 'io.spring.dependency-management' version '1.1.7'
id 'jacoco'
}

group = 'com.specialwarriors'
Expand Down Expand Up @@ -92,4 +93,55 @@ dependencies {

tasks.named('test') {
useJUnitPlatform()
finalizedBy jacocoTestReport
}

jacoco {
toolVersion = "0.8.11"
}

def jacocoExcludePatterns = [
'com/specialwarriors/conal/ConalApplication.class',
'**/common/**',
'**/exception/**',
'**/dto/**',
'**/config/**',
'**/enums/**',
'**/converter/**',
'**/test/**'
]

for (qPattern in '**/QA'..'**/QZ') {
jacocoExcludePatterns.add(qPattern + '*')
}

jacocoTestReport {
reports {
xml.required = true
csv.required = true
html.required = true
}

afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, excludes: jacocoExcludePatterns)
}))
}
}

jacocoTestCoverageVerification {
violationRules {

rule {
enabled = true
element = 'CLASS'

// 커버리지 제외 범위
excludes = jacocoExcludePatterns
}
}
}

clean {
delete file('src/main/generated')
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public String createVoteUserToken(String email, Date issuedAt, long expirationMi
.compact();
}

public String getEmailFrom(String token) {
public String extractEmailFrom(String token) {

return Jwts.parser().verifyWith(secretKey).build()
.parseSignedClaims(token)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
import java.util.ArrayList;
import java.util.List;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Table(name = "github_repos")
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode(of = "id")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Id기반으로 객체를 비교하면 어떤점에서 좋은가요?

public class GithubRepo {

@Id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
@RequiredArgsConstructor
public enum GithubRepoException implements BaseException {

UNAUTHORIZED_GITHUBREPO_ACCESS(HttpStatus.FORBIDDEN, "리포지토리 접근 권한이 없습니다"),
NOT_FOUND_GITHUBREPO_NAME(HttpStatus.NOT_FOUND, "깃허브 리포지토리 이름을 찾을 수 없습니다"),
NOT_FOUND_GITHUBREPO(HttpStatus.NOT_FOUND, "깃허브 리포지토리를 찾을 수 없습니다"),
NOT_FOUND_GITHUBREPO_EMAIL(HttpStatus.NOT_FOUND, "기여자 이메일이 없습니다"),
EXCEED_GITHUBREPO_EMAIL(HttpStatus.BAD_REQUEST, "이메일은 5개까지 등록할 수 있습니다"),
INVALID_GITHUBREPO_URL(HttpStatus.BAD_REQUEST, "잘못된 URL 입니다."),
INVALID_GITHUBREPO_EMAIL(HttpStatus.BAD_REQUEST, "잘못된 이메일 입니다"),
INVALID_GITHUBREPO_DURATION(HttpStatus.NOT_FOUND, "종료일이 존재하지 않습니다");
UNAUTHORIZED_GITHUB_REPO_ACCESS(HttpStatus.FORBIDDEN, "리포지토리 접근 권한이 없습니다"),
GITHUB_REPO_NAME_NOT_FOUND(HttpStatus.NOT_FOUND, "깃허브 리포지토리 이름을 찾을 수 없습니다"),
GITHUB_REPO_NOT_FOUND(HttpStatus.NOT_FOUND, "깃허브 리포지토리를 찾을 수 없습니다"),
GITHUB_REPO_EMAIL_NOT_FOUND(HttpStatus.NOT_FOUND, "기여자 이메일이 없습니다"),
GITHUB_REPO_EMAIL_LIMIT_EXCEED(HttpStatus.BAD_REQUEST, "이메일은 5개까지 등록할 수 있습니다"),
INVALID_GITHUB_REPO_URL(HttpStatus.BAD_REQUEST, "잘못된 URL 입니다."),
INVALID_GITHUB_REPO_EMAIL(HttpStatus.BAD_REQUEST, "잘못된 이메일 입니다"),
INVALID_GITHUB_REPO_DURATION(HttpStatus.NOT_FOUND, "종료일이 존재하지 않습니다");
Comment on lines +12 to +19
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 했어야했는데 죄송합니다...


private final HttpStatus status;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.specialwarriors.conal.github_repo.domain.GithubRepo;
import com.specialwarriors.conal.github_repo.exception.GithubRepoException;
import com.specialwarriors.conal.github_repo.repository.GithubRepoRepository;
import com.specialwarriors.conal.user.domain.User;
import com.specialwarriors.conal.user.service.UserQuery;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

Expand All @@ -12,23 +14,23 @@
public class GithubRepoQuery {

private final GithubRepoRepository githubRepoRepository;
private final UserQuery userQuery;

public GithubRepo findByUserIdAndRepositoryId(Long userId, Long repositoryId) {

GithubRepo githubRepo = githubRepoRepository.findById(repositoryId).orElseThrow(() ->
new GeneralException(GithubRepoException.NOT_FOUND_GITHUBREPO)
);
GithubRepo githubRepo = findById(repositoryId);
User user = userQuery.findById(userId);

if (!userId.equals(githubRepo.getUser().getId())) {
throw new GeneralException(GithubRepoException.UNAUTHORIZED_GITHUBREPO_ACCESS);
if (user.notHasGithubRepo(githubRepo)) {
throw new GeneralException(GithubRepoException.UNAUTHORIZED_GITHUB_REPO_ACCESS);
}

return githubRepo;
}

public GithubRepo findByRepositoryId(long repositoryId) {
public GithubRepo findById(long repositoryId) {

return githubRepoRepository.findById(repositoryId)
.orElseThrow(() -> new GeneralException(GithubRepoException.NOT_FOUND_GITHUBREPO));
.orElseThrow(() -> new GeneralException(GithubRepoException.GITHUB_REPO_NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ public GithubRepoCreateResponse createGithubRepo(Long userId, GithubRepoCreateRe

private void validateCreateRequest(GithubRepoCreateRequest request) {
if (request.name().isEmpty()) {
throw new GeneralException(GithubRepoException.NOT_FOUND_GITHUBREPO_NAME);
throw new GeneralException(GithubRepoException.GITHUB_REPO_NAME_NOT_FOUND);
}

if (!GITHUB_URL_PATTERN.matcher(request.url()).matches()) {
throw new GeneralException(GithubRepoException.INVALID_GITHUBREPO_URL);
throw new GeneralException(GithubRepoException.INVALID_GITHUB_REPO_URL);
}

long validEmailCount = request.emails().stream()
Expand All @@ -87,25 +87,25 @@ private void validateCreateRequest(GithubRepoCreateRequest request) {
.count();

if (validEmailCount == 0) {
throw new GeneralException(GithubRepoException.NOT_FOUND_GITHUBREPO_EMAIL);
throw new GeneralException(GithubRepoException.GITHUB_REPO_EMAIL_NOT_FOUND);
}
if (validEmailCount > 5) {
throw new GeneralException(GithubRepoException.EXCEED_GITHUBREPO_EMAIL);
throw new GeneralException(GithubRepoException.GITHUB_REPO_EMAIL_LIMIT_EXCEED);
}

for (String email : request.emails()) {

if (Objects.nonNull(email)) {
String trimmed = email.trim();
if (!trimmed.isEmpty() && !EMAIL_PATTERN.matcher(trimmed).matches()) {
throw new GeneralException(GithubRepoException.INVALID_GITHUBREPO_EMAIL);
throw new GeneralException(GithubRepoException.INVALID_GITHUB_REPO_EMAIL);
}
}

}

if (request.endDate() == null) {
throw new GeneralException(GithubRepoException.INVALID_GITHUBREPO_DURATION);
throw new GeneralException(GithubRepoException.INVALID_GITHUB_REPO_DURATION);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@ public class NotificationService {
public void updateNotificationAgreement(long userId, long repositoryId,
NotificationAgreementUpdateRequest request) {

GithubRepo githubRepo = githubRepoQuery.findByRepositoryId(repositoryId);
GithubRepo githubRepo = githubRepoQuery.findById(repositoryId);

NotificationType notificationType = NotificationType.valueOf(request.type());
NotificationAgreement notificationAgreement = notificationAgreementQuery
.findByGithubRepoAndType(githubRepo, notificationType);

// 사용자가 자신의 github repo에 접근한 것이 맞는 지 검증
User user = userQuery.findById(userId);
if (!user.hasGithubRepo(repositoryId)) {
throw new GeneralException(GithubRepoException.UNAUTHORIZED_GITHUBREPO_ACCESS);

if (user.notHasGithubRepo(githubRepo)) {
throw new GeneralException(GithubRepoException.UNAUTHORIZED_GITHUB_REPO_ACCESS);
}

if (request.isAgree()) {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/specialwarriors/conal/user/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ public User(int githubId, String username, String avatarUrl) {
this.avatarUrl = avatarUrl;
}

public boolean hasGithubRepo(long repositoryId) {
public boolean notHasGithubRepo(GithubRepo githubRepo) {

return githubRepos.stream().anyMatch(repo -> repo.getId() == repositoryId);
return !githubRepos.contains(githubRepo);
}

public void addGithubRepo(GithubRepo githubRepo) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/specialwarriors/conal/util/UrlUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static String[] urlToOwnerAndReponame(String url) {

return new String[]{owner, repoName};
} else {
throw new GeneralException(GithubRepoException.INVALID_GITHUBREPO_URL);
throw new GeneralException(GithubRepoException.INVALID_GITHUB_REPO_URL);
}
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void openVote(long repoId) {
final Date issuedAt = new Date();
final long expirationMillis = 604800000;

GithubRepo githubRepo = githubRepoQuery.findByRepositoryId(repoId);
GithubRepo githubRepo = githubRepoQuery.findById(repoId);
List<Contributor> contributors = githubRepo.getContributors();

String[] userTokens = contributors.stream().map(Contributor::getEmail)
Expand All @@ -64,7 +64,7 @@ public List<String> findVoteTargetEmails(long repoId, String userToken) {
throw new GeneralException(VoteException.UNAUTHORIZED_VOTE_ACCESS);
}

GithubRepo githubRepo = githubRepoQuery.findByRepositoryId(repoId);
GithubRepo githubRepo = githubRepoQuery.findById(repoId);

return githubRepo.getContributors().stream()
.map(Contributor::getEmail)
Expand All @@ -81,10 +81,10 @@ public List<VoteFormResponse> getVoteFormResponse(long repoId) {
}

Set<String> userTokens = redisTemplate.opsForSet().members(voteKey);
List<String> voteTargetEmails = userTokens.stream().map(jwtProvider::getEmailFrom).toList();
List<String> voteTargetEmails = userTokens.stream().map(jwtProvider::extractEmailFrom).toList();

return userTokens.stream().map(userToken -> {
String email = jwtProvider.getEmailFrom(userToken);
String email = jwtProvider.extractEmailFrom(userToken);

return new VoteFormResponse(repoId, userToken, email, voteTargetEmails);
})
Expand Down
Loading