Skip to content

Commit 45893f6

Browse files
Merge pull request #212 from prgrms-web-devcourse-final-project/refactor/#207
[Community] 프론트 요청사항 반영하여 구인, 후기 게시글 전반적인 수정
2 parents 9d65437 + 71ed5bf commit 45893f6

21 files changed

Lines changed: 1142 additions & 80 deletions
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.back.web7_9_codecrete_be.domain.community.post.controller;
2+
3+
import com.back.web7_9_codecrete_be.domain.community.post.dto.request.JoinPostCreateRequest;
4+
import com.back.web7_9_codecrete_be.domain.community.post.dto.request.JoinPostUpdateRequest;
5+
import com.back.web7_9_codecrete_be.domain.community.post.dto.response.JoinPostResponse;
6+
import com.back.web7_9_codecrete_be.domain.community.post.service.JoinPostService;
7+
import com.back.web7_9_codecrete_be.domain.users.entity.User;
8+
import com.back.web7_9_codecrete_be.global.rq.Rq;
9+
import com.back.web7_9_codecrete_be.global.rsData.RsData;
10+
import io.swagger.v3.oas.annotations.Operation;
11+
import io.swagger.v3.oas.annotations.tags.Tag;
12+
import jakarta.validation.Valid;
13+
import lombok.RequiredArgsConstructor;
14+
import org.springframework.web.bind.annotation.*;
15+
16+
@RestController
17+
@RequestMapping("/api/v1/join")
18+
@RequiredArgsConstructor
19+
@Tag(name = "Community - Join", description = "구인글 API")
20+
public class JoinPostController {
21+
22+
private final JoinPostService joinPostService;
23+
private final Rq rq;
24+
25+
@Operation(summary = "구인글 작성")
26+
@PostMapping
27+
public RsData<?> create(
28+
@Valid @RequestBody JoinPostCreateRequest req
29+
) {
30+
User user = rq.getUser();
31+
Long postId = joinPostService.create(req, user);
32+
return RsData.success("구인글이 작성되었습니다.", postId);
33+
}
34+
35+
@Operation(summary = "구인글 상세 조회")
36+
@GetMapping("/{postId}")
37+
public RsData<JoinPostResponse> get(
38+
@PathVariable Long postId
39+
) {
40+
return RsData.success(
41+
"구인글 조회 성공",
42+
joinPostService.get(postId)
43+
);
44+
}
45+
46+
@Operation(summary = "구인글 수정")
47+
@PutMapping("/{postId}")
48+
public RsData<?> update(
49+
@PathVariable Long postId,
50+
@Valid @RequestBody JoinPostUpdateRequest req
51+
) {
52+
User user = rq.getUser();
53+
joinPostService.update(postId, req, user.getId());
54+
return RsData.success("구인글이 수정되었습니다.");
55+
}
56+
57+
@Operation(summary = "구인글 삭제")
58+
@DeleteMapping("/{postId}")
59+
public RsData<?> delete(
60+
@PathVariable Long postId
61+
) {
62+
User user = rq.getUser();
63+
joinPostService.delete(postId, user.getId());
64+
return RsData.success("구인글이 삭제되었습니다.");
65+
}
66+
67+
@Operation(summary = "구인글 마감")
68+
@PatchMapping("/{postId}/close")
69+
public RsData<?> close(
70+
@PathVariable Long postId
71+
) {
72+
User user = rq.getUser();
73+
joinPostService.close(postId, user.getId());
74+
return RsData.success("구인글이 마감되었습니다.");
75+
}
76+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.back.web7_9_codecrete_be.domain.community.post.controller;
2+
3+
4+
import com.back.web7_9_codecrete_be.domain.community.post.dto.request.ReviewPostMultipartRequest;
5+
import com.back.web7_9_codecrete_be.domain.community.post.dto.request.ReviewPostUpdateMultipartRequest;
6+
import com.back.web7_9_codecrete_be.domain.community.post.dto.response.ReviewPostResponse;
7+
import com.back.web7_9_codecrete_be.domain.community.post.service.ReviewPostService;
8+
import com.back.web7_9_codecrete_be.domain.users.entity.User;
9+
import com.back.web7_9_codecrete_be.global.rq.Rq;
10+
import com.back.web7_9_codecrete_be.global.rsData.RsData;
11+
import io.swagger.v3.oas.annotations.Operation;
12+
import io.swagger.v3.oas.annotations.tags.Tag;
13+
import jakarta.validation.Valid;
14+
import lombok.RequiredArgsConstructor;
15+
import org.springframework.http.MediaType;
16+
import org.springframework.web.bind.annotation.*;
17+
18+
@RestController
19+
@RequestMapping("/api/v1/reviews")
20+
@RequiredArgsConstructor
21+
@Tag(name = "Community - Review", description = "후기 게시글 API")
22+
public class ReviewPostController {
23+
24+
private final ReviewPostService reviewPostService;
25+
private final Rq rq;
26+
27+
@Operation(summary = "후기 게시글 작성")
28+
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
29+
public RsData<?> createReview(
30+
@ModelAttribute @Valid ReviewPostMultipartRequest req
31+
) {
32+
User user = rq.getUser();
33+
Long postId = reviewPostService.create(req, user);
34+
return RsData.success("후기 게시글이 작성되었습니다.", postId);
35+
}
36+
37+
@Operation(summary = "후기 게시글 상세 조회")
38+
@GetMapping("/{postId}")
39+
public RsData<ReviewPostResponse> getReview(
40+
@PathVariable Long postId
41+
) {
42+
return RsData.success(
43+
"후기 게시글 조회 성공",
44+
reviewPostService.getReview(postId)
45+
);
46+
}
47+
48+
@Operation(summary = "후기 게시글 수정")
49+
@PutMapping(
50+
value = "/{postId}",
51+
consumes = MediaType.MULTIPART_FORM_DATA_VALUE
52+
)
53+
public RsData<?> updateReview(
54+
@PathVariable Long postId,
55+
@ModelAttribute @Valid ReviewPostUpdateMultipartRequest req
56+
) {
57+
User user = rq.getUser();
58+
reviewPostService.update(postId, req, user.getId());
59+
return RsData.success("후기 게시글이 수정되었습니다.");
60+
}
61+
62+
@Operation(summary = "후기 게시글 삭제")
63+
@DeleteMapping("/{postId}")
64+
public RsData<?> deleteReview(
65+
@PathVariable Long postId
66+
) {
67+
User user = rq.getUser();
68+
reviewPostService.delete(postId, user.getId());
69+
return RsData.success("후기 게시글이 삭제되었습니다.");
70+
}
71+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.back.web7_9_codecrete_be.domain.community.post.dto.request;
2+
3+
import com.back.web7_9_codecrete_be.domain.community.post.entity.GenderPreference;
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
import jakarta.validation.constraints.Min;
6+
import jakarta.validation.constraints.NotBlank;
7+
import jakarta.validation.constraints.NotNull;
8+
import lombok.Getter;
9+
10+
import java.time.LocalDateTime;
11+
import java.util.List;
12+
13+
@Getter
14+
@Schema(description = "구인글 작성 요청")
15+
public class JoinPostCreateRequest {
16+
17+
@NotNull
18+
@Schema(description = "콘서트 ID", example = "1")
19+
private Long concertId;
20+
21+
@NotBlank
22+
@Schema(description = "구인글 제목", example = "아이유 콘서트 같이 가실 분!")
23+
private String title;
24+
25+
@NotBlank
26+
@Schema(description = "구인글 내용", example = "혼자 가기 아쉬워서 같이 가실 분 구해요.")
27+
private String content;
28+
29+
@Min(2)
30+
@Schema(description = "모집 인원", example = "4")
31+
private Integer maxParticipants;
32+
33+
@Schema(
34+
description = "성별 선호",
35+
allowableValues = {"MALE", "FEMALE", "ANY"},
36+
example = "ANY"
37+
)
38+
private GenderPreference genderPreference;
39+
40+
@Schema(description = "연령대 최소", example = "20")
41+
private Integer ageRangeMin;
42+
43+
@Schema(description = "연령대 최대", example = "35")
44+
private Integer ageRangeMax;
45+
46+
@Schema(description = "만날 시간", example = "2025-01-05T18:30:00")
47+
private LocalDateTime meetingAt;
48+
49+
@Schema(description = "만날 장소", example = "잠실역 3번 출구")
50+
private String meetingPlace;
51+
52+
@Schema(
53+
description = "활동 태그",
54+
example = "[\"Dinner before\", \"Photo taking\"]"
55+
)
56+
private List<String> activityTags;
57+
}
58+
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.back.web7_9_codecrete_be.domain.community.post.dto.request;
2+
3+
import com.back.web7_9_codecrete_be.domain.community.post.entity.GenderPreference;
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
import jakarta.validation.constraints.Min;
6+
import jakarta.validation.constraints.NotBlank;
7+
import jakarta.validation.constraints.NotNull;
8+
import lombok.Getter;
9+
10+
import java.time.LocalDateTime;
11+
import java.util.List;
12+
13+
@Getter
14+
@Schema(description = "구인글 수정 요청")
15+
public class JoinPostUpdateRequest {
16+
17+
@NotBlank(message = "제목은 필수입니다.")
18+
@Schema(
19+
description = "구인글 제목",
20+
example = "아이유 콘서트 같이 가실 분 구해요!"
21+
)
22+
private String title;
23+
24+
@NotBlank(message = "내용은 필수입니다.")
25+
@Schema(
26+
description = "구인글 내용",
27+
example = "혼자 가기 아쉬워서 같이 즐기실 분 찾습니다."
28+
)
29+
private String content;
30+
31+
@NotNull(message = "모집 인원은 필수입니다.")
32+
@Min(value = 1, message = "모집 인원은 최소 1명 이상이어야 합니다.")
33+
@Schema(description = "모집 인원", example = "4")
34+
private Integer maxParticipants;
35+
36+
@Schema(
37+
description = "성별 선호",
38+
allowableValues = {"MALE", "FEMALE", "ANY"},
39+
example = "ANY"
40+
)
41+
private GenderPreference genderPreference;
42+
43+
@Schema(description = "연령대 최소", example = "20")
44+
private Integer ageRangeMin;
45+
46+
@Schema(description = "연령대 최대", example = "35")
47+
private Integer ageRangeMax;
48+
49+
@Schema(description = "만날 시간", example = "2025-01-05T18:30:00")
50+
private LocalDateTime meetingAt;
51+
52+
@Schema(description = "만날 장소", example = "잠실역 3번 출구")
53+
private String meetingPlace;
54+
55+
@Schema(
56+
description = "활동 태그",
57+
example = "[\"Dinner before\", \"Photo taking\"]"
58+
)
59+
private List<String> activityTags;
60+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.back.web7_9_codecrete_be.domain.community.post.dto.request;
2+
3+
import io.swagger.v3.oas.annotations.Parameter;
4+
import io.swagger.v3.oas.annotations.media.ArraySchema;
5+
import io.swagger.v3.oas.annotations.media.Content;
6+
import io.swagger.v3.oas.annotations.media.Schema;
7+
import jakarta.validation.constraints.Max;
8+
import jakarta.validation.constraints.Min;
9+
import jakarta.validation.constraints.NotBlank;
10+
import jakarta.validation.constraints.NotNull;
11+
import lombok.Getter;
12+
import lombok.Setter;
13+
import org.springframework.http.MediaType;
14+
import org.springframework.web.multipart.MultipartFile;
15+
16+
import java.util.List;
17+
18+
@Getter
19+
@Setter
20+
@Schema(description = "후기 게시글 작성 요청 (multipart/form-data)")
21+
public class ReviewPostMultipartRequest {
22+
23+
@NotNull(message = "콘서트 ID는 필수입니다.")
24+
@Schema(
25+
description = "후기를 작성할 콘서트 ID",
26+
example = "1"
27+
)
28+
private Long concertId;
29+
30+
@NotBlank(message = "제목은 필수입니다.")
31+
@Schema(
32+
description = "후기 게시글 제목",
33+
example = "아이유 콘서트 후기"
34+
)
35+
private String title;
36+
37+
@NotBlank(message = "내용은 필수입니다.")
38+
@Schema(
39+
description = "후기 게시글 내용",
40+
example = "라이브가 정말 미쳤습니다. 음향도 최고였어요."
41+
)
42+
private String content;
43+
44+
@NotNull(message = "평점은 필수입니다.")
45+
@Min(value = 0, message = "평점은 0 이상이어야 합니다.")
46+
@Max(value = 5, message = "평점은 5 이하여야 합니다.")
47+
@Schema(
48+
description = "콘서트 평점 (0~5)",
49+
example = "5"
50+
)
51+
private Integer rating;
52+
53+
@Parameter(
54+
description = "후기 이미지 파일 (다중 업로드 가능)",
55+
content = @Content(
56+
mediaType = MediaType.MULTIPART_FORM_DATA_VALUE,
57+
array = @ArraySchema(
58+
schema = @Schema(type = "string", format = "binary")
59+
)
60+
)
61+
)
62+
private List<MultipartFile> images;
63+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.back.web7_9_codecrete_be.domain.community.post.dto.request;
2+
3+
import io.swagger.v3.oas.annotations.Parameter;
4+
import io.swagger.v3.oas.annotations.media.ArraySchema;
5+
import io.swagger.v3.oas.annotations.media.Content;
6+
import io.swagger.v3.oas.annotations.media.Schema;
7+
import jakarta.validation.constraints.Max;
8+
import jakarta.validation.constraints.Min;
9+
import jakarta.validation.constraints.NotBlank;
10+
import jakarta.validation.constraints.NotNull;
11+
import lombok.Getter;
12+
import lombok.Setter;
13+
import org.springframework.http.MediaType;
14+
import org.springframework.web.multipart.MultipartFile;
15+
16+
import java.util.List;
17+
18+
@Getter
19+
@Setter
20+
@Schema(description = "후기 게시글 수정 요청 (multipart/form-data)")
21+
public class ReviewPostUpdateMultipartRequest {
22+
23+
@NotBlank(message = "제목은 필수입니다.")
24+
@Schema(
25+
description = "수정할 후기 게시글 제목",
26+
example = "아이유 콘서트 후기 (수정)"
27+
)
28+
private String title;
29+
30+
@NotBlank(message = "내용은 필수입니다.")
31+
@Schema(
32+
description = "수정할 후기 게시글 내용",
33+
example = "2층 좌석이었지만 시야도 괜찮고 전반적으로 만족스러웠어요."
34+
)
35+
private String content;
36+
37+
@NotNull(message = "평점은 필수입니다.")
38+
@Min(value = 0, message = "평점은 0 이상이어야 합니다.")
39+
@Max(value = 5, message = "평점은 5 이하여야 합니다.")
40+
@Schema(
41+
description = "수정할 콘서트 평점 (0~5)",
42+
example = "4"
43+
)
44+
private Integer rating;
45+
46+
@Schema(
47+
description = """
48+
수정 후에도 유지할 기존 이미지 URL 목록
49+
- 프론트에서 기존 이미지 중 '삭제하지 않은 이미지'만 전달
50+
- 전달되지 않은 기존 이미지는 삭제 처리됨
51+
""",
52+
example = "[\"https://s3.amazonaws.com/reviews/images/abc.jpg\"]"
53+
)
54+
private List<String> remainImageUrls;
55+
56+
@Parameter(
57+
description = "새로 추가할 후기 이미지 파일 목록 (다중 업로드 가능)",
58+
content = @Content(
59+
mediaType = MediaType.MULTIPART_FORM_DATA_VALUE,
60+
array = @ArraySchema(
61+
schema = @Schema(type = "string", format = "binary")
62+
)
63+
)
64+
)
65+
private List<MultipartFile> images;
66+
}

0 commit comments

Comments
 (0)