Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -2,15 +2,24 @@

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import redot.redot_server.domain.admin.controller.docs.AdminRedotAppControllerDocs;
import redot.redot_server.domain.admin.dto.request.RedotAppInfoSearchCondition;
import redot.redot_server.domain.admin.dto.request.RedotAppStatusUpdateRequest;
import redot.redot_server.domain.admin.service.AdminRedotAppService;
import redot.redot_server.domain.redot.app.dto.request.RedotAppCreateRequest;
import redot.redot_server.domain.redot.app.dto.response.RedotAppInfoResponse;
import redot.redot_server.global.util.dto.response.PageResponse;

@RestController
@RequestMapping("/api/v1/redot/admin/app")
Expand All @@ -24,4 +33,27 @@ public class AdminRedotAppController implements AdminRedotAppControllerDocs {
public ResponseEntity<RedotAppInfoResponse> createRedotApp(@Valid @RequestBody RedotAppCreateRequest request) {
return ResponseEntity.ok(redotAppService.createRedotApp(request));
}

@GetMapping
@Override
public ResponseEntity<PageResponse<RedotAppInfoResponse>> getRedotAppInfoList(
@ParameterObject RedotAppInfoSearchCondition searchCondition,
@ParameterObject @PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) {
return ResponseEntity.ok(redotAppService.getRedotAppInfoList(searchCondition, pageable));
}

@GetMapping("/{redotAppId}")
@Override
public ResponseEntity<RedotAppInfoResponse> getRedotAppInfo(
@PathVariable("redotAppId") Long redotAppId) {
return ResponseEntity.ok(redotAppService.getRedotAppInfo(redotAppId));
}

@PostMapping("/{redotAppId}/status")
@Override
public ResponseEntity<RedotAppInfoResponse> updateRedotAppStatus(
@PathVariable("redotAppId") Long redotAppId,
@Valid @RequestBody RedotAppStatusUpdateRequest request) {
return ResponseEntity.ok(redotAppService.updateRedotAppStatus(redotAppId, request));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import redot.redot_server.domain.admin.dto.request.RedotAppInfoSearchCondition;
import redot.redot_server.domain.admin.dto.request.RedotAppStatusUpdateRequest;
import redot.redot_server.domain.redot.app.dto.request.RedotAppCreateRequest;
import redot.redot_server.domain.redot.app.dto.response.RedotAppInfoResponse;
import redot.redot_server.global.util.dto.response.PageResponse;

@Tag(name = "Admin Redot App", description = "관리자 앱 관리 API")
public interface AdminRedotAppControllerDocs {
Expand All @@ -17,4 +22,24 @@ public interface AdminRedotAppControllerDocs {
@ApiResponse(responseCode = "200", description = "생성 성공",
content = @Content(schema = @Schema(implementation = RedotAppInfoResponse.class)))
ResponseEntity<RedotAppInfoResponse> createRedotApp(@Valid RedotAppCreateRequest request);

@Operation(summary = "앱 목록 조회", description = "status, name, redot_member_id 파라미터로 필터링하며 createdAt 기준 최신순 정렬을 기본으로 제공합니다.")
@ApiResponse(responseCode = "200", description = "조회 성공",
content = @Content(schema = @Schema(implementation = PageResponse.class)))
ResponseEntity<PageResponse<RedotAppInfoResponse>> getRedotAppInfoList(
@ParameterObject RedotAppInfoSearchCondition searchCondition,
@ParameterObject Pageable pageable);

@Operation(summary = "앱 단건 조회", description = "redotAppId로 특정 앱 정보를 조회합니다.")
@ApiResponse(responseCode = "200", description = "조회 성공",
content = @Content(schema = @Schema(implementation = RedotAppInfoResponse.class)))
ResponseEntity<RedotAppInfoResponse> getRedotAppInfo(
@io.swagger.v3.oas.annotations.Parameter(description = "Redot 앱 ID", example = "1") Long redotAppId);

@Operation(summary = "앱 상태 변경", description = "지정한 앱의 상태 및 비고(remark)를 수정합니다.")
@ApiResponse(responseCode = "200", description = "수정 성공",
content = @Content(schema = @Schema(implementation = RedotAppInfoResponse.class)))
ResponseEntity<RedotAppInfoResponse> updateRedotAppStatus(
@io.swagger.v3.oas.annotations.Parameter(description = "Redot 앱 ID", example = "1") Long redotAppId,
@Valid RedotAppStatusUpdateRequest request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package redot.redot_server.domain.admin.dto.request;

import redot.redot_server.domain.redot.app.entity.RedotAppStatus;

public record RedotAppInfoSearchCondition(
String name,
Long redotMemberId,
RedotAppStatus status
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package redot.redot_server.domain.admin.dto.request;

import jakarta.validation.constraints.NotNull;
import redot.redot_server.domain.redot.app.entity.RedotAppStatus;

public record RedotAppStatusUpdateRequest(
@NotNull(message = "status 는 필수입니다.") RedotAppStatus status,
String remark
) {
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,128 @@
package redot.redot_server.domain.admin.service;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import redot.redot_server.domain.admin.dto.request.RedotAppInfoSearchCondition;
import redot.redot_server.domain.admin.dto.request.RedotAppStatusUpdateRequest;
import redot.redot_server.domain.cms.site.setting.dto.response.SiteSettingResponse;
import redot.redot_server.domain.cms.site.style.dto.response.StyleInfoResponse;
import redot.redot_server.domain.redot.app.dto.request.RedotAppCreateRequest;
import redot.redot_server.domain.redot.app.dto.response.RedotAppInfoResponse;
import redot.redot_server.domain.redot.app.dto.response.RedotAppResponse;
import redot.redot_server.domain.redot.app.entity.RedotApp;
import redot.redot_server.domain.redot.app.exception.RedotAppErrorCode;
import redot.redot_server.domain.redot.app.exception.RedotAppException;
import redot.redot_server.domain.redot.app.repository.RedotAppRepository;
import redot.redot_server.domain.redot.app.service.RedotAppCreationService;
import redot.redot_server.domain.redot.member.dto.response.RedotMemberResponse;
import redot.redot_server.domain.site.domain.entity.Domain;
import redot.redot_server.domain.site.domain.repository.DomainRepository;
import redot.redot_server.domain.site.setting.entity.SiteSetting;
import redot.redot_server.domain.site.setting.repository.SiteSettingRepository;
import redot.redot_server.domain.site.style.entity.StyleInfo;
import redot.redot_server.domain.site.style.repository.StyleInfoRepository;
import redot.redot_server.global.s3.util.ImageUrlResolver;
import redot.redot_server.global.util.dto.response.PageResponse;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AdminRedotAppService {
private final RedotAppCreationService redotAppCreationService;
private final RedotAppRepository redotAppRepository;
private final DomainRepository domainRepository;
private final SiteSettingRepository siteSettingRepository;
private final StyleInfoRepository styleInfoRepository;
private final ImageUrlResolver imageUrlResolver;

@Transactional
public RedotAppInfoResponse createRedotApp(RedotAppCreateRequest request) {
return redotAppCreationService.createWithoutOwner(request);
}

public PageResponse<RedotAppInfoResponse> getRedotAppInfoList(RedotAppInfoSearchCondition searchCondition,
Pageable pageable) {
Page<RedotApp> redotApps = redotAppRepository.findAllBySearchCondition(searchCondition, pageable);

List<Long> redotAppIds = redotApps.stream()
.map(RedotApp::getId)
.toList();

Map<Long, Domain> domainMap = redotAppIds.isEmpty() ? Map.of()
: domainRepository.findByRedotAppIdIn(redotAppIds)
.stream()
.collect(Collectors.toMap(domain -> domain.getRedotApp().getId(), Function.identity()));

Map<Long, StyleInfo> styleInfoMap = redotAppIds.isEmpty() ? Map.of()
: styleInfoRepository.findByRedotApp_IdIn(redotAppIds)
.stream()
.collect(Collectors.toMap(style -> style.getRedotApp().getId(), Function.identity()));

Map<Long, SiteSetting> siteSettingMap = redotAppIds.isEmpty() ? Map.of()
: siteSettingRepository.findByRedotAppIdIn(redotAppIds)
.stream()
.collect(Collectors.toMap(setting -> setting.getRedotApp().getId(), Function.identity()));
Comment on lines +58 to +71
Copy link

@coderabbitai coderabbitai bot Dec 17, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

중복 키 발생 시 예외 처리 필요

Collectors.toMap에 merge function이 없어 하나의 RedotApp에 여러 Domain/StyleInfo/SiteSetting이 존재할 경우 IllegalStateException이 발생합니다. 또한 getRedotApp()이 null을 반환하면 NPE가 발생할 수 있습니다.

다음 diff를 적용하여 중복 키와 null 처리를 개선하세요:

 Map<Long, Domain> domainMap = redotAppIds.isEmpty() ? Map.of()
         : domainRepository.findByRedotAppIdIn(redotAppIds)
         .stream()
+        .filter(domain -> domain.getRedotApp() != null)
-        .collect(Collectors.toMap(domain -> domain.getRedotApp().getId(), Function.identity()));
+        .collect(Collectors.toMap(
+                domain -> domain.getRedotApp().getId(),
+                Function.identity(),
+                (existing, replacement) -> existing));

 Map<Long, StyleInfo> styleInfoMap = redotAppIds.isEmpty() ? Map.of()
         : styleInfoRepository.findByRedotApp_IdIn(redotAppIds)
         .stream()
+        .filter(style -> style.getRedotApp() != null)
-        .collect(Collectors.toMap(style -> style.getRedotApp().getId(), Function.identity()));
+        .collect(Collectors.toMap(
+                style -> style.getRedotApp().getId(),
+                Function.identity(),
+                (existing, replacement) -> existing));

 Map<Long, SiteSetting> siteSettingMap = redotAppIds.isEmpty() ? Map.of()
         : siteSettingRepository.findByRedotAppIdIn(redotAppIds)
         .stream()
+        .filter(setting -> setting.getRedotApp() != null)
-        .collect(Collectors.toMap(setting -> setting.getRedotApp().getId(), Function.identity()));
+        .collect(Collectors.toMap(
+                setting -> setting.getRedotApp().getId(),
+                Function.identity(),
+                (existing, replacement) -> existing));
📝 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
Map<Long, Domain> domainMap = redotAppIds.isEmpty() ? Map.of()
: domainRepository.findByRedotAppIdIn(redotAppIds)
.stream()
.collect(Collectors.toMap(domain -> domain.getRedotApp().getId(), Function.identity()));
Map<Long, StyleInfo> styleInfoMap = redotAppIds.isEmpty() ? Map.of()
: styleInfoRepository.findByRedotApp_IdIn(redotAppIds)
.stream()
.collect(Collectors.toMap(style -> style.getRedotApp().getId(), Function.identity()));
Map<Long, SiteSetting> siteSettingMap = redotAppIds.isEmpty() ? Map.of()
: siteSettingRepository.findByRedotAppIdIn(redotAppIds)
.stream()
.collect(Collectors.toMap(setting -> setting.getRedotApp().getId(), Function.identity()));
Map<Long, Domain> domainMap = redotAppIds.isEmpty() ? Map.of()
: domainRepository.findByRedotAppIdIn(redotAppIds)
.stream()
.filter(domain -> domain.getRedotApp() != null)
.collect(Collectors.toMap(
domain -> domain.getRedotApp().getId(),
Function.identity(),
(existing, replacement) -> existing));
Map<Long, StyleInfo> styleInfoMap = redotAppIds.isEmpty() ? Map.of()
: styleInfoRepository.findByRedotApp_IdIn(redotAppIds)
.stream()
.filter(style -> style.getRedotApp() != null)
.collect(Collectors.toMap(
style -> style.getRedotApp().getId(),
Function.identity(),
(existing, replacement) -> existing));
Map<Long, SiteSetting> siteSettingMap = redotAppIds.isEmpty() ? Map.of()
: siteSettingRepository.findByRedotAppIdIn(redotAppIds)
.stream()
.filter(setting -> setting.getRedotApp() != null)
.collect(Collectors.toMap(
setting -> setting.getRedotApp().getId(),
Function.identity(),
(existing, replacement) -> existing));
🤖 Prompt for AI Agents
In
src/main/java/redot/redot_server/domain/admin/service/AdminRedotAppService.java
around lines 58 to 71, the three Collectors.toMap calls can throw
IllegalStateException on duplicate keys and NPE if getRedotApp() returns null;
update each stream to filter out entries with null getRedotApp() (or null
getRedotApp().getId()) before collecting and supply a merge function to
Collectors.toMap to resolve duplicate keys (for example, choose the first or
last occurrence consistently), ensuring no NPE and no duplicate-key exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

한개의 앱에는 하나의 domain, styleinfo, sitesetting만 존재해요.

Copy link

Choose a reason for hiding this comment

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

@eraser502 이해했습니다! 1:1 관계라면 중복 키 문제는 발생하지 않겠네요. 명확하게 설명해 주셔서 감사합니다. 😊


✏️ Learnings added
Learnt from: eraser502
Repo: redotlabs/server PR: 134
File: src/main/java/redot/redot_server/domain/admin/service/AdminRedotAppService.java:58-71
Timestamp: 2025-12-17T01:39:43.440Z
Learning: In the RedotApp domain model, there is a 1:1 relationship between RedotApp and Domain, StyleInfo, and SiteSetting entities. Each RedotApp has exactly one Domain, one StyleInfo, and one SiteSetting.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


Page<RedotAppInfoResponse> responsePage = redotApps.map(redotApp ->
toRedotAppInfoResponse(
redotApp,
domainMap.get(redotApp.getId()),
styleInfoMap.get(redotApp.getId()),
siteSettingMap.get(redotApp.getId())
));

return PageResponse.from(responsePage);
}

private RedotAppInfoResponse toRedotAppInfoResponse(RedotApp redotApp) {
Domain domain = domainRepository.findByRedotAppId(redotApp.getId()).orElse(null);
StyleInfo styleInfo = styleInfoRepository.findByRedotApp_Id(redotApp.getId()).orElse(null);
SiteSetting siteSetting = siteSettingRepository.findByRedotAppId(redotApp.getId()).orElse(null);

return toRedotAppInfoResponse(redotApp, domain, styleInfo, siteSetting);
}

private RedotAppInfoResponse toRedotAppInfoResponse(RedotApp redotApp,
Domain domain,
StyleInfo styleInfo,
SiteSetting siteSetting) {
SiteSettingResponse siteSettingResponse = (siteSetting != null && domain != null)
? SiteSettingResponse.fromEntity(siteSetting, domain, imageUrlResolver)
: null;

StyleInfoResponse styleInfoResponse = styleInfo != null
? StyleInfoResponse.fromEntity(styleInfo)
: null;

return new RedotAppInfoResponse(
RedotAppResponse.fromEntity(redotApp),
siteSettingResponse,
styleInfoResponse,
RedotMemberResponse.fromNullable(redotApp.getOwner(), imageUrlResolver)
);
}

public RedotAppInfoResponse getRedotAppInfo(Long redotAppId) {
RedotApp redotApp = redotAppRepository.findById(redotAppId)
.orElseThrow(() -> new RedotAppException(RedotAppErrorCode.REDOT_APP_NOT_FOUND));

return toRedotAppInfoResponse(redotApp);
}

@Transactional
public RedotAppInfoResponse updateRedotAppStatus(Long redotAppId, RedotAppStatusUpdateRequest request) {
RedotApp redotApp = redotAppRepository.findById(redotAppId)
.orElseThrow(() -> new RedotAppException(RedotAppErrorCode.REDOT_APP_NOT_FOUND));

redotApp.updateStatus(request.status(), request.remark());

return toRedotAppInfoResponse(redotApp);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ public class AdminImpersonationController implements AdminImpersonationControlle

@PostMapping("/cms-admin")
@Override
public ResponseEntity<TokenResponse> impersonateAsCMSAdmin(HttpServletRequest request, @Valid @RequestBody CMSAdminImpersonationRequest cmsAdminImpersonationRequest, @AuthenticationPrincipal JwtPrincipal jwtPrincipal) {
Long adminId = jwtPrincipal.id();

AuthResult authResult = adminImpersonationService.impersonateAsCMSAdmin(request, cmsAdminImpersonationRequest, adminId);
public ResponseEntity<TokenResponse> impersonateAsCMSAdmin(HttpServletRequest request, @Valid @RequestBody CMSAdminImpersonationRequest cmsAdminImpersonationRequest) {
AuthResult authResult = adminImpersonationService.impersonateAsCMSAdmin(request, cmsAdminImpersonationRequest);
return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, authResult.accessCookie().toString())
.header(HttpHeaders.SET_COOKIE, authResult.refreshCookie().toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import org.springframework.http.ResponseEntity;
import redot.redot_server.domain.auth.dto.request.CMSAdminImpersonationRequest;
import redot.redot_server.domain.auth.dto.response.TokenResponse;
import redot.redot_server.global.security.principal.JwtPrincipal;

@Tag(name = "Admin Impersonation", description = "관리자 권한 위임 API")
public interface AdminImpersonationControllerDocs {
Expand All @@ -20,6 +19,5 @@ public interface AdminImpersonationControllerDocs {
@ApiResponse(responseCode = "200", description = "발급 성공",
content = @Content(schema = @Schema(implementation = TokenResponse.class)))
ResponseEntity<TokenResponse> impersonateAsCMSAdmin(@Parameter(hidden = true) HttpServletRequest request,
@Valid CMSAdminImpersonationRequest cmsAdminImpersonationRequest,
@Parameter(hidden = true) JwtPrincipal jwtPrincipal);
@Valid CMSAdminImpersonationRequest cmsAdminImpersonationRequest);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
import org.springframework.transaction.annotation.Transactional;
import redot.redot_server.domain.auth.dto.request.CMSAdminImpersonationRequest;
import redot.redot_server.domain.auth.dto.response.AuthResult;
import redot.redot_server.domain.auth.exception.AuthErrorCode;
import redot.redot_server.domain.auth.exception.AuthException;
import redot.redot_server.domain.cms.member.entity.CMSMember;
import redot.redot_server.domain.cms.member.entity.CMSMemberRole;
import redot.redot_server.domain.cms.member.repository.CMSMemberRepository;
import redot.redot_server.global.jwt.token.TokenContext;
import redot.redot_server.global.jwt.token.TokenType;

Expand All @@ -17,10 +21,18 @@
public class AdminImpersonationService {

private final AuthTokenService authTokenService;
private final CMSMemberRepository cmsMemberRepository;

public AuthResult impersonateAsCMSAdmin(HttpServletRequest request,
CMSAdminImpersonationRequest cmsAdminImpersonationRequest) {
CMSMember owner = cmsMemberRepository
.findFirstByRedotApp_IdAndRoleOrderByIdAsc(cmsAdminImpersonationRequest.redotAppId(),
CMSMemberRole.OWNER)
.orElseThrow(() -> new AuthException(AuthErrorCode.CMS_MEMBER_NOT_FOUND));

public AuthResult impersonateAsCMSAdmin(HttpServletRequest request, CMSAdminImpersonationRequest cmsAdminImpersonationRequest, Long adminId) {
return authTokenService.issueTokens(request,
new TokenContext(adminId, TokenType.CMS, List.of(CMSMemberRole.ADMIN.name()), cmsAdminImpersonationRequest.redotAppId())
new TokenContext(owner.getId(), TokenType.CMS, List.of(owner.getRole().name()),
cmsAdminImpersonationRequest.redotAppId())
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import redot.redot_server.domain.cms.member.entity.CMSMember;
import redot.redot_server.domain.cms.member.entity.CMSMemberRole;

public interface CMSMemberRepository extends JpaRepository<CMSMember, Long>, CMSMemberRepositoryCustom {
Optional<CMSMember> findByEmailAndRedotApp_Id(String email, Long redotAppId);
Expand All @@ -21,4 +22,5 @@ Optional<CMSMember> findByIdAndRedotApp_IdIncludingDeleted(
@Param("id") Long id,
@Param("redotAppId") Long redotAppId);

Optional<CMSMember> findFirstByRedotApp_IdAndRoleOrderByIdAsc(Long redotAppId, CMSMemberRole role);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ public record RedotAppResponse(
RedotAppStatus status,
boolean isCreatedManager,
LocalDateTime createdAt,
Long planId
Long planId,
String remark
) {
public static RedotAppResponse fromEntity(RedotApp redotApp) {
return new RedotAppResponse(
Expand All @@ -19,7 +20,8 @@ public static RedotAppResponse fromEntity(RedotApp redotApp) {
redotApp.getStatus(),
redotApp.isCreatedManager(),
redotApp.getCreatedAt(),
redotApp.getPlan().getId()
redotApp.getPlan().getId(),
redotApp.getRemark()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public class RedotApp extends BaseTimeEntity {
@Column(nullable = false)
private String name;

@Column(columnDefinition = "text")
private String remark;

// 초기 관리자 계정 생성 여부(default=false)
@Column(nullable = false)
@Builder.Default
Expand Down Expand Up @@ -78,4 +81,9 @@ public boolean isOwner(Long redotMemberId) {
public void updatePlan(Plan plan) {
this.plan = plan;
}

public void updateStatus(RedotAppStatus status, String remark) {
this.status = status;
this.remark = remark;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ public enum RedotAppStatus {
INACTIVE,
DELETED,
RESIGNED,
PAYMENT_DELAYED
PAYMENT_DELAYED,
BANNED
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import org.springframework.data.jpa.repository.JpaRepository;
import redot.redot_server.domain.redot.app.entity.RedotApp;

public interface RedotAppRepository extends JpaRepository<RedotApp, Long> {
public interface RedotAppRepository extends JpaRepository<RedotApp, Long>, RedotAppRepositoryCustom {
Page<RedotApp> findByOwnerId(Long ownerId, Pageable pageable);

long countByOwnerId(Long ownerId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package redot.redot_server.domain.redot.app.repository;

import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import redot.redot_server.domain.admin.dto.request.RedotAppInfoSearchCondition;
import redot.redot_server.domain.redot.app.entity.RedotApp;

public interface RedotAppRepositoryCustom {

Page<RedotApp> findAllBySearchCondition(RedotAppInfoSearchCondition searchCondition,
Pageable pageable);

List<RedotAppWithSiteInfo> findAllWithSiteInfo(RedotAppInfoSearchCondition searchCondition,
Pageable pageable);

long countBySearchCondition(RedotAppInfoSearchCondition searchCondition);
}
Loading