Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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 @@ -28,7 +28,7 @@

import static konkuk.thip.book.adapter.out.api.naver.NaverApiUtil.PAGE_SIZE;
import static konkuk.thip.common.exception.code.ErrorCode.*;
import static konkuk.thip.recentSearch.adapter.out.jpa.SearchType.BOOK_SEARCH;
import static konkuk.thip.recentSearch.adapter.out.jpa.RecentSearchType.BOOK_SEARCH;

@Service
@RequiredArgsConstructor
Expand Down Expand Up @@ -69,7 +69,7 @@ public NaverBookParseResult searchBooks(String keyword, int page, Long userId) {
//최근검색어 추가
RecentSearch recentSearch = RecentSearch.builder()
.searchTerm(keyword)
.type(BOOK_SEARCH.getSearchType())
.type(BOOK_SEARCH)
.userId(userId)
.build();
recentSearchCommandPort.save(recentSearch);
Expand Down
9 changes: 0 additions & 9 deletions src/main/java/konkuk/thip/common/entity/BaseDomainEntity.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package konkuk.thip.common.entity;

import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

import java.time.LocalDateTime;
Expand All @@ -10,18 +9,10 @@
@SuperBuilder
public class BaseDomainEntity {

@Setter
private LocalDateTime createdAt;

private LocalDateTime modifiedAt;

private StatusType status;

protected void changeStatus() {
if (this.status == StatusType.ACTIVE) {
this.status = StatusType.INACTIVE;
} else {
this.status = StatusType.ACTIVE;
}
}
}
9 changes: 0 additions & 9 deletions src/main/java/konkuk/thip/common/entity/BaseJpaEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.google.common.annotations.VisibleForTesting;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
Expand All @@ -27,21 +25,14 @@ public abstract class BaseJpaEntity {
@Column(name = "created_at",nullable = false, updatable = false)
private LocalDateTime createdAt;

@Setter
@LastModifiedDate
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonSerialize(using = LocalDateSerializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@Column(name = "modified_at",nullable = false)
private LocalDateTime modifiedAt;

@Setter
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private StatusType status = StatusType.ACTIVE;

@VisibleForTesting
protected void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public enum ErrorCode implements ResponseCode {
*/
INVALID_SEARCH_TYPE(HttpStatus.BAD_REQUEST, 90000,"알맞은 검색어 타입을 찾을 수 없습니다."),
RECENT_SEARCH_NOT_FOUND(HttpStatus.NOT_FOUND, 90001, "존재하지 않는 RECENT SEARCH 입니다."),
RECENT_SEARCH_NOT_ADDED_BY_USER(HttpStatus.BAD_REQUEST, 90002, "사용자가 추가하지 않은 검색어는 삭제할 수 없습니다."),

/**
* 100000 : room error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ public enum SwaggerResponseDescription {
JSON_PROCESSING_ERROR
))),

// Recent Search
RECENT_SEARCH_DELETE(new LinkedHashSet<>(Set.of(
RECENT_SEARCH_NOT_FOUND,
RECENT_SEARCH_NOT_ADDED_BY_USER
))),

;
private final Set<ErrorCode> errorCodeList;
SwaggerResponseDescription(Set<ErrorCode> errorCodeList) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

package konkuk.thip.feed.adapter.out.jpa;

import com.google.common.annotations.VisibleForTesting;
import jakarta.persistence.*;
import konkuk.thip.book.adapter.out.jpa.BookJpaEntity;
import konkuk.thip.feed.domain.Feed;
Expand All @@ -12,7 +11,6 @@
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.List;

@Entity
Expand Down Expand Up @@ -51,9 +49,4 @@ public void updateFrom(Feed feed) {
this.likeCount = feed.getLikeCount();
this.commentCount = feed.getCommentCount();
}

@VisibleForTesting
public void setCreatedAt(LocalDateTime newCreatedAt) {
super.setCreatedAt(newCreatedAt);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,33 @@
package konkuk.thip.recentSearch.adapter.in.web;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import konkuk.thip.common.dto.BaseResponse;
import konkuk.thip.common.security.annotation.UserId;
import konkuk.thip.common.swagger.annotation.ExceptionDescription;
import konkuk.thip.recentSearch.application.port.in.RecentSearchDeleteUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import static konkuk.thip.common.swagger.SwaggerResponseDescription.RECENT_SEARCH_DELETE;

@Tag(name = "Recent Search Command API", description = "최근 검색어 상태 변경 관련 API")
@RestController
@RequiredArgsConstructor
public class RecentSearchCommandController {

private final RecentSearchDeleteUseCase recentSearchDeleteUseCase;

@Operation(summary = "최근 검색어 삭제", description = "최근 검색어를 삭제합니다.")
@ExceptionDescription(RECENT_SEARCH_DELETE)
@DeleteMapping("/recent-searches/{recentSearchId}")
public BaseResponse<Void> deleteRecentSearch(
@PathVariable(value = "recentSearchId") final Long recentSearchId,
@UserId final Long userId
) {
return BaseResponse.ok(recentSearchDeleteUseCase.deleteRecentSearch(recentSearchId, userId));
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
package konkuk.thip.recentSearch.adapter.in.web;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import konkuk.thip.common.dto.BaseResponse;
import konkuk.thip.common.security.annotation.UserId;
import konkuk.thip.recentSearch.adapter.in.web.response.RecentSearchGetResponse;
import konkuk.thip.recentSearch.application.port.in.RecentSearchGetUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "Recent Search Query API", description = "최근 검색어 조회 관련 API")
@RestController
@RequiredArgsConstructor
public class RecentSearchQueryController {

private final RecentSearchGetUseCase recentSearchGetUseCase;

@Operation(summary = "최근 검색어 조회", description = "사용자의 최근 검색어를 조회합니다. 최신순으로 최대 5개까지 조회됩니다.")
@GetMapping("/recent-searches")
public BaseResponse<RecentSearchGetResponse> showRecentSearches(
@Parameter(description = "최근 검색어 유형 (사용자 검색 : USER / 방 검색 : ROOM / 책 검색 : BOOK)", example = "USER")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@RequestParam(value = "type") String type,
@Parameter(hidden = true) @UserId final Long userId
) {
return BaseResponse.ok(recentSearchGetUseCase.getRecentSearches(type, userId));
}
Comment on lines +24 to +30
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

타입 파라미터에 대한 검증이 필요합니다.

type 파라미터에 대한 검증이 없어 잘못된 값이 전달될 수 있습니다. RecentSearchType enum의 유효한 값들로만 제한하는 것이 좋겠습니다.

다음과 같이 검증을 추가하는 것을 제안합니다:

@GetMapping("/recent-searches")
public BaseResponse<RecentSearchGetResponse> showRecentSearches(
        @Parameter(description = "최근 검색어 유형 (사용자 검색 : USER / 방 검색 : ROOM / 책 검색 : BOOK)", example = "USER")
-       @RequestParam(value = "type") String type,
+       @RequestParam(value = "type") @Pattern(regexp = "^(USER|ROOM|BOOK)$", message = "유효하지 않은 검색 타입입니다") String type,
        @Parameter(hidden = true) @UserId final Long userId
) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public BaseResponse<RecentSearchGetResponse> showRecentSearches(
@Parameter(description = "최근 검색어 유형 (사용자 검색 : USER / 방 검색 : ROOM / 책 검색 : BOOK)", example = "USER")
@RequestParam(value = "type") String type,
@Parameter(hidden = true) @UserId final Long userId
) {
return BaseResponse.ok(recentSearchGetUseCase.getRecentSearches(type, userId));
}
@GetMapping("/recent-searches")
public BaseResponse<RecentSearchGetResponse> showRecentSearches(
@Parameter(description = "최근 검색어 유형 (사용자 검색 : USER / 방 검색 : ROOM / 책 검색 : BOOK)", example = "USER")
@RequestParam(value = "type")
@Pattern(regexp = "^(USER|ROOM|BOOK)$", message = "유효하지 않은 검색 타입입니다")
String type,
@Parameter(hidden = true) @UserId final Long userId
) {
return BaseResponse.ok(recentSearchGetUseCase.getRecentSearches(type, userId));
}
🤖 Prompt for AI Agents
In
src/main/java/konkuk/thip/recentSearch/adapter/in/web/RecentSearchQueryController.java
around lines 24 to 30, the 'type' request parameter lacks validation and can
accept invalid values. To fix this, validate the 'type' parameter against the
RecentSearchType enum by converting the input string to the enum and handling
invalid values appropriately, such as throwing an exception or returning a bad
request response. This ensures only valid enum values are processed.


}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package konkuk.thip.recentSearch.adapter.in.web.response;

import java.util.List;

public record RecentSearchGetResponse(
List<RecentSearchDto> recentSearchList
) {

public record RecentSearchDto(
Long recentSearchId,
String searchTerm
) {
}
public static RecentSearchGetResponse of(List<RecentSearchDto> recentSearchList) {
return new RecentSearchGetResponse(recentSearchList);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import jakarta.persistence.*;
import konkuk.thip.common.entity.BaseJpaEntity;
import konkuk.thip.recentSearch.domain.RecentSearch;
import konkuk.thip.user.adapter.out.jpa.UserJpaEntity;
import lombok.*;

Expand All @@ -25,15 +24,9 @@ public class RecentSearchJpaEntity extends BaseJpaEntity {

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private SearchType type;
private RecentSearchType type;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

RecentSearchType 임포트 누락으로 컴파일 에러 발생.

RecentSearchType 열거형을 사용하고 있지만 해당 클래스의 임포트 구문이 누락되어 컴파일 에러가 발생합니다.

다음 임포트를 추가해 주세요:

package konkuk.thip.recentSearch.adapter.out.jpa;

import jakarta.persistence.*;
import konkuk.thip.common.entity.BaseJpaEntity;
+import konkuk.thip.recentSearch.domain.RecentSearchType;
import konkuk.thip.user.adapter.out.jpa.UserJpaEntity;
import lombok.*;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private RecentSearchType type;
package konkuk.thip.recentSearch.adapter.out.jpa;
import jakarta.persistence.*;
import konkuk.thip.common.entity.BaseJpaEntity;
import konkuk.thip.recentSearch.domain.RecentSearchType;
import konkuk.thip.user.adapter.out.jpa.UserJpaEntity;
import lombok.*;
🤖 Prompt for AI Agents
In
src/main/java/konkuk/thip/recentSearch/adapter/out/jpa/RecentSearchJpaEntity.java
at line 27, the RecentSearchType enum is used but not imported, causing a
compilation error. Add the appropriate import statement for RecentSearchType at
the top of the file to resolve the missing import issue.


@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private UserJpaEntity userJpaEntity;

public void updateFrom(RecentSearch recentSearch) {
this.searchTerm = recentSearch.getSearchTerm();
this.type = SearchType.from(recentSearch.getType());
this.setCreatedAt(recentSearch.getCreatedAt());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package konkuk.thip.recentSearch.adapter.out.jpa;


import konkuk.thip.common.exception.InvalidStateException;
import lombok.Getter;

import static konkuk.thip.common.exception.code.ErrorCode.INVALID_SEARCH_TYPE;

@Getter
public enum RecentSearchType {

USER_SEARCH("USER"),
BOOK_SEARCH("BOOK"),
ROOM_SEARCH("ROOM"),
;

private final String searchType;

RecentSearchType(String searchType) {
this.searchType = searchType;
}

public static RecentSearchType from(String searchType) {
for (RecentSearchType type : RecentSearchType.values()) {
if (type.getSearchType().equals(searchType)) {
return type;
}
}
throw new InvalidStateException(INVALID_SEARCH_TYPE);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package konkuk.thip.recentSearch.adapter.out.mapper;

import konkuk.thip.recentSearch.adapter.out.jpa.RecentSearchJpaEntity;
import konkuk.thip.recentSearch.adapter.out.jpa.SearchType;
import konkuk.thip.recentSearch.domain.RecentSearch;
import konkuk.thip.user.adapter.out.jpa.UserJpaEntity;
import org.springframework.stereotype.Component;
Expand All @@ -12,7 +11,7 @@ public class RecentSearchMapper {
public RecentSearchJpaEntity toJpaEntity(RecentSearch recentSearch, UserJpaEntity userJpaEntity) {
return RecentSearchJpaEntity.builder()
.searchTerm(recentSearch.getSearchTerm())
.type(SearchType.from(recentSearch.getType()))
.type(recentSearch.getType())
.userJpaEntity(userJpaEntity)
.build();
}
Expand All @@ -21,7 +20,7 @@ public RecentSearch toDomainEntity(RecentSearchJpaEntity recentSearchJpaEntity)
return RecentSearch.builder()
.id(recentSearchJpaEntity.getRecentSearchId())
.searchTerm(recentSearchJpaEntity.getSearchTerm())
.type(recentSearchJpaEntity.getType().getSearchType())
.type(recentSearchJpaEntity.getType())
.userId(recentSearchJpaEntity.getUserJpaEntity().getUserId())
.createdAt(recentSearchJpaEntity.getCreatedAt())
.modifiedAt(recentSearchJpaEntity.getModifiedAt())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.Optional;

import static konkuk.thip.common.exception.code.ErrorCode.RECENT_SEARCH_NOT_FOUND;
import static konkuk.thip.common.exception.code.ErrorCode.USER_NOT_FOUND;

Expand All @@ -23,6 +25,12 @@ public class RecentSearchCommandPersistenceAdapter implements RecentSearchComman

private final RecentSearchMapper recentSearchMapper;

@Override
public Optional<RecentSearch> findById(Long id) {
return recentSearchJpaRepository.findById(id)
.map(recentSearchMapper::toDomainEntity);
}

@Override
public void save(RecentSearch recentSearch) {

Expand All @@ -44,11 +52,9 @@ public void delete(Long id) {
}

@Override
public void update(RecentSearch recentSearch) {
RecentSearchJpaEntity recentSearchJpaEntity = recentSearchJpaRepository.findById(recentSearch.getId())
.orElseThrow(() -> new EntityNotFoundException(RECENT_SEARCH_NOT_FOUND));

recentSearchJpaEntity.updateFrom(recentSearch);
recentSearchJpaRepository.save(recentSearchJpaEntity);
public void touch(RecentSearch recentSearch) {
recentSearchJpaRepository.updateModifiedAt(recentSearch.getId());
}


}
Loading