diff --git a/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/DefaultListQuotasUseCase.java b/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/DefaultListQuotasUseCase.java index c5bd7fcf..c21f7e47 100644 --- a/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/DefaultListQuotasUseCase.java +++ b/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/DefaultListQuotasUseCase.java @@ -1,15 +1,24 @@ package com.callv2.drive.application.member.quota.retrieve.list; +import com.callv2.drive.domain.member.MemberGateway; import com.callv2.drive.domain.pagination.Page; import com.callv2.drive.domain.pagination.SearchQuery; public class DefaultListQuotasUseCase extends ListQuotasUseCase { + private final MemberGateway memberGateway; + + public DefaultListQuotasUseCase(final MemberGateway memberGateway) { + this.memberGateway = memberGateway; + } + @Override - public Page execute(SearchQuery query) { + public Page execute(final SearchQuery query) { + + return memberGateway + .findAll(query) + .map(ListQuotaOutput::of); - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'execute'"); } } diff --git a/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/ListQuotaOutput.java b/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/ListQuotaOutput.java new file mode 100644 index 00000000..004f3be6 --- /dev/null +++ b/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/ListQuotaOutput.java @@ -0,0 +1,14 @@ +package com.callv2.drive.application.member.quota.retrieve.list; + +import com.callv2.drive.domain.member.Member; + +public record ListQuotaOutput(String memberId, String username, Long total) { + + public static ListQuotaOutput of(final Member member) { + return new ListQuotaOutput( + member.getId().getValue(), + member.getUsername().value(), + member.getQuota().sizeInBytes()); + } + +} diff --git a/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/ListQuotasUseCase.java b/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/ListQuotasUseCase.java index cae14b64..bc952e34 100644 --- a/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/ListQuotasUseCase.java +++ b/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/ListQuotasUseCase.java @@ -4,6 +4,6 @@ import com.callv2.drive.domain.pagination.Page; import com.callv2.drive.domain.pagination.SearchQuery; -public abstract class ListQuotasUseCase extends UseCase> { +public abstract class ListQuotasUseCase extends UseCase> { } diff --git a/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/QuotaListOutput.java b/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/QuotaListOutput.java deleted file mode 100644 index 9db4e867..00000000 --- a/application/src/main/java/com/callv2/drive/application/member/quota/retrieve/list/QuotaListOutput.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.callv2.drive.application.member.quota.retrieve.list; - -public record QuotaListOutput(String memberId, Long amount) { - - public static QuotaListOutput of(String memberId, Long amount) { - return new QuotaListOutput(memberId, amount); - } - -} diff --git a/domain/src/main/java/com/callv2/drive/domain/member/MemberGateway.java b/domain/src/main/java/com/callv2/drive/domain/member/MemberGateway.java index 394345e3..40630fb7 100644 --- a/domain/src/main/java/com/callv2/drive/domain/member/MemberGateway.java +++ b/domain/src/main/java/com/callv2/drive/domain/member/MemberGateway.java @@ -9,6 +9,8 @@ public interface MemberGateway { Member create(Member member); + Page findAll(SearchQuery searchQuery); + Optional findById(MemberID id); Member update(Member member); diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/api/MemberAdminAPI.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/api/MemberAdminAPI.java index f3ea018a..d11ae5d1 100644 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/api/MemberAdminAPI.java +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/api/MemberAdminAPI.java @@ -1,5 +1,7 @@ package com.callv2.drive.infrastructure.api; +import java.util.List; + import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; @@ -7,9 +9,11 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; +import com.callv2.drive.domain.pagination.Filter; import com.callv2.drive.domain.pagination.Page; import com.callv2.drive.domain.pagination.Pagination; import com.callv2.drive.infrastructure.api.controller.ApiError; +import com.callv2.drive.infrastructure.member.model.MemberQuotaListResponse; import com.callv2.drive.infrastructure.member.model.MemberQuotaResponse; import com.callv2.drive.infrastructure.member.model.QuotaRequestListResponse; @@ -49,4 +53,17 @@ ResponseEntity> listQuotaRequests( @RequestParam(name = "orderField", required = false, defaultValue = "quotaRequestedAt") String orderField, @RequestParam(name = "orderDirection", required = false, defaultValue = "DESC") Pagination.Order.Direction orderDirection); + @Operation(summary = "List members quotas", description = "This method list members quotas", security = @SecurityRequirement(name = "bearerAuth")) + @ApiResponse(responseCode = "200", description = "Quota members listed successfully", content = @Content(schema = @Schema(implementation = Page.class, subTypes = { + MemberQuotaListResponse.class }))) + @ApiResponse(responseCode = "500", description = "Internal Server Error", content = @Content(schema = @Schema(implementation = ApiError.class))) + @GetMapping("quotas") + ResponseEntity> listQuotas( + @RequestParam(name = "page", required = false, defaultValue = "0") final int page, + @RequestParam(name = "perPage", required = false, defaultValue = "10") final int perPage, + @RequestParam(name = "orderField", required = false, defaultValue = "createdAt") String orderField, + @RequestParam(name = "orderDirection", required = false, defaultValue = "DESC") Pagination.Order.Direction orderDirection, + @RequestParam(name = "filterOperator", required = false, defaultValue = "AND") Filter.Operator filterOperator, + @RequestParam(name = "filters", required = false) List filters); + } \ No newline at end of file diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/api/controller/MemberAdminController.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/api/controller/MemberAdminController.java index 961c2f4a..db18743f 100644 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/api/controller/MemberAdminController.java +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/api/controller/MemberAdminController.java @@ -10,10 +10,16 @@ import com.callv2.drive.application.member.quota.request.list.ListRequestQuotaUseCase; import com.callv2.drive.application.member.quota.retrieve.get.GetQuotaInput; import com.callv2.drive.application.member.quota.retrieve.get.GetQuotaUseCase; +import com.callv2.drive.application.member.quota.retrieve.list.ListQuotasUseCase; +import com.callv2.drive.domain.pagination.Filter; +import com.callv2.drive.domain.pagination.Filter.Operator; import com.callv2.drive.domain.pagination.Page; import com.callv2.drive.domain.pagination.Pagination; +import com.callv2.drive.domain.pagination.Pagination.Order.Direction; import com.callv2.drive.domain.pagination.SearchQuery; import com.callv2.drive.infrastructure.api.MemberAdminAPI; +import com.callv2.drive.infrastructure.filter.adapter.QueryAdapter; +import com.callv2.drive.infrastructure.member.model.MemberQuotaListResponse; import com.callv2.drive.infrastructure.member.model.MemberQuotaResponse; import com.callv2.drive.infrastructure.member.model.QuotaRequestListResponse; import com.callv2.drive.infrastructure.member.presenter.MemberPresenter; @@ -24,14 +30,17 @@ public class MemberAdminController implements MemberAdminAPI { private final ApproveRequestQuotaUseCase approveRequestQuotaUseCase; private final ListRequestQuotaUseCase listRequestQuotaUseCase; private final GetQuotaUseCase getQuotaUseCase; + private final ListQuotasUseCase listQuotasUseCase; public MemberAdminController( final ApproveRequestQuotaUseCase approveRequestQuotaUseCase, final ListRequestQuotaUseCase listRequestQuotaUseCase, - final GetQuotaUseCase getQuotaUseCase) { + final GetQuotaUseCase getQuotaUseCase, + final ListQuotasUseCase listQuotasUseCase) { this.approveRequestQuotaUseCase = approveRequestQuotaUseCase; this.listRequestQuotaUseCase = listRequestQuotaUseCase; this.getQuotaUseCase = getQuotaUseCase; + this.listQuotasUseCase = listQuotasUseCase; } @Override @@ -61,4 +70,28 @@ public ResponseEntity> listQuotaRequests( } + @Override + public ResponseEntity> listQuotas( + int page, + int perPage, + String orderField, + Direction orderDirection, + Operator filterOperator, + List filters) { + + final List searchFilters = filters == null ? List.of() + : filters + .stream() + .map(QueryAdapter::of) + .toList(); + + final SearchQuery query = SearchQuery.of( + Pagination.of(page, perPage, Pagination.Order.of(orderField, orderDirection)), + filterOperator, + searchFilters); + + return ResponseEntity.ok(listQuotasUseCase.execute(query).map(MemberPresenter::present)); + + } + } diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/configuration/usecase/MemberUseCaseConfig.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/configuration/usecase/MemberUseCaseConfig.java index 14d4ac06..93aba9e6 100644 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/configuration/usecase/MemberUseCaseConfig.java +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/configuration/usecase/MemberUseCaseConfig.java @@ -11,6 +11,8 @@ import com.callv2.drive.application.member.quota.request.list.ListRequestQuotaUseCase; import com.callv2.drive.application.member.quota.retrieve.get.DefaultGetQuotaUseCase; import com.callv2.drive.application.member.quota.retrieve.get.GetQuotaUseCase; +import com.callv2.drive.application.member.quota.retrieve.list.DefaultListQuotasUseCase; +import com.callv2.drive.application.member.quota.retrieve.list.ListQuotasUseCase; import com.callv2.drive.application.member.synchronize.DefaultSynchronizeMemberUseCase; import com.callv2.drive.application.member.synchronize.SynchronizeMemberUseCase; import com.callv2.drive.domain.file.FileGateway; @@ -52,4 +54,9 @@ SynchronizeMemberUseCase synchronizeMemberUseCase() { return new DefaultSynchronizeMemberUseCase(memberGateway); } + @Bean + ListQuotasUseCase listQuotasUseCase() { + return new DefaultListQuotasUseCase(memberGateway); + } + } diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/DefaultMemberGateway.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/DefaultMemberGateway.java index ff1a698c..b38105c2 100644 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/DefaultMemberGateway.java +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/DefaultMemberGateway.java @@ -3,6 +3,8 @@ import java.util.Optional; import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -14,6 +16,7 @@ import com.callv2.drive.domain.member.QuotaRequestPreview; import com.callv2.drive.domain.pagination.Page; import com.callv2.drive.domain.pagination.SearchQuery; +import com.callv2.drive.infrastructure.filter.FilterService; import com.callv2.drive.infrastructure.filter.adapter.QueryAdapter; import com.callv2.drive.infrastructure.member.persistence.MemberJpaEntity; import com.callv2.drive.infrastructure.member.persistence.MemberJpaRepository; @@ -21,9 +24,13 @@ @Component public class DefaultMemberGateway implements MemberGateway { + private final FilterService filterService; private final MemberJpaRepository memberJpaRepository; - public DefaultMemberGateway(final MemberJpaRepository memberJpaRepository) { + public DefaultMemberGateway( + final FilterService filterService, + final MemberJpaRepository memberJpaRepository) { + this.filterService = filterService; this.memberJpaRepository = memberJpaRepository; } @@ -35,6 +42,28 @@ public Member create(final Member member) { return this.memberJpaRepository.save(MemberJpaEntity.fromDomain(member)).toDomain(); } + @Override + public Page findAll(SearchQuery searchQuery) { + + final PageRequest pageRequest = QueryAdapter.of(searchQuery.pagination()); + + final Specification specification = filterService.buildSpecification( + MemberJpaEntity.class, + searchQuery.filterMethod(), + searchQuery.filters()); + + final var pageResult = this.memberJpaRepository.findAll(specification, pageRequest); + + return new Page<>( + pageResult.getNumber(), + pageResult.getSize(), + pageResult.getTotalPages(), + pageResult.getTotalElements(), + pageResult.toList()) + .map(MemberJpaEntity::toDomain); + + } + @Override public Optional findById(final MemberID id) { return this.memberJpaRepository diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/model/MemberQuotaListResponse.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/model/MemberQuotaListResponse.java new file mode 100644 index 00000000..6082c7d1 --- /dev/null +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/model/MemberQuotaListResponse.java @@ -0,0 +1,5 @@ +package com.callv2.drive.infrastructure.member.model; + +public record MemberQuotaListResponse(String memberId, String username, Long total) { + +} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/persistence/MemberJpaRepository.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/persistence/MemberJpaRepository.java index efe13292..cd9572c7 100644 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/persistence/MemberJpaRepository.java +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/persistence/MemberJpaRepository.java @@ -4,6 +4,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -14,6 +15,8 @@ public interface MemberJpaRepository extends JpaRepository { + Page findAll(Specification whereClause, Pageable page); + @Query(""" select distinct new com.callv2.drive.domain.member.QuotaRequestPreview( m.id as memberId, diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/presenter/MemberPresenter.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/presenter/MemberPresenter.java index a60736c5..4e48e5f4 100644 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/presenter/MemberPresenter.java +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/member/presenter/MemberPresenter.java @@ -2,6 +2,8 @@ import com.callv2.drive.application.member.quota.request.list.ListRequestQuotaOutput; import com.callv2.drive.application.member.quota.retrieve.get.GetQuotaOutput; +import com.callv2.drive.application.member.quota.retrieve.list.ListQuotaOutput; +import com.callv2.drive.infrastructure.member.model.MemberQuotaListResponse; import com.callv2.drive.infrastructure.member.model.MemberQuotaResponse; import com.callv2.drive.infrastructure.member.model.QuotaRequestListResponse; @@ -18,7 +20,18 @@ static QuotaRequestListResponse present(final ListRequestQuotaOutput output) { } static MemberQuotaResponse present(final GetQuotaOutput output) { - return new MemberQuotaResponse(output.memberId(), output.used(), output.total(), output.available()); + return new MemberQuotaResponse( + output.memberId(), + output.used(), + output.total(), + output.available()); + } + + static MemberQuotaListResponse present(final ListQuotaOutput output) { + return new MemberQuotaListResponse( + output.memberId(), + output.username(), + output.total()); } }