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
17 changes: 4 additions & 13 deletions src/main/java/com/sejong/sejongpeer/domain/study/entity/Study.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import com.sejong.sejongpeer.domain.image.entity.Image;
import com.sejong.sejongpeer.domain.study.entity.type.Frequency;
import com.sejong.sejongpeer.domain.study.entity.type.StudyMethod;
import com.sejong.sejongpeer.domain.studyrelation.entity.StudyRelation;
import jakarta.persistence.*;
import org.hibernate.annotations.Comment;

import com.sejong.sejongpeer.domain.common.BaseAuditEntity;
Expand All @@ -23,18 +23,6 @@
import com.sejong.sejongpeer.global.error.exception.CustomException;
import com.sejong.sejongpeer.global.error.exception.ErrorCode;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
Expand Down Expand Up @@ -117,6 +105,9 @@ public class Study extends BaseAuditEntity {
@OneToMany(mappedBy = "study", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Image> images = new ArrayList<>();

@Version
private Long version;

@Builder(access = AccessLevel.PRIVATE)
private Study(
String title,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public class StudyRelation extends BaseAuditEntity {
@Enumerated(EnumType.STRING)
private StudyMatchingStatus status;

@Version
private Integer version;

@Builder(access = AccessLevel.PRIVATE)
private StudyRelation(Member member, Study study, StudyMatchingStatus status) {
this.member = member;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.sejong.sejongpeer.domain.member.repository.MemberRepository;
import com.sejong.sejongpeer.domain.scrap.application.ScrapService;
Expand All @@ -13,6 +14,8 @@
import com.sejong.sejongpeer.domain.study.entity.type.StudyType;
import com.sejong.sejongpeer.domain.studyrelation.dto.request.StudyMatchingRequest;
import com.sejong.sejongpeer.global.util.SecurityUtil;
import jakarta.persistence.OptimisticLockException;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -84,60 +87,74 @@ private void sendStudyApplicantAlarmToStudyWriter(StudyRelation newStudyApplicai
smsService.sendSms(newStudyApplicaitonHistory.getStudy().getMember().getPhoneNumber(), SmsText.STUDY_APPLY_ALARM);
}

@Transactional
public void deleteStudyApplicationHistory(final Long studyId) {
final String loginMemberId = securityUtil.getCurrentMemberId();

StudyRelation studyApplicationHistory = studyRelationRepository.findTopByMemberIdAndStudyIdOrderByIdDesc(loginMemberId, studyId)
.orElseThrow(() -> new CustomException(ErrorCode.STUDY_RELATION_NOT_FOUND));

studyApplicationHistory.registerCanceledAt(LocalDateTime.now());
studyApplicationHistory.changeStudyMatchingStatus(StudyMatchingStatus.CANCEL);
studyRelationRepository.save(studyApplicationHistory);

for (int attempt = 0; attempt < 3; attempt++) {
try {
StudyRelation studyApplicationHistory = studyRelationRepository.findTopByMemberIdAndStudyIdOrderByIdDesc(loginMemberId, studyId)
.orElseThrow(() -> new CustomException(ErrorCode.STUDY_RELATION_NOT_FOUND));

studyApplicationHistory.registerCanceledAt(LocalDateTime.now());
studyApplicationHistory.changeStudyMatchingStatus(StudyMatchingStatus.CANCEL);
studyRelationRepository.save(studyApplicationHistory);
return;
} catch (OptimisticLockException e) {
if (attempt == 2) {
throw new CustomException(ErrorCode.CONCURRENT_UPDATE_CONFLICT);
}
}
}
}

@Transactional
public Map<String, Boolean> updateStudyMatchingStatus(StudyMatchingRequest request) {
Member studyApplicant = memberRepository.findByNickname(request.applicantNickname())
.orElseThrow(() -> new CustomException(ErrorCode.NICKNAME_IS_NULL));

StudyRelation studyResume = studyRelationRepository.findTopByMemberIdAndStudyIdOrderByIdDesc(studyApplicant.getId(), request.studyId())
.orElseThrow(() -> new CustomException(ErrorCode.STUDY_APPLY_HISTORY_NOT_FOUND));

boolean isFulleApplication = false;
boolean isFullApplication = false;
Map<String, Boolean> response = new HashMap<>();

if (studyResume.getStatus().equals(StudyMatchingStatus.CANCEL)) {
throw new CustomException(ErrorCode.INVALID_STUDY_MATHCING_STATUS_UPDATE_CONDITION);
}
try {
Member studyApplicant = memberRepository.findByNickname(request.applicantNickname())
.orElseThrow(() -> new CustomException(ErrorCode.NICKNAME_IS_NULL));

Study appliedStudy = studyResume.getStudy();
StudyRelation studyResume = studyRelationRepository.findTopByMemberIdAndStudyIdOrderByIdDesc(studyApplicant.getId(), request.studyId())
.orElseThrow(() -> new CustomException(ErrorCode.STUDY_APPLY_HISTORY_NOT_FOUND));

if (request.isAccept()) {
if (appliedStudy.getRecruitmentCount() <= appliedStudy.getParticipantsCount()) {
throw new CustomException(ErrorCode.STUDY_APPLICANT_CANNOT_BE_ACCEPTED);

if (studyResume.getStatus().equals(StudyMatchingStatus.CANCEL)) {
throw new CustomException(ErrorCode.INVALID_STUDY_MATHCING_STATUS_UPDATE_CONDITION);
}

studyResume.changeStudyMatchingStatus(StudyMatchingStatus.ACCEPT);
appliedStudy.addParticipantsCount();
studyRepository.save(appliedStudy);
Study appliedStudy = studyResume.getStudy();

if (request.isAccept()) {
if (appliedStudy.getRecruitmentCount() <= appliedStudy.getParticipantsCount()) {
throw new CustomException(ErrorCode.STUDY_APPLICANT_CANNOT_BE_ACCEPTED);
}

if (appliedStudy.getRecruitmentCount() <= appliedStudy.getParticipantsCount()) {
appliedStudy.changeStudyRecruitmentStatus(RecruitmentStatus.CLOSED);
studyResume.changeStudyMatchingStatus(StudyMatchingStatus.ACCEPT);
appliedStudy.addParticipantsCount();
studyRepository.save(appliedStudy);

List<StudyRelation> appliedStudyHistory = studyRelationRepository.findAllByStudyAndStatus(appliedStudy, StudyMatchingStatus.ACCEPT);
appliedStudyHistory.forEach(this::sendStudyKakaoLink);
if (appliedStudy.getRecruitmentCount() <= appliedStudy.getParticipantsCount()) {
appliedStudy.changeStudyRecruitmentStatus(RecruitmentStatus.CLOSED);
studyRepository.save(appliedStudy);

isFulleApplication = true;
}
} else {
studyResume.changeStudyMatchingStatus(StudyMatchingStatus.REJECT);
sendStudyRejectAlarmToStudyApplicant(studyResume);
}
List<StudyRelation> appliedStudyHistory = studyRelationRepository.findAllByStudyAndStatus(appliedStudy, StudyMatchingStatus.ACCEPT);
appliedStudyHistory.forEach(this::sendStudyKakaoLink);

studyRelationRepository.save(studyResume);
response.put("isFull", isFulleApplication);
isFullApplication = true;
}
} else {
studyResume.changeStudyMatchingStatus(StudyMatchingStatus.REJECT);
sendStudyRejectAlarmToStudyApplicant(studyResume);
}

studyRelationRepository.save(studyResume);
response.put("isFull", isFullApplication);
} catch (ObjectOptimisticLockingFailureException | OptimisticLockException e) {
throw new CustomException(ErrorCode.CONCURRENT_UPDATE_CONFLICT);
}
return response;
}

Expand Down Expand Up @@ -198,20 +215,19 @@ public List<AppliedStudyResponse> getAppliedStudies() {

studyRelations.sort((sr1, sr2) -> sr2.getStudy().getId().compareTo(sr1.getStudy().getId()));

List<AppliedStudyResponse> list = new ArrayList<>();
studyRelations.stream()
.forEach(studyRelation -> {
if(!studyRelation.getStatus().equals(StudyMatchingStatus.CANCEL)) {
Study study = studyRelation.getStudy();
return studyRelations.stream()
.filter(studyRelation -> !studyRelation.getStatus().equals(StudyMatchingStatus.CANCEL))
.map(studyRelation -> {
Study study = studyRelation.getStudy();

Long scrapCount = scrapService.getScrapCountByStudyPost(study.getId());
List<String> tags = tagService.getTagsNameByStudy(study);
boolean hasMemberScrappedStudy = scrapService.hasMemberScrappedStudy(loginMember, study);
Long scrapCount = scrapService.getScrapCountByStudyPost(study.getId());
List<String> tags = tagService.getTagsNameByStudy(study);
boolean hasMemberScrappedStudy = scrapService.hasMemberScrappedStudy(loginMember, study);

list.add(AppliedStudyResponse.of(study, tags, scrapCount, hasMemberScrappedStudy));
}
});
return list;
return AppliedStudyResponse.of(study, tags, scrapCount, hasMemberScrappedStudy);

})
.collect(Collectors.toList());
}

public Map<String, List<StudyApplicantsListRespone>> getApplicatnsList() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public enum ErrorCode {
CANNOT_REAPPLY_WITHIN_AN_HOUR(HttpStatus.FORBIDDEN, "스터디 게시글을 지원했다가 취소한 유저는 일정시간 동안 같은 스터디를 지원할 수 없습니다."),
INVALID_STUDY_MATHCING_STATUS_UPDATE_CONDITION(HttpStatus.BAD_REQUEST, "지원을 취소한 경우 수락/거절 처리를 할 수 없습니다."),
STUDY_APPLICANT_CANNOT_BE_ACCEPTED(HttpStatus.BAD_REQUEST, "해당 스터디 게시글의 모집 인원까지만 지원자를 수락할 수 있습니다."),
CONCURRENT_UPDATE_CONFLICT(HttpStatus.CONFLICT, "이미 사용자의 지원 상태가 변경되었습니다."),

// Lecture
LECTURE_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 강의를 찾을 수 없습니다."),
Expand Down