Skip to content

Commit

Permalink
feat: connect project & prs (#43)
Browse files Browse the repository at this point in the history
* feat: connect project & prs

* 🔨 modify: web config

---------

Co-authored-by: Zerohertz <[email protected]>
  • Loading branch information
ssoheeh and Zerohertz authored Feb 9, 2025
1 parent 5922b62 commit 29071fd
Show file tree
Hide file tree
Showing 12 changed files with 258 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;

public interface ProjectRepository extends JpaRepository<Project, Long> {
List<Project> findByOwnerId(Long ownerId);

Optional<Project> findByUrl(String url);

Optional<Project> findByName(String name);
Project findByOwnerIdAndName(Long ownerId, String name);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.server.domain.project.dto.ProjectDto;
import com.server.domain.project.entity.Project;
import com.server.domain.project.repository.ProjectRepository;
import com.server.domain.pull.enums.PullRequestState;
import com.server.domain.pull.service.PullRequestService;
import com.server.domain.user.entity.User;
import com.server.domain.user.service.UserService;
import com.server.global.error.code.AuthErrorCode;
Expand All @@ -23,18 +25,22 @@ public class ProjectService {
private final UserService userService;
private final JwtService jwtService;
private final ProjectRepository projectRepository;
private final PullRequestService pullRequestService;

public ProjectDto createProject(HttpServletRequest request, String repoUrl, String name) {
String username = jwtService.extractUsernameFromToken(request)
.orElseThrow(() -> new AuthException(AuthErrorCode.INVALID_ACCESS_TOKEN));
User user = userService.getUserWithPersonalInfo(username);
String afterCom = repoUrl.substring(repoUrl.indexOf(".com/") + 5);
String[] parts = afterCom.split("/");

Project p = projectRepository.save(Project.builder()
.name(name)
.url(repoUrl)
.s3Path("")
.ownerId(user.getId())
.build());
pullRequestService.getPullRequestsWithProject(user, parts[0], parts[1], PullRequestState.ALL);

return ProjectDto.from(p);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;

import com.server.domain.pull.dto.PullRequestWithProjectDto;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand Down Expand Up @@ -45,4 +46,13 @@ public ApiResponseDto<GetPullRequestInfoOutDto> getPullRequests(HttpServletReque
return ApiResponseDto.success(HttpStatus.OK.value(),
pullRequestService.getPullRequest(request, userOrOrgName, repositoryName, pullNo));
}

@ResponseStatus(HttpStatus.OK)
@GetMapping("/{projectName}")
@Operation(summary = "프로젝트 이름으로 pull request 목록 조회", description = "프로젝트 이름을 입력 받아 해당 프로젝트와 연관되어있는 풀리퀘 목록 반환해줍니다.")
public ApiResponseDto<List<PullRequestWithProjectDto>> getPullRequestsByProjectName(HttpServletRequest request,
@PathVariable String projectName) {
return ApiResponseDto.success(HttpStatus.OK.value(),
pullRequestService.getPullRequestByProjectName(request, projectName));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import com.fasterxml.jackson.annotation.JsonProperty;

import com.server.domain.pull.entity.PullRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

Expand Down Expand Up @@ -34,4 +37,6 @@ public class GetPullRequestInfoOutDto extends PullRequestDto {
@JsonProperty("changed_files")
int changedFiles;



}
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package com.server.domain.pull.dto;

import com.server.domain.pull.enums.PullRequestState;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;

@Getter
@Setter
@Builder
public class GetPullRequestOutDto extends PullRequestDto {

}
23 changes: 23 additions & 0 deletions src/main/java/com/server/domain/pull/dto/PullRequestDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.server.domain.pull.entity.PullRequest;
import com.server.domain.pull.enums.PullRequestState;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

@Getter
Expand Down Expand Up @@ -45,4 +48,24 @@ private void unpackHead(JsonNode head) {

@JsonProperty("merged_at")
private LocalDateTime mergedAt;

public static PullRequest toEntity(PullRequestDto pullRequestDto){

return PullRequest.builder()
.prNumber(pullRequestDto.getPrId())
.url(pullRequestDto.getUrl())
.title(pullRequestDto.getTitle())
.ownerId(pullRequestDto.getOwnerId())
.branchName(pullRequestDto.getBranchName())
.status(pullRequestDto.getStatus())
.createdAt(pullRequestDto.getCreatedAt())
.closedAt(pullRequestDto.getClosedAt())
.mergedAt(pullRequestDto.getMergedAt())
.build();
}




}

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.server.domain.pull.dto;


import com.fasterxml.jackson.databind.JsonNode;
import com.server.domain.pull.entity.PullRequest;
import com.server.domain.pull.enums.PullRequestState;
import lombok.Builder;
import lombok.Getter;

import java.time.LocalDateTime;

@Builder
@Getter
public class PullRequestWithProjectDto {
private Integer prId;

private String url;

private String ownerId;

private String title;

private String branchName;

private PullRequestState status;

private LocalDateTime createdAt;

private LocalDateTime closedAt;

private LocalDateTime mergedAt;

public static PullRequestWithProjectDto toDto(PullRequest pullRequest){
return PullRequestWithProjectDto.builder()
.prId(pullRequest.getPrNumber())
.url(pullRequest.getUrl())
.ownerId(pullRequest.getOwnerId())
.title(pullRequest.getTitle())
.branchName(pullRequest.getBranchName())
.status(pullRequest.getStatus())
.createdAt(pullRequest.getCreatedAt())
.mergedAt(pullRequest.getMergedAt())
.closedAt(pullRequest.getClosedAt())
.build();
}
}
65 changes: 65 additions & 0 deletions src/main/java/com/server/domain/pull/entity/PullRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.server.domain.pull.entity;

import com.server.domain.project.entity.Project;
import com.server.domain.pull.enums.PullRequestState;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@Entity
@EntityListeners(AuditingEntityListener.class)
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "pull_requests")
@Builder
public class PullRequest {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "pull_request_id")
private Long id;

@Column(name = "pr_number")
private Integer prNumber;

@Column(name = "pull_request_url")
private String url;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "project_id")
@OnDelete(action = OnDeleteAction.CASCADE)
private Project project;

@Column(name = "pull_request_title")
private String title;

@Column(name = "pull_request_user_id")
private String ownerId;

@Column(name = "branch_name")
private String branchName;

@Column(name = "state")
private PullRequestState status;

@Column(name = "created_at")
private LocalDateTime createdAt;

@Column(name = "closed_at")
private LocalDateTime closedAt;

@Column(name = "merged_at")
private LocalDateTime mergedAt;


public void setProject(Project project){
this.project = project;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.server.domain.pull.repository;

import com.server.domain.project.entity.Project;
import com.server.domain.pull.entity.PullRequest;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface PullRequestRepository extends JpaRepository<PullRequest, Long> {
List<PullRequest> findByProject(Project project);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
package com.server.domain.pull.service;

import java.util.List;
import java.util.stream.Collectors;

import com.server.domain.project.entity.Project;
import com.server.domain.project.repository.ProjectRepository;
import com.server.domain.pull.dto.PullRequestDto;
import com.server.domain.pull.dto.PullRequestWithProjectDto;
import com.server.domain.pull.entity.PullRequest;
import com.server.domain.pull.repository.PullRequestRepository;
import com.server.global.error.code.ProjectErrorCode;
import com.server.global.error.exception.BusinessException;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
Expand Down Expand Up @@ -32,9 +41,48 @@ public class PullRequestService {

private final UserService userService;
private final JwtService jwtService;
private final PullRequestRepository pullRequestRepository;
private final ProjectRepository projectRepository;

public List<GetPullRequestOutDto> getPullRequests(HttpServletRequest request, String userOrOrgName,
public List<GetPullRequestOutDto> getPullRequestsWithProject(User user, String userOrOrgName,
String repositoryName, PullRequestState state) {

RestTemplate restTemplate = new RestTemplate();
String url = String.format("https://api.github.com/repos/%s/%s/pulls", userOrOrgName, repositoryName);
if (state != null) {
url = String.format("%s?state=%s", url, state.getValue());
}
ResponseEntity<List<GetPullRequestOutDto>> githubPullRequests = restTemplate.exchange(
url,
HttpMethod.GET,
buildGithubHttpEntity(user.getGithubToken()),
new ParameterizedTypeReference<List<GetPullRequestOutDto>>() {
});
if (githubPullRequests.getStatusCode().value() != 200) {
throw new AuthException(AuthErrorCode.OAUTH_PROCESS_ERROR);
}

List<PullRequest> pullRequests = githubPullRequests.getBody().stream()
.map(PullRequestDto::toEntity)
.toList();

String repoUrl = String.format("https://github.com/%s/%s", userOrOrgName, repositoryName);

Project project = projectRepository.findByUrl(repoUrl).orElseThrow(
()->new BusinessException(ProjectErrorCode.NOT_FOUND)
);

pullRequests.forEach(pullRequest -> {
pullRequest.setProject(project);
});

pullRequestRepository.saveAll(pullRequests);

return githubPullRequests.getBody();
}

public List<GetPullRequestOutDto> getPullRequests(HttpServletRequest request, String userOrOrgName,
String repositoryName, PullRequestState state) {
String username = jwtService.extractUsernameFromToken(request)
.orElseThrow(() -> new AuthException(AuthErrorCode.INVALID_ACCESS_TOKEN));
User user = userService.getUserWithPersonalInfo(username);
Expand All @@ -53,9 +101,11 @@ public List<GetPullRequestOutDto> getPullRequests(HttpServletRequest request, St
if (githubPullRequests.getStatusCode().value() != 200) {
throw new AuthException(AuthErrorCode.OAUTH_PROCESS_ERROR);
}

return githubPullRequests.getBody();
}


public GetPullRequestInfoOutDto getPullRequest(HttpServletRequest request, String userOrOrgName,
String repositoryName, int pullNo) {
String username = jwtService.extractUsernameFromToken(request)
Expand Down Expand Up @@ -87,4 +137,20 @@ private HttpEntity<MultiValueMap<String, String>> buildGithubHttpEntity(String a
headers.setBearerAuth(accessToken);
return new HttpEntity<>(params, headers);
}

public List<PullRequestWithProjectDto> getPullRequestByProjectName(HttpServletRequest request, String projectName) {
String username = jwtService.extractUsernameFromToken(request)
.orElseThrow(() -> new AuthException(AuthErrorCode.INVALID_ACCESS_TOKEN));
User user = userService.getUserWithPersonalInfo(username);

Project p = projectRepository.findByName(projectName).orElseThrow(()-> new BusinessException(ProjectErrorCode.NOT_FOUND));


List<PullRequest> pullRequests = pullRequestRepository.findByProject(p);

return pullRequests.stream()
.map(PullRequestWithProjectDto::toDto)
.toList();

}
}
2 changes: 1 addition & 1 deletion src/main/java/com/server/global/config/WebConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// FIXME: 우선은 CORS 전체 허용
registry.addMapping("/api/**")
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/com/server/global/error/code/ProjectErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.server.global.error.code;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum ProjectErrorCode implements ErrorCode {
NOT_FOUND(HttpStatus.NOT_FOUND.value(), "프로젝트가 존재하지 않습니다.");

private final int status;
private final String message;
}

0 comments on commit 29071fd

Please sign in to comment.