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 @@ -20,10 +20,10 @@ public interface ClubRecruitmentApi {

@Operation(summary = "동아리 모집 정보를 조회한다.", description = """
동아리의 모집 공고 상세 정보를 조회합니다.

- status는 모집 기간에 따라 BEFORE(모집 전), ONGOING(모집 중), CLOSED(모집 마감)으로 반환됩니다.
- 동아리 멤버이거나 지원 이력이 존재할 경우 isApplied는 true로 반환됩니다.

## 에러
- NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다.
- NOT_FOUND_USER (404): 유저를 찾을 수 없습니다.
Expand All @@ -39,6 +39,7 @@ ResponseEntity<ClubRecruitmentResponse> getRecruitments(
요청 값을 기준으로 동아리 모집 공고를 저장합니다.
- 모집 공고가 없으면 생성
- 모집 공고가 있으면 수정

## 에러
- INVALID_RECRUITMENT_DATE_NOT_ALLOWED (400): 상시 모집인 경우 모집 시작일과 마감일을 지정할 수 없습니다.
- INVALID_RECRUITMENT_DATE_REQUIRED (400): 상시 모집이 아닐 경우 모집 시작일과 마감일이 필수입니다.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package gg.agit.konect.domain.club.dto;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED;
import java.time.LocalDate;

import com.fasterxml.jackson.annotation.JsonFormat;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
Expand All @@ -27,8 +25,8 @@ public record ClubFeeInfoReplaceRequest(
@Schema(description = "예금주", example = "BCSD", requiredMode = NOT_REQUIRED)
String accountHolder,

@Schema(description = "납부 기한", example = "2025.12.31", requiredMode = NOT_REQUIRED)
@JsonFormat(pattern = "yyyy.MM.dd")
LocalDate deadLine
@NotNull(message = "회비 납부 필요 여부는 필수로 입력해야 합니다.")
@Schema(description = "회비 납부 필요 여부", example = "true", requiredMode = REQUIRED)
Boolean isFeeRequired
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import java.time.LocalDate;

import com.fasterxml.jackson.annotation.JsonFormat;

import gg.agit.konect.domain.club.model.Club;
import io.swagger.v3.oas.annotations.media.Schema;

Expand All @@ -22,17 +18,16 @@ public record ClubFeeInfoResponse(
@Schema(description = "예금주", example = "BCSD", requiredMode = REQUIRED)
String accountHolder,

@Schema(description = "납부 기한", example = "2025.12.31", requiredMode = REQUIRED)
@JsonFormat(pattern = "yyyy.MM.dd")
LocalDate deadLine
@Schema(description = "회비 납부 필요 여부", example = "true", requiredMode = REQUIRED)
Boolean isFeeRequired
) {
public static ClubFeeInfoResponse from(Club club) {
return new ClubFeeInfoResponse(
club.getFeeAmount(),
club.getFeeBank(),
club.getFeeAccountNumber(),
club.getFeeAccountHolder(),
club.getFeeDeadline()
club.getIsFeeRequired()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ public record ClubRecruitmentResponse(
@Schema(description = "모집 공고 이미지 리스트", requiredMode = REQUIRED)
List<InnerRecruitmentImage> images,

@Schema(description = "회비 납부 필요 여부", example = "true", requiredMode = REQUIRED)
Boolean isFeeRequired,

@Schema(description = "지원 여부", example = "false", requiredMode = REQUIRED)
Boolean isApplied
) {
Expand All @@ -63,7 +60,6 @@ public static ClubRecruitmentResponse of(ClubRecruitment recruitment, Boolean is
recruitment.getImages().stream()
.map(InnerRecruitmentImage::from)
.toList(),
recruitment.getIsFeeRequired(),
isApplied
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ public record ClubRecruitmentUpsertRequest(
@Schema(description = "상시 모집 여부", example = "false", requiredMode = REQUIRED)
Boolean isAlwaysRecruiting,

@NotNull(message = "회비 납부 필요 여부는 필수 입력입니다.")
@Schema(description = "회비 납부 필요 여부", example = "true", requiredMode = REQUIRED)
Boolean isFeeRequired,

@NotEmpty(message = "모집 공고 내용은 필수 입력입니다.")
@Schema(description = "모집 공고 내용", example = "BCSD 2025학년도 2학기 신입 부원 모집...", requiredMode = REQUIRED)
String content,
Expand Down
36 changes: 15 additions & 21 deletions src/main/java/gg/agit/konect/domain/club/model/Club.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import static jakarta.persistence.GenerationType.IDENTITY;
import static lombok.AccessLevel.PROTECTED;

import java.time.LocalDate;

import org.springframework.util.StringUtils;

import gg.agit.konect.domain.club.dto.ClubCreateRequest;
Expand Down Expand Up @@ -77,8 +75,8 @@ public class Club extends BaseEntity {
@Column(name = "fee_account_holder", length = 100)
private String feeAccountHolder;

@Column(name = "fee_deadline")
private LocalDate feeDeadline;
@Column(name = "is_fee_required", columnDefinition = "TINYINT(1)")
private Boolean isFeeRequired;

@OneToOne(mappedBy = "club", fetch = LAZY, cascade = ALL, orphanRemoval = true)
private ClubRecruitment clubRecruitment;
Expand All @@ -97,7 +95,7 @@ private Club(
String feeBank,
String feeAccountNumber,
String feeAccountHolder,
LocalDate feeDeadline,
Boolean isFeeRequired,
ClubRecruitment clubRecruitment
) {
this.id = id;
Expand All @@ -112,7 +110,7 @@ private Club(
this.feeBank = feeBank;
this.feeAccountNumber = feeAccountNumber;
this.feeAccountHolder = feeAccountHolder;
this.feeDeadline = feeDeadline;
this.isFeeRequired = isFeeRequired;
this.clubRecruitment = clubRecruitment;
}

Expand All @@ -133,18 +131,18 @@ public void replaceFeeInfo(
String feeBank,
String feeAccountNumber,
String feeAccountHolder,
LocalDate feeDeadline
Boolean isFeeRequired
) {
if (isFeeInfoEmpty(feeAmount, feeBank, feeAccountNumber, feeAccountHolder, feeDeadline)) {
if (isFeeInfoEmpty(feeAmount, feeBank, feeAccountNumber, feeAccountHolder)) {
clearFeeInfo();
return;
}

if (!isFeeInfoComplete(feeAmount, feeBank, feeAccountNumber, feeAccountHolder, feeDeadline)) {
if (!isFeeInfoComplete(feeAmount, feeBank, feeAccountNumber, feeAccountHolder)) {
throw CustomException.of(INVALID_REQUEST_BODY);
}

updateFeeInfo(feeAmount, feeBank, feeAccountNumber, feeAccountHolder, feeDeadline);
updateFeeInfo(feeAmount, feeBank, feeAccountNumber, feeAccountHolder, isFeeRequired);
}

public void updateInfo(String description, String imageUrl, String location, String introduce) {
Expand All @@ -163,49 +161,45 @@ private boolean isFeeInfoEmpty(
Integer feeAmount,
String feeBank,
String feeAccountNumber,
String feeAccountHolder,
LocalDate feeDeadline
String feeAccountHolder
) {
return feeAmount == null
&& feeBank == null
&& feeAccountNumber == null
&& feeAccountHolder == null
&& feeDeadline == null;
&& feeAccountHolder == null;
}

private boolean isFeeInfoComplete(
Integer feeAmount,
String feeBank,
String feeAccountNumber,
String feeAccountHolder,
LocalDate feeDeadline
String feeAccountHolder
) {
return feeAmount != null
&& StringUtils.hasText(feeBank)
&& StringUtils.hasText(feeAccountNumber)
&& StringUtils.hasText(feeAccountHolder)
&& feeDeadline != null;
&& StringUtils.hasText(feeAccountHolder);
}

private void updateFeeInfo(
Integer feeAmount,
String feeBank,
String feeAccountNumber,
String feeAccountHolder,
LocalDate feeDeadline
Boolean isFeeRequired
) {
this.feeAmount = feeAmount;
this.feeBank = feeBank;
this.feeAccountNumber = feeAccountNumber;
this.feeAccountHolder = feeAccountHolder;
this.feeDeadline = feeDeadline;
this.isFeeRequired = isFeeRequired;
}

private void clearFeeInfo() {
this.feeAmount = null;
this.feeBank = null;
this.feeAccountNumber = null;
this.feeAccountHolder = null;
this.feeDeadline = null;
this.isFeeRequired = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ public class ClubRecruitment extends BaseEntity {
@Column(name = "is_always_recruiting", columnDefinition = "TINYINT(1)")
private Boolean isAlwaysRecruiting;

@Column(name = "is_fee_required", nullable = false, columnDefinition = "TINYINT(1)")
private Boolean isFeeRequired;

@OneToOne(fetch = LAZY)
@JoinColumn(name = "club_id", nullable = false, updatable = false)
private Club club;
Expand All @@ -73,23 +70,20 @@ private ClubRecruitment(
LocalDate endDate,
String content,
Boolean isAlwaysRecruiting,
Boolean isFeeRequired,
Club club
) {
this.id = id;
this.startDate = startDate;
this.endDate = endDate;
this.content = content;
this.isAlwaysRecruiting = isAlwaysRecruiting;
this.isFeeRequired = isFeeRequired;
this.club = club;
}

public static ClubRecruitment of(
LocalDate startDate,
LocalDate endDate,
Boolean isAlwaysRecruiting,
Boolean isFeeRequired,
String content,
Club club
) {
Expand All @@ -106,7 +100,6 @@ public static ClubRecruitment of(
.content(content)
.club(club)
.isAlwaysRecruiting(isAlwaysRecruiting)
.isFeeRequired(isFeeRequired)
.build();
}

Expand Down Expand Up @@ -136,7 +129,6 @@ public void update(
LocalDate startDate,
LocalDate endDate,
Boolean isAlwaysRecruiting,
Boolean isFeeRequired,
String content
) {
if (isAlwaysRecruiting) {
Expand All @@ -149,7 +141,6 @@ public void update(
this.startDate = startDate;
this.endDate = endDate;
this.isAlwaysRecruiting = isAlwaysRecruiting;
this.isFeeRequired = isFeeRequired;
this.content = content;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,7 @@ public ClubFeeInfoResponse applyClub(Integer clubId, Integer userId, ClubApplyRe
}

private void validateFeePaymentImage(Club club, String feePaymentImageUrl) {
ClubRecruitment recruitment = clubRecruitmentRepository.findByClubId(club.getId())
.orElse(null);

if (recruitment != null
&& Boolean.TRUE.equals(recruitment.getIsFeeRequired())
if (Boolean.TRUE.equals(club.getIsFeeRequired())
&& !StringUtils.hasText(feePaymentImageUrl)) {
throw CustomException.of(FEE_PAYMENT_IMAGE_REQUIRED);
}
Expand Down Expand Up @@ -341,7 +337,7 @@ public ClubFeeInfoResponse replaceFeeInfo(Integer clubId, Integer userId, ClubFe
bankName,
request.accountNumber(),
request.accountHolder(),
request.deadLine()
request.isFeeRequired()
);

return ClubFeeInfoResponse.from(club);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ public void upsertRecruitment(Integer clubId, Integer userId, ClubRecruitmentUps
request.startDate(),
request.endDate(),
request.isAlwaysRecruiting(),
request.isFeeRequired(),
request.content(),
club
));
Expand All @@ -62,14 +61,20 @@ public void upsertRecruitment(Integer clubId, Integer userId, ClubRecruitmentUps
request.startDate(),
request.endDate(),
request.isAlwaysRecruiting(),
request.isFeeRequired(),
request.content()
);

clubRecruitment.getImages().clear();
}

List<String> imageUrls = request.getImageUrls();
addImages(clubRecruitment, request.getImageUrls());

if (clubRecruitment.getId() == null) {
clubRecruitmentRepository.save(clubRecruitment);
}
}

private void addImages(ClubRecruitment clubRecruitment, List<String> imageUrls) {
for (int index = 0; index < imageUrls.size(); index++) {
ClubRecruitmentImage image = ClubRecruitmentImage.of(
imageUrls.get(index),
Expand All @@ -78,9 +83,5 @@ public void upsertRecruitment(Integer clubId, Integer userId, ClubRecruitmentUps
);
clubRecruitment.addImage(image);
}

if (clubRecruitment.getId() == null) {
clubRecruitmentRepository.save(clubRecruitment);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- 회비 납부 기한 컬럼 삭제
ALTER TABLE club DROP COLUMN fee_deadline;

-- 회비 납부 필요 여부를 club 테이블로 이동
ALTER TABLE club ADD COLUMN is_fee_required TINYINT(1) NULL;

-- 기존 데이터 마이그레이션 (club_recruitment -> club)
UPDATE club c
INNER JOIN club_recruitment cr ON c.id = cr.club_id
SET c.is_fee_required = cr.is_fee_required;

-- club_recruitment에서 is_fee_required 컬럼 삭제
ALTER TABLE club_recruitment DROP COLUMN is_fee_required;
9 changes: 0 additions & 9 deletions src/main/resources/db/migration/V27__add_fee_deadline

This file was deleted.