Skip to content

Commit

Permalink
v3.1.0 (#931)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sangwook02 authored Feb 23, 2025
2 parents 63b0a6d + d211311 commit b501c89
Show file tree
Hide file tree
Showing 27 changed files with 471 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
import com.gdschongik.gdsc.domain.coupon.util.CouponNameUtil;
import com.gdschongik.gdsc.domain.member.dao.MemberRepository;
import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.dao.StudyHistoryRepository;
import com.gdschongik.gdsc.domain.study.dao.StudyRepository;
import com.gdschongik.gdsc.domain.study.domain.Study;
import com.gdschongik.gdsc.domain.study.domain.StudyHistory;
import com.gdschongik.gdsc.domain.studyv2.dao.StudyHistoryV2Repository;
import com.gdschongik.gdsc.domain.studyv2.dao.StudyV2Repository;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyHistoryV2;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyV2;
import com.gdschongik.gdsc.global.exception.CustomException;
import com.gdschongik.gdsc.global.util.MemberUtil;
import java.util.Arrays;
Expand All @@ -42,15 +42,15 @@ public class CouponService {

private final CouponNameUtil couponNameUtil;
private final MemberUtil memberUtil;
private final StudyHistoryRepository studyHistoryRepository;
private final StudyRepository studyRepository;
private final StudyHistoryV2Repository studyHistoryRepository;
private final StudyV2Repository studyRepository;
private final CouponRepository couponRepository;
private final IssuedCouponRepository issuedCouponRepository;
private final MemberRepository memberRepository;

@Transactional
public void createCoupon(CouponCreateRequest request) {
Optional<Study> study = Optional.ofNullable(request.studyId()).flatMap(studyRepository::findById);
Optional<StudyV2> study = Optional.ofNullable(request.studyId()).flatMap(studyRepository::findById);
Coupon coupon = Coupon.createManual(
request.name(), Money.from(request.discountAmount()), request.couponType(), study.orElse(null));
couponRepository.save(coupon);
Expand Down Expand Up @@ -105,12 +105,12 @@ public List<IssuedCouponResponse> findMyUsableIssuedCoupons() {

@Transactional
public void createAndIssueCouponByStudyHistories(List<Long> studyHistoryIds) {
List<StudyHistory> studyHistories = studyHistoryRepository.findAllById(studyHistoryIds);
List<StudyHistoryV2> studyHistories = studyHistoryRepository.findAllById(studyHistoryIds);
List<Long> studentIds = studyHistories.stream()
.map(studyHistory -> studyHistory.getStudent().getId())
.toList();
List<Member> students = memberRepository.findAllById(studentIds);
Study study = studyHistories.get(0).getStudy();
StudyV2 study = studyHistories.get(0).getStudy();

Coupon coupon = findOrCreate(STUDY_COMPLETION, study);

Expand All @@ -124,7 +124,7 @@ public void createAndIssueCouponByStudyHistories(List<Long> studyHistoryIds) {
issuedCoupons.stream().map(IssuedCoupon::getId).toList());
}

private Coupon findOrCreate(CouponType couponType, Study study) {
private Coupon findOrCreate(CouponType couponType, StudyV2 study) {
return couponRepository.findByCouponTypeAndStudy(couponType, study).orElseGet(() -> {
String couponName = couponNameUtil.generateStudyCompletionCouponName(study);
Coupon coupon = Coupon.createAutomatic(couponName, Money.FIVE_THOUSAND, couponType, study);
Expand All @@ -134,7 +134,7 @@ private Coupon findOrCreate(CouponType couponType, Study study) {

@Transactional
public void revokeStudyCompletionCouponByStudyHistoryId(long studyHistoryId) {
StudyHistory studyHistory = studyHistoryRepository
StudyHistoryV2 studyHistory = studyHistoryRepository
.findById(studyHistoryId)
.orElseThrow(() -> new CustomException(STUDY_HISTORY_NOT_FOUND));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import com.gdschongik.gdsc.domain.coupon.domain.Coupon;
import com.gdschongik.gdsc.domain.coupon.domain.CouponType;
import com.gdschongik.gdsc.domain.study.domain.Study;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyV2;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CouponRepository extends JpaRepository<Coupon, Long> {
Optional<Coupon> findByCouponTypeAndStudy(CouponType couponType, Study study);
Optional<Coupon> findByCouponTypeAndStudy(CouponType couponType, StudyV2 study);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.gdschongik.gdsc.domain.coupon.domain.IssuedCoupon;
import com.gdschongik.gdsc.domain.coupon.dto.request.IssuedCouponQueryOption;
import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.domain.Study;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyV2;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
Expand All @@ -13,5 +13,5 @@ public interface IssuedCouponCustomRepository {

Page<IssuedCoupon> findAllIssuedCoupons(IssuedCouponQueryOption queryOption, Pageable pageable);

Optional<IssuedCoupon> findUnrevokedIssuedStudyCoupon(CouponType couponType, Member member, Study study);
Optional<IssuedCoupon> findUnrevokedIssuedStudyCoupon(CouponType couponType, Member member, StudyV2 study);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import com.gdschongik.gdsc.domain.coupon.domain.IssuedCoupon;
import com.gdschongik.gdsc.domain.coupon.dto.request.IssuedCouponQueryOption;
import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.domain.Study;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyV2;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
Expand Down Expand Up @@ -39,7 +39,7 @@ public Page<IssuedCoupon> findAllIssuedCoupons(IssuedCouponQueryOption queryOpti
}

@Override
public Optional<IssuedCoupon> findUnrevokedIssuedStudyCoupon(CouponType couponType, Member member, Study study) {
public Optional<IssuedCoupon> findUnrevokedIssuedStudyCoupon(CouponType couponType, Member member, StudyV2 study) {
return Optional.ofNullable(queryFactory
.selectFrom(issuedCoupon)
.leftJoin(issuedCoupon.coupon, coupon)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import com.gdschongik.gdsc.domain.common.model.BaseEntity;
import com.gdschongik.gdsc.domain.common.vo.Money;
import com.gdschongik.gdsc.domain.study.domain.Study;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyV2;
import com.gdschongik.gdsc.global.exception.CustomException;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
Expand All @@ -26,7 +26,7 @@

@Getter
@Entity
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"coupon_type", "study_id"})})
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"coupon_type", "study_v2_id"})})
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Coupon extends BaseEntity {

Expand All @@ -47,19 +47,19 @@ public class Coupon extends BaseEntity {
private IssuanceType issuanceType;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "study_id")
private Study study;
@JoinColumn(name = "study_v2_id")
private StudyV2 study;

@Builder(access = AccessLevel.PRIVATE)
private Coupon(String name, Money discountAmount, CouponType couponType, IssuanceType issuanceType, Study study) {
private Coupon(String name, Money discountAmount, CouponType couponType, IssuanceType issuanceType, StudyV2 study) {
this.name = name;
this.discountAmount = discountAmount;
this.couponType = couponType;
this.issuanceType = issuanceType;
this.study = study;
}

public static Coupon createAutomatic(String name, Money discountAmount, CouponType couponType, Study study) {
public static Coupon createAutomatic(String name, Money discountAmount, CouponType couponType, StudyV2 study) {
validateDiscountAmountPositive(discountAmount);
return Coupon.builder()
.name(name)
Expand All @@ -70,7 +70,7 @@ public static Coupon createAutomatic(String name, Money discountAmount, CouponTy
.build();
}

public static Coupon createManual(String name, Money discountAmount, CouponType couponType, Study study) {
public static Coupon createManual(String name, Money discountAmount, CouponType couponType, StudyV2 study) {
validateDiscountAmountPositive(discountAmount);
return Coupon.builder()
.name(name)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.gdschongik.gdsc.domain.coupon.util;

import com.gdschongik.gdsc.domain.study.domain.Study;
import com.gdschongik.gdsc.domain.common.vo.Semester;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyV2;
import com.gdschongik.gdsc.global.util.formatter.SemesterFormatter;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
Expand All @@ -9,8 +10,10 @@
@RequiredArgsConstructor
public class CouponNameUtil {

public String generateStudyCompletionCouponName(Study study) {
String academicYearAndSemesterName = SemesterFormatter.format(study);
public String generateStudyCompletionCouponName(StudyV2 study) {
Semester semester = study.getSemester();
String academicYearAndSemesterName =
SemesterFormatter.format(semester.getAcademicYear(), semester.getSemesterType());
return academicYearAndSemesterName + " " + study.getTitle() + " 수료 쿠폰";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.gdschongik.gdsc.domain.studyv2.api;

import com.gdschongik.gdsc.domain.study.dto.request.OutstandingStudentRequest;
import com.gdschongik.gdsc.domain.studyv2.application.MentorStudyAchievementServiceV2;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "Mentor StudyAchievement V2", description = "멘토 스터디 우수 스터디원 관리 V2 API입니다.")
@RestController
@RequestMapping("/v2/mentor/study-achievements")
@RequiredArgsConstructor
public class MentorStudyAchievementControllerV2 {

private final MentorStudyAchievementServiceV2 mentorStudyAchievementService;

@Operation(summary = "우수 스터디원 지정", description = "우수 스터디원으로 지정합니다.")
@PostMapping
public ResponseEntity<Void> designateOutstandingStudent(
@RequestParam(name = "studyId") Long studyId, @RequestBody OutstandingStudentRequest request) {
mentorStudyAchievementService.designateOutstandingStudent(studyId, request);
return ResponseEntity.ok().build();
}

@Operation(summary = "우수 스터디원 철회", description = "우수 스터디원 지정을 철회합니다.")
@DeleteMapping
public ResponseEntity<Void> withdrawOutstandingStudent(
@RequestParam(name = "studyId") Long studyId, @RequestBody OutstandingStudentRequest request) {
mentorStudyAchievementService.withdrawOutstandingStudent(studyId, request);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.gdschongik.gdsc.domain.studyv2.api;

import com.gdschongik.gdsc.domain.studyv2.application.StudentStudyHistoryServiceV2;
import com.gdschongik.gdsc.domain.studyv2.dto.request.StudyHistoryRepositoryUpdateRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "Student Study History V2", description = "학생 스터디 수강이력 API입니다.")
@RestController
@RequestMapping("/v2/study-histories")
@RequiredArgsConstructor
public class StudentStudyHistoryControllerV2 {

private final StudentStudyHistoryServiceV2 studentStudyHistoryServiceV2;

@Operation(summary = "내 레포지토리 입력", description = "나의 과제 제출 레포지토리를 입력합니다.")
@PutMapping("/repositories/me")
public ResponseEntity<Void> updateMyRepository(@Valid @RequestBody StudyHistoryRepositoryUpdateRequest request) {
studentStudyHistoryServiceV2.updateMyRepository(request);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.gdschongik.gdsc.domain.studyv2.application;

import static com.gdschongik.gdsc.global.exception.ErrorCode.*;

import com.gdschongik.gdsc.domain.member.dao.MemberRepository;
import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.dto.request.OutstandingStudentRequest;
import com.gdschongik.gdsc.domain.studyv2.dao.StudyAchievementV2Repository;
import com.gdschongik.gdsc.domain.studyv2.dao.StudyHistoryV2Repository;
import com.gdschongik.gdsc.domain.studyv2.dao.StudyV2Repository;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyAchievementV2;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyAchievementValidatorV2;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyHistoryValidatorV2;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyV2;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyValidatorV2;
import com.gdschongik.gdsc.global.exception.CustomException;
import com.gdschongik.gdsc.global.util.MemberUtil;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
public class MentorStudyAchievementServiceV2 {

private final MemberUtil memberUtil;
private final StudyValidatorV2 studyValidator;
private final StudyHistoryValidatorV2 studyHistoryValidator;
private final StudyAchievementValidatorV2 studyAchievementValidator;
private final StudyV2Repository studyRepository;
private final StudyHistoryV2Repository studyHistoryRepository;
private final StudyAchievementV2Repository studyAchievementRepository;
private final MemberRepository memberRepository;

@Transactional
public void designateOutstandingStudent(Long studyId, OutstandingStudentRequest request) {
Member currentMember = memberUtil.getCurrentMember();
StudyV2 study = studyRepository.findById(studyId).orElseThrow(() -> new CustomException(STUDY_NOT_FOUND));
studyValidator.validateStudyMentor(currentMember, study);

long studyHistoryCount = studyHistoryRepository.countByStudyIdAndStudentIds(studyId, request.studentIds());
studyHistoryValidator.validateAppliedToStudy(
studyHistoryCount, request.studentIds().size());

long studyAchievementsAlreadyExistCount =
studyAchievementRepository.countByStudyIdAndAchievementTypeAndStudentIds(
studyId, request.achievementType(), request.studentIds());
studyAchievementValidator.validateDesignateOutstandingStudent(studyAchievementsAlreadyExistCount);

List<Member> outstandingStudents = memberRepository.findAllById(request.studentIds());
List<StudyAchievementV2> studyAchievements = outstandingStudents.stream()
.map(member -> StudyAchievementV2.create(request.achievementType(), member, study))
.toList();
studyAchievementRepository.saveAll(studyAchievements);

log.info(
"[MentorStudyAchievementServiceV2] 우수 스터디원 지정: studyId={}, studentIds={}",
studyId,
request.studentIds());
}

@Transactional
public void withdrawOutstandingStudent(Long studyId, OutstandingStudentRequest request) {
Member currentMember = memberUtil.getCurrentMember();
StudyV2 study = studyRepository.findById(studyId).orElseThrow(() -> new CustomException(STUDY_NOT_FOUND));
studyValidator.validateStudyMentor(currentMember, study);

long studyHistoryCount = studyHistoryRepository.countByStudyIdAndStudentIds(studyId, request.studentIds());
studyHistoryValidator.validateAppliedToStudy(
studyHistoryCount, request.studentIds().size());

studyAchievementRepository.deleteByStudyAndAchievementTypeAndMemberIds(
studyId, request.achievementType(), request.studentIds());

log.info(
"[MentorStudyAchievementServiceV2] 우수 스터디원 철회: studyId={}, studentIds={}",
studyId,
request.studentIds());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.gdschongik.gdsc.domain.studyv2.application;

import static com.gdschongik.gdsc.global.exception.ErrorCode.*;

import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.studyv2.dao.StudyHistoryV2Repository;
import com.gdschongik.gdsc.domain.studyv2.dao.StudyV2Repository;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyHistoryV2;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyHistoryValidatorV2;
import com.gdschongik.gdsc.domain.studyv2.domain.StudyV2;
import com.gdschongik.gdsc.domain.studyv2.dto.request.StudyHistoryRepositoryUpdateRequest;
import com.gdschongik.gdsc.global.exception.CustomException;
import com.gdschongik.gdsc.global.util.MemberUtil;
import com.gdschongik.gdsc.infra.github.client.GithubClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
public class StudentStudyHistoryServiceV2 {

private final GithubClient githubClient;
private final MemberUtil memberUtil;
private final StudyV2Repository studyV2Repository;
private final StudyHistoryV2Repository studyHistoryV2Repository;
private final StudyHistoryValidatorV2 studyHistoryValidatorV2;

@Transactional
public void updateMyRepository(StudyHistoryRepositoryUpdateRequest request) {
Member currentMember = memberUtil.getCurrentMember();
StudyV2 study =
studyV2Repository.findById(request.studyId()).orElseThrow(() -> new CustomException(STUDY_NOT_FOUND));
StudyHistoryV2 studyHistory = studyHistoryV2Repository
.findByStudentAndStudy(currentMember, study)
.orElseThrow(() -> new CustomException(STUDY_HISTORY_NOT_FOUND));
String repositoryOwnerId = githubClient.getOwnerId(request.repositoryLink());

studyHistoryValidatorV2.validateUpdateRepository(repositoryOwnerId, currentMember);

studyHistory.updateRepositoryLink(request.repositoryLink());
studyHistoryV2Repository.save(studyHistory);

log.info(
"[StudentStudyHistoryServiceV2] 내 레포지토리 입력 완료: studyHistoryId={}, repositoryLink={}",
studyHistory.getId(),
request.repositoryLink());
}
}
Loading

0 comments on commit b501c89

Please sign in to comment.