diff --git a/src/main/java/com/teamEWSN/gitdeun/codereference/controller/CodeReferenceController.java b/src/main/java/com/teamEWSN/gitdeun/codereference/controller/CodeReferenceController.java index 904cce0..35d093f 100644 --- a/src/main/java/com/teamEWSN/gitdeun/codereference/controller/CodeReferenceController.java +++ b/src/main/java/com/teamEWSN/gitdeun/codereference/controller/CodeReferenceController.java @@ -1,5 +1,4 @@ package com.teamEWSN.gitdeun.codereference.controller; public class CodeReferenceController { - -} \ No newline at end of file +} diff --git a/src/main/java/com/teamEWSN/gitdeun/codereference/entity/CodeReference.java b/src/main/java/com/teamEWSN/gitdeun/codereference/entity/CodeReference.java index e71e410..7eae685 100644 --- a/src/main/java/com/teamEWSN/gitdeun/codereference/entity/CodeReference.java +++ b/src/main/java/com/teamEWSN/gitdeun/codereference/entity/CodeReference.java @@ -1,5 +1,31 @@ package com.teamEWSN.gitdeun.codereference.entity; +import com.teamEWSN.gitdeun.mindmapnode.entity.MindmapNode; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "code_reference") public class CodeReference { - + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "node_id", nullable = false) + private MindmapNode node; + + @Column(name = "file_path", columnDefinition = "TEXT", nullable = false) + private String filePath; + + @Column(name = "start_line", length = 255) + private String startLine; + + @Column(name = "end_line", length = 255) + private String endLine; } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/codereview/entity/CodeReview.java b/src/main/java/com/teamEWSN/gitdeun/codereview/entity/CodeReview.java index f36f8e8..84b1779 100644 --- a/src/main/java/com/teamEWSN/gitdeun/codereview/entity/CodeReview.java +++ b/src/main/java/com/teamEWSN/gitdeun/codereview/entity/CodeReview.java @@ -1,5 +1,46 @@ package com.teamEWSN.gitdeun.codereview.entity; -public class CodeReview { - +import com.teamEWSN.gitdeun.common.util.AuditedEntity; +import com.teamEWSN.gitdeun.mindmapnode.entity.MindmapNode; +import com.teamEWSN.gitdeun.user.entity.User; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.ColumnDefault; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "Code_Review") +public class CodeReview extends AuditedEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "author_id", nullable = false) + private User author; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "node_id", nullable = false) + private MindmapNode node; + + @Column(name = "ref_id") + private Long refId; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + @ColumnDefault("'PENDING'") + private CodeReviewStatus status; + + @Column(name = "comment_cnt") + @ColumnDefault("0") + private Integer commentCount; + + @Column(name = "unresolved_thread_cnt") + @ColumnDefault("0") + private Integer unresolvedThreadCount; + } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/codereview/entity/CodeReviewStatus.java b/src/main/java/com/teamEWSN/gitdeun/codereview/entity/CodeReviewStatus.java new file mode 100644 index 0000000..99a0912 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/codereview/entity/CodeReviewStatus.java @@ -0,0 +1,6 @@ +package com.teamEWSN.gitdeun.codereview.entity; + +public enum CodeReviewStatus { + PENDING, + RESOLVED +} diff --git a/src/main/java/com/teamEWSN/gitdeun/comment/controller/CommentController.java b/src/main/java/com/teamEWSN/gitdeun/comment/controller/CommentController.java new file mode 100644 index 0000000..154605b --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/comment/controller/CommentController.java @@ -0,0 +1,4 @@ +package com.teamEWSN.gitdeun.comment.controller; + +public class CommentController { +} diff --git a/src/main/java/com/teamEWSN/gitdeun/comment/dto/CommentResponseDto.java b/src/main/java/com/teamEWSN/gitdeun/comment/dto/CommentResponseDto.java new file mode 100644 index 0000000..e306b6e --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/comment/dto/CommentResponseDto.java @@ -0,0 +1,5 @@ +package com.teamEWSN.gitdeun.comment.dto; + +public class CommentResponseDto { + +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/comment/entity/AttachmentType.java b/src/main/java/com/teamEWSN/gitdeun/comment/entity/AttachmentType.java new file mode 100644 index 0000000..7433cc5 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/comment/entity/AttachmentType.java @@ -0,0 +1,6 @@ +package com.teamEWSN.gitdeun.comment.entity; + +public enum AttachmentType { + IMAGE, + FILE +} diff --git a/src/main/java/com/teamEWSN/gitdeun/comment/entity/Comment.java b/src/main/java/com/teamEWSN/gitdeun/comment/entity/Comment.java new file mode 100644 index 0000000..72e028c --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/comment/entity/Comment.java @@ -0,0 +1,44 @@ +package com.teamEWSN.gitdeun.comment.entity; + +import com.teamEWSN.gitdeun.codereview.entity.CodeReview; +import com.teamEWSN.gitdeun.common.util.AuditedEntity; +import com.teamEWSN.gitdeun.user.entity.User; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "Comment") +public class Comment extends AuditedEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "code_review_id", nullable = false) + private CodeReview codeReview; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_comment_id") + private Comment parentComment; + + @Column(columnDefinition = "TEXT", nullable = false) + private String content; + + @Enumerated(EnumType.STRING) + @Column(name = "emoji_type") + private EmojiType emojiType; + + @Column(name = "resolved_at") + private LocalDateTime resolvedAt; +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/comment/entity/CommentAttachment.java b/src/main/java/com/teamEWSN/gitdeun/comment/entity/CommentAttachment.java new file mode 100644 index 0000000..42c380a --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/comment/entity/CommentAttachment.java @@ -0,0 +1,37 @@ +package com.teamEWSN.gitdeun.comment.entity; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "Comment_Attachment") +public class CommentAttachment { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "comment_id", nullable = false) + private Comment comment; + + @Column(length = 255, nullable = false) + private String url; + + @Column(name = "file_name", length = 200, nullable = false) + private String fileName; + + @Column(name = "mime_type", length = 100, nullable = false) + private String mimeType; + + @Column(nullable = false) + private Long size; + + @Enumerated(EnumType.STRING) + @Column(name = "attachment_type", nullable = false) + private AttachmentType attachmentType; +} diff --git a/src/main/java/com/teamEWSN/gitdeun/comment/entity/EmojiType.java b/src/main/java/com/teamEWSN/gitdeun/comment/entity/EmojiType.java new file mode 100644 index 0000000..96c76fc --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/comment/entity/EmojiType.java @@ -0,0 +1,9 @@ +package com.teamEWSN.gitdeun.comment.entity; + +public enum EmojiType { + QUESTION, + IDEA, + BUG, + IMPORTANT, + LOVE +} diff --git a/src/main/java/com/teamEWSN/gitdeun/comment/repository/CommentRepository.java b/src/main/java/com/teamEWSN/gitdeun/comment/repository/CommentRepository.java new file mode 100644 index 0000000..e9ce416 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/comment/repository/CommentRepository.java @@ -0,0 +1,5 @@ +package com.teamEWSN.gitdeun.comment.repository; + +public class CommentRepository { + +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/comment/service/CommentService.java b/src/main/java/com/teamEWSN/gitdeun/comment/service/CommentService.java new file mode 100644 index 0000000..1bbffe9 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/comment/service/CommentService.java @@ -0,0 +1,5 @@ +package com.teamEWSN.gitdeun.comment.service; + +public class CommentService { + +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/common/config/FastApiConfig.java b/src/main/java/com/teamEWSN/gitdeun/common/config/FastApiConfig.java new file mode 100644 index 0000000..430d07a --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/common/config/FastApiConfig.java @@ -0,0 +1,21 @@ +package com.teamEWSN.gitdeun.common.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class FastApiConfig { + + @Value("${fastapi.base-url}") + private String baseUrl; + + // FastAPI 서버와 통신하기 위한 전용 WebClient Bean + @Bean("fastApiWebClient") + public WebClient webClient() { + return WebClient.builder() + .baseUrl(baseUrl) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/common/config/WebClientConfig.java b/src/main/java/com/teamEWSN/gitdeun/common/config/WebClientConfig.java index f9e78f8..6022d60 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/config/WebClientConfig.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/config/WebClientConfig.java @@ -7,7 +7,8 @@ @Configuration public class WebClientConfig { - @Bean + // OAuth 및 기타 외부 API 통신을 위한 범용 WebClient Bean + @Bean("oauthWebClient") public WebClient webClient() { return WebClient.builder().build(); } diff --git a/src/main/java/com/teamEWSN/gitdeun/common/exception/ErrorCode.java b/src/main/java/com/teamEWSN/gitdeun/common/exception/ErrorCode.java index a0cd2ed..05d382d 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/exception/ErrorCode.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/exception/ErrorCode.java @@ -34,6 +34,10 @@ public enum ErrorCode { SOCIAL_ACCOUNT_CONNECT_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "OAUTH-006", "소셜 계정 연동에 실패했습니다."), SOCIAL_TOKEN_REFRESH_NOT_SUPPORTED(HttpStatus.BAD_REQUEST, "OAUTH-007", "리프레시 토큰 갱신은 지원하지 않습니다. 재인증이 필요합니다."), + // 리포지토리 관련 + REPO_NOT_FOUND_BY_ID(HttpStatus.NOT_FOUND, "REPO-001", "해당 ID로 요청한 리포지토리를 찾을 수 없습니다."), + REPO_NOT_FOUND_BY_URL(HttpStatus.NOT_FOUND, "REPO-002", "해당 URL로 요청한 리포지토리를 찾을 수 없습니다."), + // S3 파일 관련 // Client Errors (4xx) FILE_NOT_FOUND(HttpStatus.NOT_FOUND, "FILE-001", "요청한 파일을 찾을 수 없습니다."), diff --git a/src/main/java/com/teamEWSN/gitdeun/common/fastapi/FastApiClient.java b/src/main/java/com/teamEWSN/gitdeun/common/fastapi/FastApiClient.java new file mode 100644 index 0000000..894e902 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/common/fastapi/FastApiClient.java @@ -0,0 +1,44 @@ +package com.teamEWSN.gitdeun.common.fastapi; + +import com.teamEWSN.gitdeun.common.fastapi.dto.FastApiCommitTimeResponse; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; + +import java.time.LocalDateTime; + +@Component +public class FastApiClient { + + private final WebClient webClient; // FastApiConfig에서 생성한 Bean을 주입받음 + + public FastApiClient(@Qualifier("fastApiWebClient") WebClient webClient) { + this.webClient = webClient; + } + + /** + * FastAPI 서버에 특정 GitHub 리포지토리의 최신 커밋 시간을 요청합니다. + * @param githubRepoUrl 조회할 리포지토리의 URL + * @return 최신 커밋 시간 + */ + public LocalDateTime fetchLatestCommitTime(String githubRepoUrl) { + // FastAPI의 가벼운 엔드포인트(예: /check-commit-time)를 호출합니다. + FastApiCommitTimeResponse response = webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/check-commit-time") // FastAPI에 정의된 엔드포인트 경로 + .queryParam("url", githubRepoUrl) // 쿼리 파라미터로 URL 전달 + .build()) + .retrieve() // 응답을 받아옴 + .bodyToMono(FastApiCommitTimeResponse.class) // 응답 본문을 DTO로 변환 + .block(); // 비동기 응답을 동기적으로 기다림 + + // null 체크 후 날짜 반환 + if (response == null) { + throw new RuntimeException("FastAPI 서버로부터 최신 커밋 시간 정보를 받아오지 못했습니다."); + } + return response.getLatestCommitAt(); + } + + // TODO: requestAnalysis 등 다른 FastAPI 호출 메서드들도 여기에 구현 + +} diff --git a/src/main/java/com/teamEWSN/gitdeun/common/fastapi/dto/AnalysisResultDto.java b/src/main/java/com/teamEWSN/gitdeun/common/fastapi/dto/AnalysisResultDto.java new file mode 100644 index 0000000..ff5d85f --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/common/fastapi/dto/AnalysisResultDto.java @@ -0,0 +1,21 @@ +package com.teamEWSN.gitdeun.common.fastapi.dto; + +import com.teamEWSN.gitdeun.mindmap.entity.MindmapType; +import lombok.Getter; + +import java.time.LocalDateTime; + +@Getter +public class AnalysisResultDto { + // FastAPI가 반환하는 Repo 관련 정보 + private String defaultBranch; + private String language; + private String description; + private LocalDateTime githubLastUpdatedAt; + + // FastAPI가 반환하는 Mindmap 관련 정보 + private String mapData; + private MindmapType type; + private String prompt; + // TODO: FastAPI 응답에 맞춰 필드 정의 +} diff --git a/src/main/java/com/teamEWSN/gitdeun/common/fastapi/dto/FastApiCommitTimeResponse.java b/src/main/java/com/teamEWSN/gitdeun/common/fastapi/dto/FastApiCommitTimeResponse.java new file mode 100644 index 0000000..40f202e --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/common/fastapi/dto/FastApiCommitTimeResponse.java @@ -0,0 +1,12 @@ +package com.teamEWSN.gitdeun.common.fastapi.dto; + +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Setter // JSON 역직렬화를 위해 필요 +public class FastApiCommitTimeResponse { + private LocalDateTime latestCommitAt; +} diff --git a/src/main/java/com/teamEWSN/gitdeun/common/oauth/entity/OauthProvider.java b/src/main/java/com/teamEWSN/gitdeun/common/oauth/entity/OauthProvider.java index f573228..52054d9 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/oauth/entity/OauthProvider.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/oauth/entity/OauthProvider.java @@ -2,5 +2,5 @@ public enum OauthProvider { GOOGLE, - GITHUB, + GITHUB } diff --git a/src/main/java/com/teamEWSN/gitdeun/common/oauth/service/GitHubApiHelper.java b/src/main/java/com/teamEWSN/gitdeun/common/oauth/service/GitHubApiHelper.java index c87661b..12a779d 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/oauth/service/GitHubApiHelper.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/oauth/service/GitHubApiHelper.java @@ -3,8 +3,8 @@ import com.teamEWSN.gitdeun.common.exception.ErrorCode; import com.teamEWSN.gitdeun.common.exception.GlobalException; import com.teamEWSN.gitdeun.common.oauth.dto.GitHubEmailDto; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpHeaders; @@ -20,11 +20,14 @@ @Slf4j @Component -@RequiredArgsConstructor public class GitHubApiHelper { private final WebClient webClient; + public GitHubApiHelper(@Qualifier("oauthWebClient") WebClient webClient) { + this.webClient = webClient; + } + @Value("${spring.security.oauth2.client.registration.github.client-id}") private String clientId; diff --git a/src/main/java/com/teamEWSN/gitdeun/common/oauth/service/GoogleApiHelper.java b/src/main/java/com/teamEWSN/gitdeun/common/oauth/service/GoogleApiHelper.java index 7a0d3c8..dadc42b 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/oauth/service/GoogleApiHelper.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/oauth/service/GoogleApiHelper.java @@ -3,8 +3,8 @@ import com.teamEWSN.gitdeun.common.exception.ErrorCode; import com.teamEWSN.gitdeun.common.exception.GlobalException; import com.teamEWSN.gitdeun.common.oauth.record.GoogleTokenResponse; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; @@ -18,11 +18,14 @@ @Slf4j @Component -@RequiredArgsConstructor public class GoogleApiHelper { private final WebClient webClient; + public GoogleApiHelper(@Qualifier("oauthWebClient") WebClient webClient) { + this.webClient = webClient; + } + @Value("${spring.security.oauth2.client.registration.google.client-id}") private String googleClientId; diff --git a/src/main/java/com/teamEWSN/gitdeun/common/oauth/service/SocialTokenRefreshService.java b/src/main/java/com/teamEWSN/gitdeun/common/oauth/service/SocialTokenRefreshService.java index 2d2a0f5..41c22d0 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/oauth/service/SocialTokenRefreshService.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/oauth/service/SocialTokenRefreshService.java @@ -1,6 +1,5 @@ package com.teamEWSN.gitdeun.common.oauth.service; -import com.fasterxml.jackson.databind.ObjectMapper; import com.teamEWSN.gitdeun.common.exception.GlobalException; import com.teamEWSN.gitdeun.common.exception.ErrorCode; import com.teamEWSN.gitdeun.common.oauth.entity.OauthProvider; @@ -10,11 +9,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.util.Optional; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpHeaders; + import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.reactive.function.client.WebClient; + +import static com.teamEWSN.gitdeun.common.exception.ErrorCode.*; // 레포 및 마인드맵 호출 시 소셜로그인 토큰 갱신 호출 @@ -25,22 +24,14 @@ public class SocialTokenRefreshService { private final SocialConnectionRepository socialConnectionRepository; - private final WebClient webClient; - private final ObjectMapper objectMapper = new ObjectMapper(); // JSON 파싱을 위한 ObjectMapper' private final GitHubApiHelper gitHubApiHelper; private final GoogleApiHelper googleApiHelper; - @Value("${spring.security.oauth2.client.registration.google.client-id}") - private String googleClientId; - - @Value("${spring.security.oauth2.client.registration.google.client-secret}") - private String googleClientSecret; - // 기존 refreshToken 기반 갱신(주기적/자동 갱신) public void refreshSocialToken(Long userId, OauthProvider provider) { SocialConnection connection = socialConnectionRepository.findByUserIdAndProvider(userId, provider) - .orElseThrow(() -> new GlobalException(ErrorCode.SOCIAL_CONNECTION_NOT_FOUND)); + .orElseThrow(() -> new GlobalException(SOCIAL_CONNECTION_NOT_FOUND)); switch (provider) { case GOOGLE -> refreshGoogle(connection, Optional.empty(), Optional.empty()); @@ -81,7 +72,7 @@ private void refreshGoogle(SocialConnection conn, // 2. refreshToken 기반 재발급 (latestRefresh가 있으면 그것 사용, 없으면 기존) String refreshToUse = latestRefreshOpt.orElse(conn.getRefreshToken()); if (refreshToUse == null) { - throw new GlobalException(ErrorCode.INVALID_REFRESH_TOKEN); + throw new GlobalException(INVALID_REFRESH_TOKEN); } GoogleTokenResponse res = googleApiHelper.refreshToken(refreshToUse); diff --git a/src/main/java/com/teamEWSN/gitdeun/invitation/entity/Invitation.java b/src/main/java/com/teamEWSN/gitdeun/invitation/entity/Invitation.java index 720d849..9879940 100644 --- a/src/main/java/com/teamEWSN/gitdeun/invitation/entity/Invitation.java +++ b/src/main/java/com/teamEWSN/gitdeun/invitation/entity/Invitation.java @@ -1,5 +1,47 @@ package com.teamEWSN.gitdeun.invitation.entity; +import com.teamEWSN.gitdeun.mindmap.entity.Mindmap; +import com.teamEWSN.gitdeun.user.entity.User; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.CreationTimestamp; + +import java.time.LocalDateTime; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "Invitation") public class Invitation { - + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mindmap_id", nullable = false) + private Mindmap mindmap; + + @Column(length = 36, nullable = false, unique = true) + private String token; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + @ColumnDefault("'READ_ONLY'") + private InvitationStatus status; + + @CreationTimestamp + @Column(name = "invited_at", updatable = false) + private LocalDateTime invitedAt; + + @Column(name = "is_accept", nullable = false) + @ColumnDefault("false") + private boolean isAccept; } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/invitation/entity/InvitationStatus.java b/src/main/java/com/teamEWSN/gitdeun/invitation/entity/InvitationStatus.java new file mode 100644 index 0000000..09101f3 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/invitation/entity/InvitationStatus.java @@ -0,0 +1,6 @@ +package com.teamEWSN.gitdeun.invitation.entity; + +public enum InvitationStatus { + READ_ONLY, + EDIT_ALLOWED +} diff --git a/src/main/java/com/teamEWSN/gitdeun/meeting/controller/MeetingController.java b/src/main/java/com/teamEWSN/gitdeun/meeting/controller/MeetingController.java new file mode 100644 index 0000000..9241da3 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/meeting/controller/MeetingController.java @@ -0,0 +1,4 @@ +package com.teamEWSN.gitdeun.meeting.controller; + +public class MeetingController { +} diff --git a/src/main/java/com/teamEWSN/gitdeun/meeting/dto/MeetingResponseDto.java b/src/main/java/com/teamEWSN/gitdeun/meeting/dto/MeetingResponseDto.java new file mode 100644 index 0000000..0e4edf7 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/meeting/dto/MeetingResponseDto.java @@ -0,0 +1,5 @@ +package com.teamEWSN.gitdeun.meeting.dto; + +public class MeetingResponseDto { + +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/meeting/entity/Meeting.java b/src/main/java/com/teamEWSN/gitdeun/meeting/entity/Meeting.java new file mode 100644 index 0000000..1f1676c --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/meeting/entity/Meeting.java @@ -0,0 +1,46 @@ +package com.teamEWSN.gitdeun.meeting.entity; + +import com.teamEWSN.gitdeun.common.util.CreatedEntity; +import com.teamEWSN.gitdeun.mindmapnode.entity.MindmapNode; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.ColumnDefault; + +import java.time.LocalDateTime; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "Meeting") +public class Meeting extends CreatedEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "node_id", nullable = false) + private MindmapNode node; + + @Column(name = "room_name", length = 255, nullable = false) + private String roomName; + + @Column(length = 255) + private String title; + + @Column(columnDefinition = "TEXT") + private String summary; + + @Column(name = "shared_to_ai", nullable = false) + @ColumnDefault("false") + private boolean sharedToAI; + + @Column(name = "started_at", nullable = false) + private LocalDateTime startedAt; + + @Column(name = "ended_at") + private LocalDateTime endedAt; + +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/meeting/entity/Participant.java b/src/main/java/com/teamEWSN/gitdeun/meeting/entity/Participant.java new file mode 100644 index 0000000..65ccea3 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/meeting/entity/Participant.java @@ -0,0 +1,36 @@ +package com.teamEWSN.gitdeun.meeting.entity; + +import com.teamEWSN.gitdeun.user.entity.User; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.CreationTimestamp; + +import java.time.LocalDateTime; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "Participant") +@IdClass(ParticipantId.class) +public class Participant { + + @Id + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @Id + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "meeting_id", nullable = false) + private Meeting meeting; + + @CreationTimestamp + @Column(name = "joined_at", nullable = false, updatable = false) + private LocalDateTime joinedAt; + + @Column(name = "left_at") + private LocalDateTime leftAt; + +} diff --git a/src/main/java/com/teamEWSN/gitdeun/meeting/entity/ParticipantId.java b/src/main/java/com/teamEWSN/gitdeun/meeting/entity/ParticipantId.java new file mode 100644 index 0000000..673a00f --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/meeting/entity/ParticipantId.java @@ -0,0 +1,13 @@ +package com.teamEWSN.gitdeun.meeting.entity; + +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@NoArgsConstructor +@EqualsAndHashCode +public class ParticipantId implements Serializable { + private Long user; + private Long meeting; +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/meeting/repository/MeetingRepository.java b/src/main/java/com/teamEWSN/gitdeun/meeting/repository/MeetingRepository.java new file mode 100644 index 0000000..c38249a --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/meeting/repository/MeetingRepository.java @@ -0,0 +1,5 @@ +package com.teamEWSN.gitdeun.meeting.repository; + +public class MeetingRepository { + +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/meeting/service/MeetingService.java b/src/main/java/com/teamEWSN/gitdeun/meeting/service/MeetingService.java new file mode 100644 index 0000000..4f11b95 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/meeting/service/MeetingService.java @@ -0,0 +1,5 @@ +package com.teamEWSN.gitdeun.meeting.service; + +public class MeetingService { + +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/controller/MindmapController.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/controller/MindmapController.java index 10fedef..dc7cfd5 100644 --- a/src/main/java/com/teamEWSN/gitdeun/mindmap/controller/MindmapController.java +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/controller/MindmapController.java @@ -1,5 +1,8 @@ package com.teamEWSN.gitdeun.mindmap.controller; public class MindmapController { - + + + // TODO: 마인드맵 로딩 시 자동 확인 + 새로고침 시 재동기화 + } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/entity/Mindmap.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/entity/Mindmap.java index fa5027d..d26a8a3 100644 --- a/src/main/java/com/teamEWSN/gitdeun/mindmap/entity/Mindmap.java +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/entity/Mindmap.java @@ -1,5 +1,51 @@ package com.teamEWSN.gitdeun.mindmap.entity; -public class Mindmap { - +import com.teamEWSN.gitdeun.common.util.AuditedEntity; +import com.teamEWSN.gitdeun.repo.entity.Repo; +import com.teamEWSN.gitdeun.user.entity.User; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "Mindmap") +public class Mindmap extends AuditedEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "repo_id", nullable = false) + private Repo repo; + + // owner + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @Column(columnDefinition = "TEXT") + private String prompt; + + @Column(length = 100, nullable = false) + private String branch; + + @Enumerated(EnumType.STRING) + @Column(name = "type", nullable = false) + private MindmapType type; + + @Column(name = "Field", length = 255, nullable = false) + @ColumnDefault("'확인용 (n)'") + private String field; + + @JdbcTypeCode(SqlTypes.JSON) + @Column(name = "map_data", columnDefinition = "json", nullable = false) + private String mapData; + } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/entity/MindmapType.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/entity/MindmapType.java new file mode 100644 index 0000000..dfeefec --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/entity/MindmapType.java @@ -0,0 +1,6 @@ +package com.teamEWSN.gitdeun.mindmap.entity; + +public enum MindmapType { + DEV, + CHECK +} diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/mapper/MindmapMapper.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/mapper/MindmapMapper.java new file mode 100644 index 0000000..3b027ba --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/mapper/MindmapMapper.java @@ -0,0 +1,8 @@ +package com.teamEWSN.gitdeun.mindmap.mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface MindmapMapper { +} diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/repository/MindmapRepository.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/repository/MindmapRepository.java index d866bea..4e26d5f 100644 --- a/src/main/java/com/teamEWSN/gitdeun/mindmap/repository/MindmapRepository.java +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/repository/MindmapRepository.java @@ -1,5 +1,10 @@ package com.teamEWSN.gitdeun.mindmap.repository; -public class MindmapRepository { +import com.teamEWSN.gitdeun.mindmap.entity.Mindmap; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface MindmapRepository extends JpaRepository { } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmapedge/controller/MindmapEdgeController.java b/src/main/java/com/teamEWSN/gitdeun/mindmapedge/controller/MindmapEdgeController.java new file mode 100644 index 0000000..f9cc934 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/mindmapedge/controller/MindmapEdgeController.java @@ -0,0 +1,5 @@ +package com.teamEWSN.gitdeun.mindmapedge.controller; + +public class MindmapEdgeController { + +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmapedge/dto/MindmapEdgeDto.java b/src/main/java/com/teamEWSN/gitdeun/mindmapedge/dto/MindmapEdgeDto.java new file mode 100644 index 0000000..f7b9ab7 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/mindmapedge/dto/MindmapEdgeDto.java @@ -0,0 +1,5 @@ +package com.teamEWSN.gitdeun.mindmapedge.dto; + +public class MindmapEdgeDto { + +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmapedge/entity/EdgeType.java b/src/main/java/com/teamEWSN/gitdeun/mindmapedge/entity/EdgeType.java new file mode 100644 index 0000000..0807276 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/mindmapedge/entity/EdgeType.java @@ -0,0 +1,7 @@ +package com.teamEWSN.gitdeun.mindmapedge.entity; + +public enum EdgeType { + CROSS, + PARENT, + CHILD +} diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmapedge/entity/MindmapEdge.java b/src/main/java/com/teamEWSN/gitdeun/mindmapedge/entity/MindmapEdge.java new file mode 100644 index 0000000..17a8409 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/mindmapedge/entity/MindmapEdge.java @@ -0,0 +1,42 @@ +package com.teamEWSN.gitdeun.mindmapedge.entity; + +import com.teamEWSN.gitdeun.common.util.AuditedEntity; +import com.teamEWSN.gitdeun.mindmapnode.entity.MindmapNode; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.ColumnDefault; + +import java.math.BigDecimal; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "Mindmap_Edge") +public class MindmapEdge extends AuditedEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "from_node_id", nullable = false) + private MindmapNode fromNode; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "to_node_id", nullable = false) + private MindmapNode toNode; + + @Enumerated(EnumType.STRING) + @Column(name = "type", nullable = false) + private EdgeType type; + + @Column(nullable = false) + @ColumnDefault("0") + private BigDecimal strength; + + @Column(name = "arango_key") + private Long arangoKey; + +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmapedge/repository/MindmapEdgeRepository.java b/src/main/java/com/teamEWSN/gitdeun/mindmapedge/repository/MindmapEdgeRepository.java new file mode 100644 index 0000000..73abaf4 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/mindmapedge/repository/MindmapEdgeRepository.java @@ -0,0 +1,5 @@ +package com.teamEWSN.gitdeun.mindmapedge.repository; + +public class MindmapEdgeRepository { + +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmapedge/service/MindmapEdgeService.java b/src/main/java/com/teamEWSN/gitdeun/mindmapedge/service/MindmapEdgeService.java new file mode 100644 index 0000000..ab345d5 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/mindmapedge/service/MindmapEdgeService.java @@ -0,0 +1,5 @@ +package com.teamEWSN.gitdeun.mindmapedge.service; + +public class MindmapEdgeService { + +} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmapnode/entity/MindmapNode.java b/src/main/java/com/teamEWSN/gitdeun/mindmapnode/entity/MindmapNode.java index 40ae180..59b15c3 100644 --- a/src/main/java/com/teamEWSN/gitdeun/mindmapnode/entity/MindmapNode.java +++ b/src/main/java/com/teamEWSN/gitdeun/mindmapnode/entity/MindmapNode.java @@ -1,5 +1,41 @@ package com.teamEWSN.gitdeun.mindmapnode.entity; -public class MindmapNode { - +import com.teamEWSN.gitdeun.common.util.AuditedEntity; +import com.teamEWSN.gitdeun.mindmap.entity.Mindmap; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.ColumnDefault; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "Mindmap_Node") +public class MindmapNode extends AuditedEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mindmap_id", nullable = false) + private Mindmap mindmap; + + @Column(length = 100, nullable = false) + private String label; + + @Column(columnDefinition = "TEXT", nullable = false) + private String path; + + @Column(nullable = false) + @ColumnDefault("1") + private Integer depth; + + @Column(name = "arango_key", length = 64) + private String arangoKey; + + @Column(name = "Importance", nullable = false) + @ColumnDefault("0") + private Double importance; } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/repo/controller/RepoController.java b/src/main/java/com/teamEWSN/gitdeun/repo/controller/RepoController.java index b903ef3..6eb6968 100644 --- a/src/main/java/com/teamEWSN/gitdeun/repo/controller/RepoController.java +++ b/src/main/java/com/teamEWSN/gitdeun/repo/controller/RepoController.java @@ -1,5 +1,42 @@ package com.teamEWSN.gitdeun.repo.controller; +import com.teamEWSN.gitdeun.repo.dto.RepoResponseDto; +import com.teamEWSN.gitdeun.repo.dto.RepoUpdateCheckResponseDto; +import com.teamEWSN.gitdeun.repo.service.RepoService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/repos") public class RepoController { - + + private final RepoService repoService; + + // 리포지토리 URL을 통한 등록 확인 + @GetMapping("/check") + public ResponseEntity checkRepoExists(@RequestParam String url) { + RepoResponseDto response = repoService.findRepoByUrl(url); + return ResponseEntity.ok(response); + } + + // 리포지토리 정보 조회 + @GetMapping("/{repoId}") + public ResponseEntity getRepoInfo(@PathVariable Long repoId) { + RepoResponseDto response = repoService.findRepoById(repoId); + return ResponseEntity.ok(response); + } + + /** + * 특정 리포지토리에 대한 업데이트 필요 여부 확인 + */ + @GetMapping("/{repoId}/status") + public ResponseEntity getRepoUpdateStatus(@PathVariable Long repoId) { + RepoUpdateCheckResponseDto response = repoService.checkUpdateNeeded(repoId); + return ResponseEntity.ok(response); + } + + } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoDto.java b/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoDto.java deleted file mode 100644 index 9c8714f..0000000 --- a/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoDto.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.teamEWSN.gitdeun.repo.dto; - -public class RepoDto { - -} \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoResponseDto.java b/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoResponseDto.java new file mode 100644 index 0000000..218143c --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoResponseDto.java @@ -0,0 +1,23 @@ +package com.teamEWSN.gitdeun.repo.dto; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Builder +public class RepoResponseDto { + + private final Long repoId; + private final String githubRepoUrl; + private final String defaultBranch; + private final String language; + private final String description; + private final LocalDateTime githubLastUpdatedAt; + private final LocalDateTime lastSyncedAt; + + @Setter // Mapper의 @AfterMapping에서 이 값을 설정 + private boolean updateNeeded; // 재동기화 필요 여부 플래그 +} diff --git a/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoUpdateCheckResponseDto.java b/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoUpdateCheckResponseDto.java new file mode 100644 index 0000000..199cdd7 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoUpdateCheckResponseDto.java @@ -0,0 +1,11 @@ +package com.teamEWSN.gitdeun.repo.dto; + + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class RepoUpdateCheckResponseDto { + private final boolean updateNeeded; +} diff --git a/src/main/java/com/teamEWSN/gitdeun/repo/entity/Repo.java b/src/main/java/com/teamEWSN/gitdeun/repo/entity/Repo.java index c527d3f..8f0be06 100644 --- a/src/main/java/com/teamEWSN/gitdeun/repo/entity/Repo.java +++ b/src/main/java/com/teamEWSN/gitdeun/repo/entity/Repo.java @@ -1,5 +1,51 @@ package com.teamEWSN.gitdeun.repo.entity; +import com.teamEWSN.gitdeun.common.fastapi.dto.AnalysisResultDto; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "Repo") public class Repo { - + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "github_repo_url", length = 512, nullable = false, unique = true) + private String githubRepoUrl; + + @Column(name = "default_branch", length = 100) + private String defaultBranch; // 기본 브랜치 + + @Column(length = 50) + private String language; // 주요 언어 + + @Column(columnDefinition = "TEXT") + private String description; // 설명 + + @Column(name = "github_last_updated_at") + private LocalDateTime githubLastUpdatedAt; // GitHub 브랜치 최신 커밋 시간 (commit.committer.date) + + + @Builder + public Repo(String githubRepoUrl, String defaultBranch, String language, String description, LocalDateTime githubLastUpdatedAt) { + this.githubRepoUrl = githubRepoUrl; + this.defaultBranch = defaultBranch; + this.language = language; + this.description = description; + this.githubLastUpdatedAt = githubLastUpdatedAt; + } + + public void updateWithAnalysis(AnalysisResultDto result) { + this.language = result.getLanguage(); + this.description = result.getDescription(); + this.githubLastUpdatedAt = result.getGithubLastUpdatedAt(); + } } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/repo/mapper/RepoMapper.java b/src/main/java/com/teamEWSN/gitdeun/repo/mapper/RepoMapper.java new file mode 100644 index 0000000..fe6db82 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/repo/mapper/RepoMapper.java @@ -0,0 +1,13 @@ +package com.teamEWSN.gitdeun.repo.mapper; + +import com.teamEWSN.gitdeun.repo.dto.RepoResponseDto; +import com.teamEWSN.gitdeun.repo.entity.Repo; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface RepoMapper { + + RepoResponseDto toResponseDto(Repo repo); + +} diff --git a/src/main/java/com/teamEWSN/gitdeun/repo/repository/RepoRepository.java b/src/main/java/com/teamEWSN/gitdeun/repo/repository/RepoRepository.java index 7d3b49b..2d7ec47 100644 --- a/src/main/java/com/teamEWSN/gitdeun/repo/repository/RepoRepository.java +++ b/src/main/java/com/teamEWSN/gitdeun/repo/repository/RepoRepository.java @@ -1,5 +1,13 @@ package com.teamEWSN.gitdeun.repo.repository; -public class RepoRepository { - +import com.teamEWSN.gitdeun.repo.entity.Repo; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface RepoRepository extends JpaRepository { + + Optional findByGithubRepoUrl(String githubRepoUrl); } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/repo/service/RepoService.java b/src/main/java/com/teamEWSN/gitdeun/repo/service/RepoService.java index 9eaf262..544add6 100644 --- a/src/main/java/com/teamEWSN/gitdeun/repo/service/RepoService.java +++ b/src/main/java/com/teamEWSN/gitdeun/repo/service/RepoService.java @@ -1,5 +1,64 @@ package com.teamEWSN.gitdeun.repo.service; +import com.teamEWSN.gitdeun.common.fastapi.FastApiClient; +import com.teamEWSN.gitdeun.common.exception.ErrorCode; +import com.teamEWSN.gitdeun.common.exception.GlobalException; +import com.teamEWSN.gitdeun.repo.dto.RepoResponseDto; +import com.teamEWSN.gitdeun.repo.dto.RepoUpdateCheckResponseDto; +import com.teamEWSN.gitdeun.repo.entity.Repo; +import com.teamEWSN.gitdeun.repo.mapper.RepoMapper; +import com.teamEWSN.gitdeun.repo.repository.RepoRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) // 기본적으로는 읽기 전용, 데이터 변경 메서드에 @Transactional을 별도 추가 public class RepoService { - + + private final RepoRepository repoRepository; + private final RepoMapper repoMapper; + private final FastApiClient fastApiClient; + + /** + * Mapper를 통해 'updateNeeded' 플래그가 포함된 DTO를 반환합니다. + */ + public RepoResponseDto findRepoById(Long repoId) { + Repo repo = repoRepository.findById(repoId) + .orElseThrow(() -> new GlobalException(ErrorCode.REPO_NOT_FOUND_BY_ID)); + return repoMapper.toResponseDto(repo); + } + + /** + * 리포지토리 URL로 정보를 조회 + */ + public RepoResponseDto findRepoByUrl(String url) { + Repo repo = repoRepository.findByGithubRepoUrl(url) + .orElseThrow(() -> new GlobalException(ErrorCode.REPO_NOT_FOUND_BY_URL)); + return repoMapper.toResponseDto(repo); + } + + /** + * 리포지토리의 최신 업데이트 상태를 실시간으로 확인 + * @param repoId 확인할 리포지토리의 ID + * @return 업데이트 필요 여부를 담은 DTO + */ + public RepoUpdateCheckResponseDto checkUpdateNeeded(Long repoId) { + // 시스템의 마지막 동기화 시간 조회 + Repo repo = repoRepository.findById(repoId) + .orElseThrow(() -> new GlobalException(ErrorCode.REPO_NOT_FOUND_BY_ID)); + LocalDateTime lastSyncedAt = repo.getGithubLastUpdatedAt(); + + // FastAPI의 가벼운 API를 호출하여 GitHub의 최신 커밋 시간 조회 + LocalDateTime latestCommitAt = fastApiClient.fetchLatestCommitTime(repo.getGithubRepoUrl()); + + // 두 시간을 비교하여 업데이트 필요 여부 결정 + boolean isNeeded = latestCommitAt.isAfter(lastSyncedAt); + + return new RepoUpdateCheckResponseDto(isNeeded); + } + } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/user/controller/AuthController.java b/src/main/java/com/teamEWSN/gitdeun/user/controller/AuthController.java index acc86dd..2f8954a 100644 --- a/src/main/java/com/teamEWSN/gitdeun/user/controller/AuthController.java +++ b/src/main/java/com/teamEWSN/gitdeun/user/controller/AuthController.java @@ -3,7 +3,9 @@ import com.teamEWSN.gitdeun.common.cookie.CookieUtil; import com.teamEWSN.gitdeun.common.jwt.CustomUserDetails; import com.teamEWSN.gitdeun.common.jwt.JwtToken; +import com.teamEWSN.gitdeun.common.oauth.entity.OauthProvider; import com.teamEWSN.gitdeun.common.oauth.service.OAuthStateService; +import com.teamEWSN.gitdeun.common.oauth.service.SocialTokenRefreshService; import com.teamEWSN.gitdeun.user.dto.UserTokenResponseDto; import com.teamEWSN.gitdeun.user.service.AuthService; import jakarta.servlet.http.HttpServletResponse; @@ -26,6 +28,7 @@ public class AuthController { private Long refreshTokenExpired; private final OAuthStateService oAuthStateService; + private final SocialTokenRefreshService socialTokenRefreshService; private final AuthService authService; private final CookieUtil cookieUtil; @@ -66,30 +69,13 @@ public ResponseEntity refreshAccessToken( return ResponseEntity.ok(new UserTokenResponseDto(newJwtToken.getAccessToken())); } -// /** -// * GitHub의 모든 OAuth 콜백을 처리하는 단일 엔드포인트 -// * @param code GitHub에서 제공하는 Authorization Code -// * @param userDetails 현재 로그인된 사용자 정보. 비로그인 상태면 null. -// * @return 로그인 또는 계정 연동 흐름에 따라 적절한 경로로 포워딩 또는 리디렉션 -// */ -// @GetMapping("/github/callback") -// public ResponseEntity githubCallback( -// @RequestParam("code") String code, -// @AuthenticationPrincipal CustomUserDetails userDetails, -// HttpServletResponse response // 쿠키 설정을 위해 필요 -// ) { -// -// if (userDetails != null) { -// // "계정 연동" 흐름 -// authService.connectGithubAccount(userDetails.getId(), code); -// // 성공했다는 응답 전달 -// return ResponseEntity.ok().body(Map.of("status", "success", "message", "계정 연동 성공!")); -// -// } else { -// // "최초 로그인" 흐름 -// GithubLoginResponseDto loginResponse = authService.loginWithGithub(code, response); -// return ResponseEntity.ok(loginResponse); -// } -// } + // 외부 OAuth 재발급 (Access 만료 → provider 선택) + @PostMapping("/oauth/refresh/{provider}") + public ResponseEntity refreshSocial( + @AuthenticationPrincipal CustomUserDetails user, + @PathVariable OauthProvider provider) { + socialTokenRefreshService.refreshSocialToken(user.getId(), provider); + return ResponseEntity.noContent().build(); + } } diff --git a/src/main/java/com/teamEWSN/gitdeun/visithistory/entity/VisitHistory.java b/src/main/java/com/teamEWSN/gitdeun/visithistory/entity/VisitHistory.java index 68b7c40..3292b63 100644 --- a/src/main/java/com/teamEWSN/gitdeun/visithistory/entity/VisitHistory.java +++ b/src/main/java/com/teamEWSN/gitdeun/visithistory/entity/VisitHistory.java @@ -1,5 +1,36 @@ package com.teamEWSN.gitdeun.visithistory.entity; +import com.teamEWSN.gitdeun.mindmap.entity.Mindmap; +import com.teamEWSN.gitdeun.user.entity.User; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.ColumnDefault; + +import java.time.LocalDateTime; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "Visit_History") +@IdClass(VisitHistoryId.class) public class VisitHistory { - + + @Id + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @Id + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mindmap_id", nullable = false) + private Mindmap mindmap; + + @Column(name = "last_visited_at", nullable = false) + private LocalDateTime lastVisitedAt; + + @Column(nullable = false) + @ColumnDefault("false") + private boolean pinned; } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/visithistory/entity/VisitHistoryId.java b/src/main/java/com/teamEWSN/gitdeun/visithistory/entity/VisitHistoryId.java new file mode 100644 index 0000000..40b0755 --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/visithistory/entity/VisitHistoryId.java @@ -0,0 +1,13 @@ +package com.teamEWSN.gitdeun.visithistory.entity; + +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@NoArgsConstructor +@EqualsAndHashCode +public class VisitHistoryId implements Serializable { + private Long user; + private Long mindmap; +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 5f65fb5..8fa6f61 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -30,4 +30,7 @@ app: front-url: http://localhost:3000 cookie: secure: false - same-site: Lax \ No newline at end of file + same-site: Lax + +fastapi: + base-url: http://localhost:8000 # 내 PC에서 개발할 때의 주소 \ No newline at end of file diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index fbd1c5f..07c7b4e 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -28,4 +28,7 @@ app: front-url: https://gitdeun.site cookie: secure: true - same-site: None \ No newline at end of file + same-site: None + +fastapi: + base-url: http://fastapi-server:8000 # Docker 네트워크 내부에서 사용할 주소 \ No newline at end of file