Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ public enum GithubRepoException implements BaseException {
EXCEED_GITHUBREPO_EMAIL(HttpStatus.BAD_REQUEST, "이메일은 5개까지 등록할 수 있습니다"),
INVALID_GITHUBREPO_URL(HttpStatus.BAD_REQUEST, "잘못된 URL 입니다."),
INVALID_GITHUBREPO_EMAIL(HttpStatus.BAD_REQUEST, "잘못된 이메일 입니다"),
Comment on lines 16 to 18
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
EXCEED_GITHUBREPO_EMAIL(HttpStatus.BAD_REQUEST, "이메일은 5개까지 등록할 수 있습니다"),
INVALID_GITHUBREPO_URL(HttpStatus.BAD_REQUEST, "잘못된 URL 입니다."),
INVALID_GITHUBREPO_EMAIL(HttpStatus.BAD_REQUEST, "잘못된 이메일 입니다"),
EXCEED_GITHUB_REPO_EMAIL_LIMIT(HttpStatus.BAD_REQUEST, "이메일은 5개까지 등록할 수 있습니다"),
INVALID_GITHUB_REPO_URL(HttpStatus.BAD_REQUEST, "잘못된 URL 입니다."),
INVALID_GITHUB_REPO_EMAIL(HttpStatus.BAD_REQUEST, "잘못된 이메일 입니다"),
  • 코드 컨벤션에 예외명이 어긋나는 듯 보이는데 수정 부탁드립니다
  • 예외 상황을 좀 더 명확히 표현할 수 있도록 예외명을 변경하는 것이 어떨까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

컨벤션에 맞도록 수정하겠습니다!

INVALID_GITHUBREPO_DURATION(HttpStatus.NOT_FOUND, "종료일이 존재하지 않습니다");
INVALID_GITHUBREPO_DURATION(HttpStatus.NOT_FOUND, "종료일이 존재하지 않습니다"),
INVALID_GITHUBREPO_PAGE(HttpStatus.BAD_REQUEST, "페이지 번호가 없습니다.");

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,7 @@
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.exception.UserException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

Expand All @@ -15,6 +16,10 @@ public class GithubRepoQuery {

public GithubRepo findByUserIdAndRepositoryId(Long userId, Long repositoryId) {

if (userId == null) {
throw new GeneralException(UserException.USER_NOT_FOUND);
}
Comment on lines 17 to +21
Copy link
Collaborator

Choose a reason for hiding this comment

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

이 메서드를 이용할 때 userId는 무조건 설정되어 들어올 것으로 보이는데(인증/인가가 정상적으로 되었다면) 굳이 래퍼타입으로 다루는 이유가 있을까요? 래퍼 타입의 적절한 사용에 대해 고려해보시면 좋겠습니다.

Copy link
Member Author

Choose a reason for hiding this comment

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

현재 구조상 userId는 null이 될 가능성이 없다고 생각하기 때문에, 해당 부분을 기본형으로 바꾸거나 null 체크를 생략하는 것도 고려할 수 있겠습니다. 해당 논의를 바탕으로 코드의 의도를 좀 더 명확히 반영할 수 있도록 개선해보겠습니다.


GithubRepo githubRepo = githubRepoRepository.findById(repositoryId).orElseThrow(() ->
new GeneralException(GithubRepoException.NOT_FOUND_GITHUBREPO)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,19 @@ public GithubRepoGetResponse getGithubRepoInfo(Long userId, Long repoId) {
@Transactional(readOnly = true)
public GithubRepoPageResponse getGithubRepoInfos(Long userId, int page) {

if (page < 0) {
throw new GeneralException(GithubRepoException.INVALID_GITHUBREPO_PAGE);
}
Comment on lines 141 to +146
Copy link
Collaborator

Choose a reason for hiding this comment

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

  • userId를 래퍼 타입으로 다루는 이유가 있을까요? 래퍼 타입의 적절한 사용에 대해 고려해보시면 좋겠습니다
  • page의 범위를 확인하는 검증같은 기본 검증을 service가 아닌 controller에서 다루는 것은 어떨까요? 검증 코드으로 인해 비즈니스 로직이 수행하는 핵심 작업 이상으로 비대해지는 경향이 있어보입니다. 검토 부탁드립니다

Copy link
Member Author

Choose a reason for hiding this comment

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

말씀하신 것처럼, 컨트롤러에서 입력값을 사전에 검증하고 핵심 비즈니스 로직은 Service에서만 담당하도록 분리하는 것이 코드의 역할을 명확히 하고 가독성을 높이는 데 더 적절할 것 같습니다.

이 부분은 Controller 단에서 @RequestParam에 대한 validation을 추가하는 방식으로 개선하는 방향을 검토해보겠습니다.


Pageable pageable = PageRequest.of(page, PAGE_SIZE);
Page<GithubRepo> resultPage = githubRepoRepository.findGithubRepoPages(userId,
pageable);

int totalPages = resultPage.getTotalPages();
if (page >= totalPages) {
throw new GeneralException(GithubRepoException.INVALID_GITHUBREPO_PAGE);
}

return githubRepoMapper.toGithubRepoPageResponse(resultPage, userId);
}

Expand Down
94 changes: 65 additions & 29 deletions src/main/resources/templates/main/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
font-family: sans-serif;
display: flex;
justify-content: center;
align-items: flex-start; /* 상단 정렬로 변경 */
padding: 3rem 0; /* 위아래 여유 */
align-items: flex-start;
padding: 3rem 0;
}

.mypage-button {
Expand All @@ -21,7 +21,7 @@
top: 2rem;
width: 70px;
height: 70px;
border-radius: 50%; /* 완전한 원형 */
border-radius: 50%;
border: 1px solid #aaa;
background-color: white;
font-size: 12px;
Expand Down Expand Up @@ -81,75 +81,89 @@

.container {
width: 700px;
min-height: 500px; /* 최소 높이만 보장 */
min-height: 500px;
background-color: white;
padding: 3rem;
border-radius: 16px;
box-shadow: 0 0 12px rgba(0, 0, 0, 0.05);
position: relative;
box-sizing: border-box;

display: flex;
flex-direction: column;
padding-bottom: 3rem; /* footer용 여유 공간 */
padding-bottom: 3rem;
}

.footer {
margin-top: 3rem;
width: 100%;
display: flex;
justify-content: flex-end; /* 오른쪽 정렬 먼저 하고 */
justify-content: flex-end;
position: relative;
}

.footer .add-button, .footer .logout-button {
padding: 0.6rem 1.2rem;
border-radius: 8px;
font-size: 14px;
cursor: pointer;
background-color: white;
}

.footer .add-button {
position: absolute;
left: 50%;
transform: translateX(-50%);
border: 1px solid #333;
color: #333;
background-color: white;
padding: 0.6rem 1.2rem;
border-radius: 8px;
font-size: 14px;
cursor: pointer;
}

.footer .logout-button {
border: 1px solid #c0392b;
color: #c0392b;
background-color: white;
padding: 0.6rem 1.2rem;
border-radius: 8px;
font-size: 14px;
cursor: pointer;
}

.footer .add-button, .footer .logout-button {
padding: 0.6rem 1.2rem;
border-radius: 8px;
a.repo-link {
text-decoration: none;
color: inherit;
}

.pagination {
text-align: center;
margin-top: 2rem;
}

.pagination a, .pagination button {
margin: 0 4px;
padding: 6px 10px;
font-size: 14px;
cursor: pointer;
border: 1px solid #ccc;
background-color: white;
color: #333;
border-radius: 5px;
text-decoration: none;
cursor: pointer;
}

a.repo-link {
text-decoration: none;
color: inherit;
.pagination .active a {
background-color: #333;
color: white;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container">
<button class="mypage-button" onclick="location.href='/mypage'">마이페이지</button>

<!-- 📌 레포지토리 목록이 존재할 때 -->
<!-- 레포지토리 목록 -->
<div th:if="${repositories != null}" class="repo-list">
<div class="repo-item" th:each="repository : ${repositories.repositoryId}">
<a th:href="@{|/users/repositories/${repository.id}|}" class="repo-link">
<div class="repo-title" th:text="${repository.name}">레포지토리 이름</div>
<div class="repo-url" th:text="${repository.url}">https://repo1.com</div>
<div class="repo-time">10 min</div>
<div class="repo-time" th:text="${#temporals.format(repository.endDate, 'yyyy-MM-dd')}">
종료일
</div>
</a>
<form th:action="@{|/users/repositories/${repository.id}|}" method="post"
onsubmit="return confirm('정말 레포지토리를 삭제하시겠습니까?');">
Expand All @@ -159,15 +173,38 @@
</div>
</div>

<!-- 레포지토리가 없을 때 -->
<div th:if="${#lists.isEmpty(repositories.repositoryId)}" class="no-repo">
등록된 레포지토리가 없습니다!
</div>

<!-- 페이지네이션 -->
<div class="pagination" th:if="${repositories.totalPages > 1}">
<!-- 이전 버튼 -->
<button th:if="${repositories.currentPage > 0}"
th:onclick="'location.href=\'?page=' + ${repositories.currentPage - 1} + '\''">
이전
</button>

<!-- 페이지 숫자 -->
<span th:each="i : ${#numbers.sequence(0, repositories.totalPages - 1)}"
th:classappend="${i == repositories.currentPage} ? 'active' : ''">
<a th:href="@{'/users/repositories'(page=${i})}"
th:text="${i + 1}"></a>
</span>

<!-- 다음 버튼 -->
<button th:if="${repositories.currentPage < repositories.totalPages - 1}"
th:onclick="'location.href=\'?page=' + ${repositories.currentPage + 1} + '\''">
다음
</button>
</div>

<!-- 하단 버튼 -->
<div class="footer">
<form th:action="@{'/users/repositories/new'}" method="get">
<button class="add-button" type="submit">리포지토리 추가하기</button>
</form>

<form th:action="@{/logout}" method="post" onsubmit="return confirmLogout();">
<button type="submit" class="logout-button">로그아웃</button>
</form>
Expand All @@ -183,7 +220,6 @@
return false;
}
</script>

</div>
</body>
</html>
</html>
Loading