diff --git a/.gitignore b/.gitignore index 678c603..ee70cb8 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ out/ .vscode/ /core/core-security/src/main/resources/key/AuthKey_X93DK84396.p8 /key/AuthKey_X93DK84396.p8 +/data/ diff --git a/api/src/main/java/com/mm/api/domain/point/service/PointService.java b/api/src/main/java/com/mm/api/domain/point/service/PointService.java index 9fa0604..0fba331 100644 --- a/api/src/main/java/com/mm/api/domain/point/service/PointService.java +++ b/api/src/main/java/com/mm/api/domain/point/service/PointService.java @@ -1,11 +1,5 @@ package com.mm.api.domain.point.service; -import java.time.LocalDateTime; -import java.util.List; - -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import com.mm.api.domain.buy.dto.response.BuyResponse; import com.mm.api.domain.point.dto.response.PointsResponse; import com.mm.api.exception.CustomException; @@ -16,111 +10,133 @@ import com.mm.coredomain.repository.BuyRepository; import com.mm.coredomain.repository.MemberRepository; import com.mm.coresecurity.oauth.OAuth2UserDetails; - import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; @Service @Transactional @RequiredArgsConstructor public class PointService { - private final MemberRepository memberRepository; - private final BuyRepository buyRepository; - - @Transactional(readOnly = true) - public Integer getMyPoint(OAuth2UserDetails userDetails) { - Long memberId = userDetails.getId(); - return getMember(memberId).getPoint(); - } - - // TODO 쿼리로 가져오게 개선 - @Transactional(readOnly = true) - public PointsResponse getCumulativeHistory(OAuth2UserDetails userDetails) { - Long memberId = userDetails.getId(); - Member member = getMember(memberId); - - List buys = buyRepository.findAllByMember(member); - List buyResponses = buys - .stream() - .filter(this::isRefundCumulative) - .map(buy -> BuyResponse.of(buy, buy.getMember())) - .toList(); - Integer totalPoint = buys.stream() - .filter(this::isRefundCumulativeTotalPoint) - .map(Buy::getRefund) - .reduce(0, Integer::sum); - - return new PointsResponse(totalPoint, buyResponses); - } - - @Transactional(readOnly = true) - public PointsResponse getExpectedHistory(OAuth2UserDetails userDetails) { - Long memberId = userDetails.getId(); - Member member = getMember(memberId); - - List buys = buyRepository.findAllByMember(member); - List buyResponses = buyRepository.findAllByMember(member) - .stream() - .filter(this::isRefundExpected) - .map(buy -> BuyResponse.of(buy, buy.getMember())) - .toList(); - Integer totalPoint = buys.stream() - .filter(this::isRefundExpectedTotalPoint) - .map(Buy::getRefund) - .reduce(0, Integer::sum); - - return new PointsResponse(totalPoint, buyResponses); - } - - public BuyResponse postPointsWithdraw(OAuth2UserDetails userDetails, Integer refund) { - Member member = getMember(userDetails.getId()); - - isPointsEnoughForRefund(refund, member); - - Buy buy = Buy.builder() - .member(member) - .refund(refund) - .uploadTime(LocalDateTime.now()) - .refundStatus(RefundStatus.WITHDRAWN_IN_PROGRESS) - .build(); - - Buy savedBuy = buyRepository.save(buy); - return BuyResponse.of(savedBuy, savedBuy.getMember()); - } - - private void isPointsEnoughForRefund(Integer refund, Member member) { - if (refund < 1000) { - throw new CustomException(ErrorCode.POINTS_WITHDRAW_MIN); - } - if (refund > 5000) { - throw new CustomException(ErrorCode.POINTS_WITHDRAW_MAX); - } - if (refund > member.getPoint()) { - throw new CustomException(ErrorCode.POINTS_WITHDRAW_NOT_ENOUGH); - } - } - - private boolean isRefundCumulativeTotalPoint(Buy buy) { - return buy.getRefundStatus().equals(RefundStatus.COMPLETED); - } - - private boolean isRefundExpectedTotalPoint(Buy buy) { - return buy.getRefundStatus().equals(RefundStatus.IN_PROGRESS); - } - - private boolean isRefundCumulative(Buy buy) { - return buy.getRefundStatus().equals(RefundStatus.COMPLETED) || - buy.getRefundStatus().equals(RefundStatus.REJECTED) || - buy.getRefundStatus().equals(RefundStatus.WITHDRAWN_COMPLETED) || - buy.getRefundStatus().equals(RefundStatus.WITHDRAWN_REJECTED); - } - - private boolean isRefundExpected(Buy buy) { - return buy.getRefundStatus().equals(RefundStatus.IN_PROGRESS) || - buy.getRefundStatus().equals(RefundStatus.WITHDRAWN_IN_PROGRESS); - } - - private Member getMember(Long memberId) { - return memberRepository.findById(memberId) - .orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND)); - } + private final MemberRepository memberRepository; + private final BuyRepository buyRepository; + + @Transactional(readOnly = true) + public Integer getMyPoint(OAuth2UserDetails userDetails) { + Long memberId = userDetails.getId(); + return getMember(memberId).getPoint(); + } + + // TODO 쿼리로 가져오게 개선 + @Transactional(readOnly = true) + public PointsResponse getCumulativeHistory(OAuth2UserDetails userDetails) { + Long memberId = userDetails.getId(); + Member member = getMember(memberId); + + List buys = buyRepository.findAllByMember(member); + List buyResponses = buys + .stream() + .filter(this::isRefundCumulative) + .map(buy -> BuyResponse.of(buy, buy.getMember())) + .toList(); + List reveredBuyResponses = new ArrayList<>(buyResponses); + Collections.reverse(reveredBuyResponses); + + Integer totalPoint = buys.stream() + .filter(this::isRefundCumulativeTotalPoint) + .map(buy -> { + if (buy.getRefund() == null) { + return 0; + } + return buy.getRefund(); + }) + .reduce(0, Integer::sum); + + return new PointsResponse(totalPoint, reveredBuyResponses); + } + + @Transactional(readOnly = true) + public PointsResponse getExpectedHistory(OAuth2UserDetails userDetails) { + Long memberId = userDetails.getId(); + Member member = getMember(memberId); + + List buys = buyRepository.findAllByMember(member); + List buyResponses = buyRepository.findAllByMember(member) + .stream() + .filter(this::isRefundExpected) + .map(buy -> BuyResponse.of(buy, buy.getMember())) + .toList(); + List reveredBuyResponses = new ArrayList<>(buyResponses); + Collections.reverse(reveredBuyResponses); + + Integer totalPoint = buys.stream() + .filter(this::isRefundExpectedTotalPoint) + .map(buy -> { + if (buy.getRefund() == null) { + return 0; + } + return buy.getRefund(); + }) + .reduce(0, Integer::sum); + + return new PointsResponse(totalPoint, reveredBuyResponses); + } + + public BuyResponse postPointsWithdraw(OAuth2UserDetails userDetails, Integer refund) { + Member member = getMember(userDetails.getId()); + + isPointsEnoughForRefund(refund, member); + + Buy buy = Buy.builder() + .member(member) + .refund(refund) + .uploadTime(LocalDateTime.now()) + .refundStatus(RefundStatus.WITHDRAWN_IN_PROGRESS) + .build(); + + Buy savedBuy = buyRepository.save(buy); + return BuyResponse.of(savedBuy, savedBuy.getMember()); + } + + private void isPointsEnoughForRefund(Integer refund, Member member) { + if (refund < 1000) { + throw new CustomException(ErrorCode.POINTS_WITHDRAW_MIN); + } + if (refund > 5000) { + throw new CustomException(ErrorCode.POINTS_WITHDRAW_MAX); + } + if (refund > member.getPoint()) { + throw new CustomException(ErrorCode.POINTS_WITHDRAW_NOT_ENOUGH); + } + } + + private boolean isRefundCumulativeTotalPoint(Buy buy) { + return buy.getRefundStatus().equals(RefundStatus.COMPLETED); + } + + private boolean isRefundExpectedTotalPoint(Buy buy) { + return buy.getRefundStatus().equals(RefundStatus.IN_PROGRESS); + } + + private boolean isRefundCumulative(Buy buy) { + return buy.getRefundStatus().equals(RefundStatus.COMPLETED) || + buy.getRefundStatus().equals(RefundStatus.REJECTED) || + buy.getRefundStatus().equals(RefundStatus.WITHDRAWN_COMPLETED) || + buy.getRefundStatus().equals(RefundStatus.WITHDRAWN_REJECTED); + } + + private boolean isRefundExpected(Buy buy) { + return buy.getRefundStatus().equals(RefundStatus.IN_PROGRESS) || + buy.getRefundStatus().equals(RefundStatus.WITHDRAWN_IN_PROGRESS); + } + + private Member getMember(Long memberId) { + return memberRepository.findById(memberId) + .orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND)); + } } diff --git a/core/core-domain/src/main/java/com/mm/coredomain/domain/Groups.java b/core/core-domain/src/main/java/com/mm/coredomain/domain/Groups.java index 6ffa0da..8ffe8ee 100644 --- a/core/core-domain/src/main/java/com/mm/coredomain/domain/Groups.java +++ b/core/core-domain/src/main/java/com/mm/coredomain/domain/Groups.java @@ -1,23 +1,20 @@ package com.mm.coredomain.domain; -import java.util.List; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; +import jakarta.persistence.*; import lombok.Getter; +import java.util.List; + @Getter @Entity +@Table(name = "member_groups") public class Groups extends BaseEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - private String name; + private String name; - @OneToMany(mappedBy = "groups") - private List groupPermissions; + @OneToMany(mappedBy = "groups") + private List groupPermissions; } diff --git a/core/core-domain/src/main/java/com/mm/coredomain/domain/Permission.java b/core/core-domain/src/main/java/com/mm/coredomain/domain/Permission.java index 24738d8..cf90b89 100644 --- a/core/core-domain/src/main/java/com/mm/coredomain/domain/Permission.java +++ b/core/core-domain/src/main/java/com/mm/coredomain/domain/Permission.java @@ -2,15 +2,16 @@ import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import lombok.Getter; @Getter @Entity public class Permission extends BaseEntity { - @Id - @GeneratedValue - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - private String name; + private String name; } diff --git a/core/core-infra-qdsl/src/main/java/com/mm/coreinfraqdsl/repository/BuyCustomRepositoryImpl.java b/core/core-infra-qdsl/src/main/java/com/mm/coreinfraqdsl/repository/BuyCustomRepositoryImpl.java index 35146a6..31ec634 100644 --- a/core/core-infra-qdsl/src/main/java/com/mm/coreinfraqdsl/repository/BuyCustomRepositoryImpl.java +++ b/core/core-infra-qdsl/src/main/java/com/mm/coreinfraqdsl/repository/BuyCustomRepositoryImpl.java @@ -1,43 +1,42 @@ package com.mm.coreinfraqdsl.repository; -import static com.mm.coredomain.domain.QBuy.*; - -import java.util.List; - -import org.springframework.stereotype.Repository; - import com.mm.coredomain.domain.Buy; import com.mm.coredomain.domain.Member; import com.querydsl.jpa.impl.JPAQueryFactory; - import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +import static com.mm.coredomain.domain.QBuy.buy; @Repository @RequiredArgsConstructor public class BuyCustomRepositoryImpl implements BuyCustomRepository { - private final JPAQueryFactory jpaQueryFactory; - - private static final Long PAGE_OFFSET = 10L; - private static final Long PAGE_OFFSET_ME = 9L; - - @Override - public List getBuysMeByMember(Integer page, Member member) { - return jpaQueryFactory.selectFrom(buy) - .where(buy.member.eq(member)) - .offset((page - 1) * PAGE_OFFSET_ME) - .limit(PAGE_OFFSET_ME) - .fetch(); - } - - @Override - public Long getBuysMePageNum(Member member) { - Long count = jpaQueryFactory.select(buy.count()) - .from(buy) - .where(buy.member.eq(member)) - .fetchOne(); - if (count % PAGE_OFFSET_ME != 0) { - return count / PAGE_OFFSET_ME + 1; - } - return count / PAGE_OFFSET_ME; - } + private final JPAQueryFactory jpaQueryFactory; + + private static final Long PAGE_OFFSET = 10L; + private static final Long PAGE_OFFSET_ME = 9L; + + @Override + public List getBuysMeByMember(Integer page, Member member) { + return jpaQueryFactory.selectFrom(buy) + .where(buy.member.eq(member)) + .orderBy(buy.id.desc()) + .offset((page - 1) * PAGE_OFFSET_ME) + .limit(PAGE_OFFSET_ME) + .fetch(); + } + + @Override + public Long getBuysMePageNum(Member member) { + Long count = jpaQueryFactory.select(buy.count()) + .from(buy) + .where(buy.member.eq(member)) + .fetchOne(); + if (count % PAGE_OFFSET_ME != 0) { + return count / PAGE_OFFSET_ME + 1; + } + return count / PAGE_OFFSET_ME; + } } diff --git a/core/core-security/src/main/java/com/mm/coresecurity/config/WebSecurityConfig.java b/core/core-security/src/main/java/com/mm/coresecurity/config/WebSecurityConfig.java index acbc131..ae76b10 100644 --- a/core/core-security/src/main/java/com/mm/coresecurity/config/WebSecurityConfig.java +++ b/core/core-security/src/main/java/com/mm/coresecurity/config/WebSecurityConfig.java @@ -110,7 +110,7 @@ private RequestMatcher[] permitAllRequests() { private RequestMatcher[] oauthRequests() { List requestMatchers = List.of( - antMatcher("/oauth2/authorization/kakao"), + antMatcher("/oauth2/authorization/*"), antMatcher("/oauth/**"), antMatcher("/api/*/auth/refresh-access-token"), antMatcher("/super-token") diff --git a/db/initdb.d/1-schema.sql b/db/initdb.d/1-schema.sql new file mode 100644 index 0000000..afef8e1 --- /dev/null +++ b/db/initdb.d/1-schema.sql @@ -0,0 +1,122 @@ +create table member_groups ( + id bigint auto_increment primary key, + created_at datetime, + deleted boolean, + updated_at datetime, + name varchar(255) +); + +create table permission ( + id bigint auto_increment primary key, + created_at datetime, + deleted boolean, + updated_at datetime, + name varchar(20) +); + +create table admin ( + id bigint auto_increment primary key, + created_at datetime, + deleted boolean, + updated_at datetime, + email varchar(255), + name varchar(100), + password varchar(255), + member_groups_id bigint, + foreign key (member_groups_id) references member_groups(id) +); + +create table member ( + id bigint auto_increment primary key, + created_at datetime, + deleted boolean, + updated_at datetime, + account varchar(50), + account_bank varchar(50), + depositor_name varchar(20), + email varchar(255), + member_status smallint, + name varchar(100), + point int, + provider smallint, + member_groups_id bigint, + foreign key (member_groups_id) references member_groups(id) +); + +create table item ( + id bigint auto_increment primary key, + created_at datetime, + deleted boolean, + updated_at datetime, + category_type varchar(50), + is_suggested boolean, + price int, + rating double, + redirect_url longtext, + refund int, + thumbnail_url longtext, + title longtext +); + +create table item_image ( + id bigint auto_increment primary key, + created_at datetime, + deleted boolean, + updated_at datetime, + url longtext, + item_id bigint, + foreign key (item_id) references item(id) +); + +create table item_video ( + id bigint auto_increment primary key, + created_at datetime, + deleted boolean, + updated_at datetime, + url longtext, + item_id bigint, + foreign key (item_id) references item(id) +); + +create table buy ( + id bigint auto_increment primary key, + created_at datetime, + deleted boolean, + updated_at datetime, + approved_time datetime, + cert_image_url longtext, + points_after_refund int, + points_before_refund int, + purchase int, + redirect_url longtext, + refund int, + refund_status smallint, + reject_reason varchar(255), + upload_time datetime, + item_id bigint, + member_id bigint, + foreign key (item_id) references item(id), + foreign key (member_id) references member(id) +); + +create table dib ( + id bigint auto_increment primary key, + created_at datetime, + deleted boolean, + updated_at datetime, + item_id bigint, + member_id bigint, + foreign key (item_id) references item(id), + foreign key (member_id) references member(id) +); + +create table group_permission ( + id bigint auto_increment primary key, + created_at datetime, + deleted boolean, + updated_at datetime, + member_groups_id bigint, + permission_id bigint, + foreign key (member_groups_id) references member_groups(id), + foreign key (permission_id) references permission(id) +); diff --git a/db/initdb.d/2-data.sql b/db/initdb.d/2-data.sql new file mode 100644 index 0000000..01ae6c0 --- /dev/null +++ b/db/initdb.d/2-data.sql @@ -0,0 +1,12 @@ +insert into permission(id, name) values(1, 'ROLE_ADMIN'); +insert into permission(id, name) values(2, 'ROLE_USER'); + +insert into member_groups(id, name) values(1, 'ADMIN_GROUP'); +insert into member_groups(id, name) values(2, 'USER_GROUP'); + +insert into group_permission(id, member_groups_id, permission_id) values(1, 1, 1); +insert into group_permission(id, member_groups_id, permission_id) values(2, 1, 2); +insert into group_permission(id, member_groups_id, permission_id) values(3, 2, 2); + +insert into member(id, name, email, point, member_groups_id) +values(1, 'test', 'test@test', 10000000, 1); diff --git a/docker-compose.yml b/docker-compose.yml index 87182ea..ccf9dbe 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,21 +1,21 @@ version: '3' services: - # mysql: - # image: mysql:latest - # container_name: bingterpark - # restart: always - # environment: - # MYSQL_ROOT_PASSWORD: root1234! - # MYSQL_DATABASE: bingterpark - # MYSQL_CHARSET: utf8mb4 - # MYSQL_COLLATION: utf8mb4_unicode_ci - # ports: - # - "3307:3306" - # volumes: - # - ./data/:/var/lib/mysql - # - ./db/conf.d:/etc/mysql/conf.d - # - ./db/initdb.d:/docker-entrypoint-initdb.d + mysql: + image: mysql:latest + container_name: daldal_rdb + restart: always + environment: + MYSQL_ROOT_PASSWORD: root1234! + MYSQL_DATABASE: daldal_rdb + MYSQL_CHARSET: utf8mb4 + MYSQL_COLLATION: utf8mb4_unicode_ci + ports: + - "3307:3306" + volumes: + - ./data/:/var/lib/mysql + - ./db/conf.d:/etc/mysql/conf.d + - ./db/initdb.d:/docker-entrypoint-initdb.d redis: image: redis:latest