Skip to content

Commit 8b2d645

Browse files
authored
feat: 모집글 시간 필드 추가 (#269)
* refactor(recruit-board): 봉사 시간 필드 추가 - volunteer_hours * test(recruit-board): 봉사 시간 필드 추가에 따른 테스트 - volunteer_hours * feat(recruit-board): 모집글 Validator 추가 * test(recruit-board): 모집글 Validator 추가에 따른 테스트 * refactor(recruit-board): 모집글 Validator 추가에 따른 리팩토링 * test(recruit-board): 모집글 Validator 추가에 따른 리팩토링 테스트 * refactor(recruit-board): 모집글 조회시 QueryUseCase 의존하도록 리팩토링 * refactor(recruit-board): 패키지 구조 변경(query, command 패키지 제거) * chore(recruit-board): sonarqube 이슈 해결 * refactor(recruit-board): 봉사 시간 타입 변경 - Integer -> int * fix(recruit-board): 오타 해결 * refactor: 메서드명 변경 - isAuthor -> isWriter
1 parent 0f09e27 commit 8b2d645

File tree

51 files changed

+514
-623
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+514
-623
lines changed

src/main/java/com/somemore/domains/recruitboard/controller/RecruitBoardCommandApiController.java

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,30 @@
11
package com.somemore.domains.recruitboard.controller;
22

33

4-
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
5-
4+
import com.somemore.domains.recruitboard.dto.request.RecruitBoardCreateRequestDto;
5+
import com.somemore.domains.recruitboard.dto.request.RecruitBoardLocationUpdateRequestDto;
6+
import com.somemore.domains.recruitboard.dto.request.RecruitBoardStatusUpdateRequestDto;
67
import com.somemore.domains.recruitboard.dto.request.RecruitBoardUpdateRequestDto;
7-
import com.somemore.domains.recruitboard.usecase.command.CreateRecruitBoardUseCase;
8-
import com.somemore.domains.recruitboard.usecase.command.DeleteRecruitBoardUseCase;
9-
import com.somemore.domains.recruitboard.usecase.command.UpdateRecruitBoardUseCase;
8+
import com.somemore.domains.recruitboard.usecase.CreateRecruitBoardUseCase;
9+
import com.somemore.domains.recruitboard.usecase.DeleteRecruitBoardUseCase;
10+
import com.somemore.domains.recruitboard.usecase.UpdateRecruitBoardUseCase;
1011
import com.somemore.global.auth.annotation.CurrentUser;
1112
import com.somemore.global.common.response.ApiResponse;
1213
import com.somemore.global.imageupload.dto.ImageUploadRequestDto;
1314
import com.somemore.global.imageupload.usecase.ImageUploadUseCase;
14-
import com.somemore.domains.recruitboard.dto.request.RecruitBoardCreateRequestDto;
15-
import com.somemore.domains.recruitboard.dto.request.RecruitBoardLocationUpdateRequestDto;
16-
import com.somemore.domains.recruitboard.dto.request.RecruitBoardStatusUpdateRequestDto;
1715
import io.swagger.v3.oas.annotations.Operation;
1816
import io.swagger.v3.oas.annotations.tags.Tag;
1917
import jakarta.validation.Valid;
20-
import java.time.LocalDateTime;
21-
import java.util.UUID;
2218
import lombok.RequiredArgsConstructor;
2319
import org.springframework.security.access.annotation.Secured;
24-
import org.springframework.web.bind.annotation.DeleteMapping;
25-
import org.springframework.web.bind.annotation.PatchMapping;
26-
import org.springframework.web.bind.annotation.PathVariable;
27-
import org.springframework.web.bind.annotation.PostMapping;
28-
import org.springframework.web.bind.annotation.PutMapping;
29-
import org.springframework.web.bind.annotation.RequestBody;
30-
import org.springframework.web.bind.annotation.RequestMapping;
31-
import org.springframework.web.bind.annotation.RequestPart;
32-
import org.springframework.web.bind.annotation.RestController;
20+
import org.springframework.web.bind.annotation.*;
3321
import org.springframework.web.multipart.MultipartFile;
3422

23+
import java.time.LocalDateTime;
24+
import java.util.UUID;
25+
26+
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
27+
3528
@Tag(name = "Recruit Board Command API", description = "봉사 활동 모집글 생성 수정 삭제 API")
3629
@RequiredArgsConstructor
3730
@RequestMapping("/api")

src/main/java/com/somemore/domains/recruitboard/controller/RecruitBoardQueryApiController.java

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
11
package com.somemore.domains.recruitboard.controller;
22

3-
import static org.springframework.data.domain.Sort.Direction.DESC;
4-
5-
import com.somemore.domains.recruitboard.dto.condition.RecruitBoardNearByCondition;
6-
import com.somemore.domains.recruitboard.dto.condition.RecruitBoardSearchCondition;
7-
import com.somemore.domains.recruitboard.usecase.query.RecruitBoardQueryUseCase;
8-
import com.somemore.global.common.response.ApiResponse;
93
import com.somemore.domains.recruitboard.domain.RecruitStatus;
104
import com.somemore.domains.recruitboard.domain.VolunteerCategory;
5+
import com.somemore.domains.recruitboard.dto.condition.RecruitBoardNearByCondition;
6+
import com.somemore.domains.recruitboard.dto.condition.RecruitBoardSearchCondition;
117
import com.somemore.domains.recruitboard.dto.response.RecruitBoardDetailResponseDto;
128
import com.somemore.domains.recruitboard.dto.response.RecruitBoardResponseDto;
139
import com.somemore.domains.recruitboard.dto.response.RecruitBoardWithCenterResponseDto;
1410
import com.somemore.domains.recruitboard.dto.response.RecruitBoardWithLocationResponseDto;
11+
import com.somemore.domains.recruitboard.usecase.RecruitBoardQueryUseCase;
12+
import com.somemore.global.common.response.ApiResponse;
1513
import io.swagger.v3.oas.annotations.Operation;
1614
import io.swagger.v3.oas.annotations.tags.Tag;
17-
import java.util.UUID;
1815
import lombok.RequiredArgsConstructor;
1916
import org.springframework.data.domain.Page;
2017
import org.springframework.data.domain.Pageable;
2118
import org.springframework.data.web.PageableDefault;
22-
import org.springframework.web.bind.annotation.GetMapping;
23-
import org.springframework.web.bind.annotation.PathVariable;
24-
import org.springframework.web.bind.annotation.RequestMapping;
25-
import org.springframework.web.bind.annotation.RequestParam;
26-
import org.springframework.web.bind.annotation.RestController;
19+
import org.springframework.web.bind.annotation.*;
20+
21+
import java.util.UUID;
22+
23+
import static org.springframework.data.domain.Sort.Direction.DESC;
2724

2825
@Tag(name = "Recruit Board Query API", description = "봉사 활동 모집 조회 관련 API")
2926
@RequiredArgsConstructor

src/main/java/com/somemore/domains/recruitboard/domain/RecruitBoard.java

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,19 @@
11
package com.somemore.domains.recruitboard.domain;
22

3-
import static jakarta.persistence.EnumType.STRING;
4-
import static jakarta.persistence.GenerationType.IDENTITY;
5-
import static lombok.AccessLevel.PROTECTED;
6-
73
import com.somemore.domains.recruitboard.dto.request.RecruitBoardUpdateRequestDto;
84
import com.somemore.global.common.entity.BaseEntity;
9-
import jakarta.persistence.Column;
10-
import jakarta.persistence.Embedded;
11-
import jakarta.persistence.Entity;
12-
import jakarta.persistence.Enumerated;
13-
import jakarta.persistence.GeneratedValue;
14-
import jakarta.persistence.Id;
15-
import jakarta.persistence.Lob;
16-
import jakarta.persistence.Table;
17-
import java.time.LocalDateTime;
18-
import java.time.LocalTime;
19-
import java.util.UUID;
5+
import jakarta.persistence.*;
206
import lombok.Builder;
217
import lombok.Getter;
228
import lombok.NoArgsConstructor;
239

10+
import java.time.LocalDateTime;
11+
import java.util.UUID;
12+
13+
import static jakarta.persistence.EnumType.STRING;
14+
import static jakarta.persistence.GenerationType.IDENTITY;
15+
import static lombok.AccessLevel.PROTECTED;
16+
2417
@Getter
2518
@NoArgsConstructor(access = PROTECTED)
2619
@Entity
@@ -56,7 +49,7 @@ public class RecruitBoard extends BaseEntity {
5649

5750
@Builder
5851
public RecruitBoard(UUID centerId, Long locationId, String title, String content,
59-
RecruitmentInfo recruitmentInfo, String imgUrl) {
52+
RecruitmentInfo recruitmentInfo, String imgUrl) {
6053
this.centerId = centerId;
6154
this.locationId = locationId;
6255
this.title = title;
@@ -65,10 +58,6 @@ public RecruitBoard(UUID centerId, Long locationId, String title, String content
6558
this.imgUrl = imgUrl;
6659
}
6760

68-
public LocalTime getVolunteerHours() {
69-
return recruitmentInfo.calculateVolunteerTime();
70-
}
71-
7261
public boolean isWriter(UUID centerId) {
7362
return this.centerId.equals(centerId);
7463
}
@@ -102,6 +91,7 @@ private void updateRecruitmentInfo(RecruitBoardUpdateRequestDto dto) {
10291
dto.volunteerCategory(),
10392
dto.volunteerStartDateTime(),
10493
dto.volunteerEndDateTime(),
94+
dto.volunteerHours(),
10595
dto.admitted()
10696
);
10797
}
Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
package com.somemore.domains.recruitboard.domain;
22

3-
import static jakarta.persistence.EnumType.STRING;
4-
import static java.time.temporal.ChronoUnit.MINUTES;
5-
import static lombok.AccessLevel.PROTECTED;
6-
73
import jakarta.persistence.Column;
84
import jakarta.persistence.Embeddable;
95
import jakarta.persistence.Enumerated;
10-
import java.time.Duration;
11-
import java.time.LocalDateTime;
12-
import java.time.LocalTime;
136
import lombok.Builder;
147
import lombok.Getter;
158
import lombok.NoArgsConstructor;
169

10+
import java.time.LocalDateTime;
11+
12+
import static jakarta.persistence.EnumType.STRING;
13+
import static java.time.temporal.ChronoUnit.MINUTES;
14+
import static lombok.AccessLevel.PROTECTED;
15+
1716
@Getter
1817
@NoArgsConstructor(access = PROTECTED)
1918
@Embeddable
@@ -31,6 +30,9 @@ public class RecruitmentInfo {
3130
@Column(name = "volunteer_end_date_time", nullable = false)
3231
private LocalDateTime volunteerEndDateTime;
3332

33+
@Column(name = "volunteer_hours", nullable = false)
34+
private int volunteerHours;
35+
3436
@Enumerated(value = STRING)
3537
@Column(name = "volunteer_category", nullable = false, length = 30)
3638
private VolunteerCategory volunteerCategory;
@@ -39,50 +41,32 @@ public class RecruitmentInfo {
3941
private Boolean admitted;
4042

4143
@Builder
42-
public RecruitmentInfo(String region, Integer recruitmentCount,
43-
LocalDateTime volunteerStartDateTime, LocalDateTime volunteerEndDateTime,
44-
VolunteerCategory volunteerCategory, Boolean admitted) {
45-
46-
validateVolunteerDateTime(volunteerStartDateTime, volunteerEndDateTime);
44+
public RecruitmentInfo(String region, Integer recruitmentCount, LocalDateTime volunteerStartDateTime, LocalDateTime volunteerEndDateTime,
45+
int volunteerHours, VolunteerCategory volunteerCategory, Boolean admitted) {
4746

4847
this.region = region;
4948
this.recruitmentCount = recruitmentCount;
5049
this.volunteerStartDateTime = volunteerStartDateTime.truncatedTo(MINUTES);
5150
this.volunteerEndDateTime = volunteerEndDateTime.truncatedTo(MINUTES);
51+
this.volunteerHours = volunteerHours;
5252
this.volunteerCategory = volunteerCategory;
5353
this.admitted = admitted;
5454
}
5555

56-
public LocalTime calculateVolunteerTime() {
57-
Duration duration = Duration.between(volunteerStartDateTime, volunteerEndDateTime);
58-
59-
long hours = duration.toHours();
60-
long minutes = duration.toMinutes() % 60;
61-
62-
return LocalTime.of((int) hours, (int) minutes);
63-
}
64-
6556
public void updateWith(String region, Integer recruitmentCount, VolunteerCategory volunteerCategory,
66-
LocalDateTime volunteerStartDateTime, LocalDateTime volunteerEndDateTime,
67-
Boolean admitted) {
68-
69-
validateVolunteerDateTime(volunteerStartDateTime, volunteerEndDateTime);
70-
57+
LocalDateTime volunteerStartDateTime, LocalDateTime volunteerEndDateTime,
58+
Integer volunteerHours, Boolean admitted) {
7159
this.region = region;
7260
this.recruitmentCount = recruitmentCount;
7361
this.volunteerCategory = volunteerCategory;
7462
this.volunteerStartDateTime = volunteerStartDateTime.truncatedTo(MINUTES);
7563
this.volunteerEndDateTime = volunteerEndDateTime.truncatedTo(MINUTES);
64+
this.volunteerHours = volunteerHours;
7665
this.admitted = admitted;
7766
}
7867

7968
public void updateWith(String region) {
8069
this.region = region;
8170
}
8271

83-
private void validateVolunteerDateTime(LocalDateTime startDateTime, LocalDateTime endDateTime) {
84-
if (endDateTime.isEqual(startDateTime) || endDateTime.isBefore(startDateTime)) {
85-
throw new IllegalArgumentException("종료 시간은 시작 시간보다 이후여야 합니다.");
86-
}
87-
}
8872
}

src/main/java/com/somemore/domains/recruitboard/dto/request/RecruitBoardCreateRequestDto.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
import jakarta.validation.constraints.Future;
1111
import jakarta.validation.constraints.NotBlank;
1212
import jakarta.validation.constraints.NotNull;
13+
import lombok.Builder;
14+
1315
import java.time.LocalDateTime;
1416
import java.util.UUID;
15-
import lombok.Builder;
1617

1718
@JsonNaming(SnakeCaseStrategy.class)
1819
@Builder
@@ -37,6 +38,9 @@ public record RecruitBoardCreateRequestDto(
3738
@NotNull(message = "봉사 종료 일시는 필수 값입니다.")
3839
@Future(message = "봉사 종료 일시는 내일부터 가능합니다.")
3940
LocalDateTime volunteerEndDateTime,
41+
@Schema(description = "봉사 시간", example = "2")
42+
@NotNull(message = "봉사 시간은 필수 값입니다.")
43+
Integer volunteerHours,
4044
@Schema(description = "봉사 활동 유형", example = "ENVIRONMENTAL_PROTECTION")
4145
@NotNull(message = "봉사 활동 유형은 필수 값입니다.")
4246
VolunteerCategory volunteerCategory,
@@ -53,6 +57,7 @@ public RecruitBoard toEntity(UUID centerId, Long locationId, String imgUrl) {
5357
.recruitmentCount(recruitmentCount)
5458
.volunteerStartDateTime(volunteerStartDateTime)
5559
.volunteerEndDateTime(volunteerEndDateTime)
60+
.volunteerHours(volunteerHours)
5661
.volunteerCategory(volunteerCategory)
5762
.admitted(admitted)
5863
.build();

src/main/java/com/somemore/domains/recruitboard/dto/request/RecruitBoardUpdateRequestDto.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
import jakarta.validation.constraints.Future;
88
import jakarta.validation.constraints.NotBlank;
99
import jakarta.validation.constraints.NotNull;
10-
import java.time.LocalDateTime;
1110
import lombok.Builder;
1211

12+
import java.time.LocalDateTime;
13+
1314
@JsonNaming(SnakeCaseStrategy.class)
1415
@Builder
1516
public record RecruitBoardUpdateRequestDto(
@@ -31,7 +32,11 @@ public record RecruitBoardUpdateRequestDto(
3132
LocalDateTime volunteerStartDateTime,
3233
@Schema(description = "봉사 종료 일시", example = "2024-12-20T12:00:00", type = "string")
3334
@NotNull(message = "봉사 종료 일시는 필수 값입니다.")
34-
@Future(message = "봉사 종료 일시는 내일부터 가능합니다.")LocalDateTime volunteerEndDateTime,
35+
@Future(message = "봉사 종료 일시는 내일부터 가능합니다.")
36+
LocalDateTime volunteerEndDateTime,
37+
@Schema(description = "봉사 시간", example = "2")
38+
@NotNull(message = "봉사 시간는 필수 값입니다.")
39+
Integer volunteerHours,
3540
@Schema(description = "봉사 활동 유형", example = "ENVIRONMENTAL_PROTECTION")
3641
@NotNull(message = "봉사 활동 유형은 필수 값입니다.")
3742
VolunteerCategory volunteerCategory,

src/main/java/com/somemore/domains/recruitboard/dto/response/RecruitBoardDetailResponseDto.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33
import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;
44
import com.fasterxml.jackson.databind.annotation.JsonNaming;
55
import com.somemore.domains.center.dto.response.CenterSimpleInfoResponseDto;
6-
import com.somemore.domains.recruitboard.repository.mapper.RecruitBoardDetail;
76
import com.somemore.domains.location.dto.response.LocationResponseDto;
87
import com.somemore.domains.recruitboard.domain.RecruitBoard;
98
import com.somemore.domains.recruitboard.domain.RecruitStatus;
109
import com.somemore.domains.recruitboard.domain.RecruitmentInfo;
1110
import com.somemore.domains.recruitboard.domain.VolunteerCategory;
11+
import com.somemore.domains.recruitboard.repository.mapper.RecruitBoardDetail;
1212
import io.swagger.v3.oas.annotations.media.Schema;
13-
import java.time.LocalDateTime;
14-
import java.time.LocalTime;
1513
import lombok.Builder;
1614

15+
import java.time.LocalDateTime;
16+
1717

1818
@Builder
1919
@JsonNaming(SnakeCaseStrategy.class)
@@ -41,8 +41,8 @@ public record RecruitBoardDetailResponseDto(
4141
LocalDateTime volunteerEndDateTime,
4242
@Schema(description = "봉사 유형", example = "LIVING_SUPPORT")
4343
VolunteerCategory volunteerCategory,
44-
@Schema(description = "봉사 시간", example = "04:00:00")
45-
LocalTime volunteerTime,
44+
@Schema(description = "봉사 시간", example = "4")
45+
Integer volunteerHours,
4646
@Schema(description = "시간 인정 여부", example = "true")
4747
Boolean admitted,
4848
@Schema(description = "이미지 URL", example = "https://image.domain.com/links")
@@ -74,7 +74,7 @@ public static RecruitBoardDetailResponseDto from(RecruitBoardDetail recruitBoard
7474
.volunteerStartDateTime(info.getVolunteerStartDateTime())
7575
.volunteerEndDateTime(info.getVolunteerEndDateTime())
7676
.volunteerCategory(info.getVolunteerCategory())
77-
.volunteerTime(info.calculateVolunteerTime())
77+
.volunteerHours(info.getVolunteerHours())
7878
.admitted(info.getAdmitted())
7979
.imgUrl(board.getImgUrl())
8080
.location(location)

src/main/java/com/somemore/domains/recruitboard/dto/response/RecruitBoardResponseDto.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
import com.somemore.domains.recruitboard.domain.RecruitmentInfo;
88
import com.somemore.domains.recruitboard.domain.VolunteerCategory;
99
import io.swagger.v3.oas.annotations.media.Schema;
10+
import lombok.Builder;
11+
1012
import java.time.LocalDateTime;
11-
import java.time.LocalTime;
1213
import java.util.UUID;
13-
import lombok.Builder;
1414

1515
@Builder
1616
@JsonNaming(SnakeCaseStrategy.class)
@@ -42,8 +42,8 @@ public record RecruitBoardResponseDto(
4242
LocalDateTime volunteerEndDateTime,
4343
@Schema(description = "봉사 유형", example = "LIVING_SUPPORT")
4444
VolunteerCategory volunteerCategory,
45-
@Schema(description = "봉사 시간", example = "04:00:00")
46-
LocalTime volunteerTime,
45+
@Schema(description = "봉사 시간", example = "4")
46+
Integer volunteerHours,
4747
@Schema(description = "시간 인정 여부", example = "true")
4848
Boolean admitted,
4949
@Schema(description = "이미지 URL", example = "https://image.domain.com/links")
@@ -66,7 +66,7 @@ public static RecruitBoardResponseDto from(RecruitBoard board) {
6666
.volunteerStartDateTime(info.getVolunteerStartDateTime())
6767
.volunteerEndDateTime(info.getVolunteerEndDateTime())
6868
.volunteerCategory(info.getVolunteerCategory())
69-
.volunteerTime(info.calculateVolunteerTime())
69+
.volunteerHours(info.getVolunteerHours())
7070
.admitted(info.getAdmitted())
7171
.imgUrl(board.getImgUrl())
7272
.build();

0 commit comments

Comments
 (0)