Skip to content

Commit 92d1bb2

Browse files
committed
Merge branch 'develop' of https://github.com/prgrms-web-devcourse-final-project/WEB5_6_NeogulCoder_BE into feature/EA3-168-study-application
2 parents b362131 + ca8a599 commit 92d1bb2

31 files changed

+417
-402
lines changed

src/main/java/grep/neogul_coder/domain/calender/controller/PersonalCalendarController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ public class PersonalCalendarController implements PersonalCalendarSpecification
2323
public ApiResponse<Long> create(
2424
@PathVariable("userId") Long userId,
2525
@Valid @RequestBody PersonalCalendarRequest request) {
26-
Long calendarId = personalCalendarService.create(userId, request);
27-
return ApiResponse.success(calendarId); // 생성된 일정 ID 반환
26+
Long personalCalendarId = personalCalendarService.create(userId, request);
27+
return ApiResponse.success(personalCalendarId ); // 생성된 일정 ID 반환
2828
}
2929

3030
// 사용자 개인 일정 전체 조회 API

src/main/java/grep/neogul_coder/domain/calender/controller/PersonalCalendarSpecification.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public interface PersonalCalendarSpecification {
1818

1919
@Operation(
2020
summary = "개인 일정 생성",
21-
description = "사용자의 개인 일정을 생성합니다.\n\n예: `/api/users/{userId}/calendar`"
21+
description = "사용자의 개인 일정을 생성하고, 생성된 개인 일정 ID를 반환합니다. \n\n예: `/api/users/{userId}/calendar`"
2222
)
2323
ApiResponse<Long> create(
2424
@Parameter(name = "userId", description = "사용자 ID", required = true, in = ParameterIn.PATH)

src/main/java/grep/neogul_coder/domain/calender/controller/TeamCalendarController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public ApiResponse<Long> create(
2828
@PathVariable("studyId") Long studyId,
2929
@Valid @RequestBody TeamCalendarRequest request
3030
) {
31-
Long calendarId = teamCalendarService.create(studyId, userId, request);
32-
return ApiResponse.success(calendarId); // 생성된 일정 ID 반환
31+
Long teamCalendarId = teamCalendarService.create(studyId, userId, request);
32+
return ApiResponse.success(teamCalendarId); // 생성된 일정 ID 반환
3333
}
3434

3535
// 전체 일정 조회 API

src/main/java/grep/neogul_coder/domain/calender/controller/TeamCalendarSpecification.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ ApiResponse<List<TeamCalendarResponse>> findByDate(
4545

4646
@Operation(
4747
summary = "팀 일정 생성",
48-
description = "특정 팀 ID에 새로운 일정을 생성합니다.\n\n" +
48+
description = "팀 일정을 생성하고 생성된 팀 일정 ID를 반환합니다.\n\n" +
4949
"예: `/api/teams/{studyId}/calendar`"
5050
)
5151
ApiResponse<Long> create(

src/main/java/grep/neogul_coder/domain/calender/service/PersonalCalendarService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public Long create(Long userId, PersonalCalendarRequest request) {
6363
Calendar calendar = request.toCalendar();
6464
PersonalCalendar personalCalendar = new PersonalCalendar(userId, calendar);
6565
personalCalendarRepository.save(personalCalendar);
66-
return calendar.getId();
66+
return personalCalendar.getId();
6767
}
6868

6969
// 개인 일정 수정

src/main/java/grep/neogul_coder/domain/calender/service/TeamCalendarService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public Long create(Long studyId, Long userId, TeamCalendarRequest request) {
6666
TeamCalendar teamCalendar = new TeamCalendar(studyId, userId, calendar);
6767
teamCalendarRepository.save(teamCalendar);
6868

69-
return calendar.getId();
69+
return teamCalendar.getId();
7070
}
7171

7272
@Transactional

src/main/java/grep/neogul_coder/domain/studypost/controller/StudyPostController.java

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,48 +10,60 @@
1010
import grep.neogul_coder.global.response.ApiResponse;
1111
import jakarta.validation.Valid;
1212
import lombok.RequiredArgsConstructor;
13+
import org.springframework.http.MediaType;
1314
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1415
import org.springframework.web.bind.annotation.*;
16+
import org.springframework.web.multipart.MultipartFile;
17+
18+
import java.io.IOException;
1519

1620
@RequiredArgsConstructor
17-
@RequestMapping("/api/posts")
21+
@RequestMapping("/api/studies")
1822
@RestController
1923
public class StudyPostController implements StudyPostSpecification {
2024

2125
private final StudyPostService studyPostService;
2226

23-
@PostMapping
24-
public ApiResponse<Long> create(@RequestBody @Valid StudyPostSaveRequest request,
27+
@PostMapping("/{study-id}/posts")
28+
public ApiResponse<Long> create(@PathVariable("study-id") long studyId,
29+
@RequestBody @Valid StudyPostSaveRequest request,
2530
@AuthenticationPrincipal Principal userDetails) {
26-
long postId = studyPostService.create(request, userDetails.getUserId());
31+
long postId = studyPostService.create(request, studyId, userDetails.getUserId());
2732
return ApiResponse.success(postId);
2833
}
2934

30-
@GetMapping("/{postId}")
31-
public ApiResponse<StudyPostDetailResponse> findOne(@PathVariable("postId") Long postId) {
32-
StudyPostDetailResponse response = studyPostService.findOne(postId);
33-
return ApiResponse.success(response);
34-
}
35-
36-
@PostMapping("/studies/{study-id}")
35+
@PostMapping("/{study-id}/posts/search")
3736
public ApiResponse<PostPagingResult> findPagingInfo(@PathVariable("study-id") Long studyId,
3837
@RequestBody @Valid StudyPostPagingCondition condition) {
3938
PostPagingResult response = studyPostService.findPagingInfo(condition, studyId);
4039
return ApiResponse.success(response);
4140
}
4241

43-
@PutMapping("/{postId}")
44-
public ApiResponse<Void> update(@PathVariable("postId") Long postId,
42+
@GetMapping("/posts/{post-id}")
43+
public ApiResponse<StudyPostDetailResponse> findOne(@PathVariable("post-id") Long postId) {
44+
StudyPostDetailResponse response = studyPostService.findOne(postId);
45+
return ApiResponse.success(response);
46+
}
47+
48+
@PutMapping("/posts/{post-id}")
49+
public ApiResponse<Void> update(@PathVariable("post-id") Long postId,
4550
@RequestBody @Valid StudyPostUpdateRequest request,
4651
@AuthenticationPrincipal Principal userDetails) {
4752
studyPostService.update(request, postId, userDetails.getUserId());
4853
return ApiResponse.noContent();
4954
}
5055

51-
@DeleteMapping("/{postId}")
52-
public ApiResponse<Void> delete(@PathVariable("postId") Long postId,
56+
@DeleteMapping("/posts/{post-id}")
57+
public ApiResponse<Void> delete(@PathVariable("post-id") Long postId,
5358
@AuthenticationPrincipal Principal userDetails) {
5459
studyPostService.delete(postId, userDetails.getUserId());
5560
return ApiResponse.noContent();
5661
}
62+
63+
@PostMapping(value = "/posts/images", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
64+
public ApiResponse<String> uploadPostImage(@RequestPart("file") MultipartFile file,
65+
@AuthenticationPrincipal Principal userDetail) throws IOException {
66+
String imageUrl = studyPostService.uploadPostImage(file, userDetail.getUserId());
67+
return ApiResponse.success(imageUrl);
68+
}
5769
}

src/main/java/grep/neogul_coder/domain/studypost/controller/StudyPostSpecification.java

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,23 @@
1111
import io.swagger.v3.oas.annotations.Parameter;
1212
import io.swagger.v3.oas.annotations.tags.Tag;
1313
import org.springframework.security.core.annotation.AuthenticationPrincipal;
14+
import org.springframework.web.multipart.MultipartFile;
15+
16+
import java.io.IOException;
1417

1518
@Tag(name = "Study-Post", description = "스터디 게시판 API")
1619
public interface StudyPostSpecification {
1720

1821
@Operation(summary = "게시글 생성", description = "스터디에 새로운 게시글을 작성합니다.")
19-
ApiResponse<Long> create(StudyPostSaveRequest request, Principal userDetails);
22+
ApiResponse<Long> create(long studyId, StudyPostSaveRequest request, Principal userDetails);
2023

2124
@Operation(
2225
summary = "게시글 목록 페이징 조회",
2326
description = """
2427
스터디의 게시글을 조건에 따라 페이징하여 조회합니다.
2528
2629
✅ 요청 예시:
27-
`GET /api/posts/studies/{study-id}
30+
`GET /api/studies/{study-id}/posts/search
2831
2932
✅ condition 설명:
3033
- `page`: 조회할 페이지 번호 (0부터 시작)
@@ -75,46 +78,46 @@ ApiResponse<PostPagingResult> findPagingInfo(@Parameter(description = "스터디
7578
@Operation(
7679
summary = "게시글 상세 조회",
7780
description = """
78-
특정 게시글의 상세 정보를 조회합니다.
79-
80-
✅ 요청 예시:
81-
`GET /api/posts/{post-id}`
82-
83-
✅ 응답 예시:
84-
```json
85-
{
86-
"data": {
87-
"postInfo": {
88-
"postId": 15,
89-
"title": "스터디에 참여해주세요",
90-
"category": "NOTICE",
91-
"content": "매주 월요일 정기모임 진행합니다.",
92-
"createdDate": "2025-07-21T15:32:00",
93-
"commentCount": 3
94-
},
95-
"comments": [
96-
{
97-
"userId": 3,
98-
"nickname": "너굴코더",
99-
"profileImageUrl": "https://cdn.example.com/profile.jpg",
100-
"id": 100,
101-
"content": "정말 좋은 정보 감사합니다!",
102-
"createdAt": "2025-07-10T14:45:00"
103-
},
104-
{
105-
"userId": 4,
106-
"nickname": "코딩곰",
107-
"profileImageUrl": "https://cdn.example.com/codingbear.png",
108-
"id": 101,
109-
"content": "참석하겠습니다!",
110-
"createdAt": "2025-07-10T15:12:00"
111-
}
112-
],
113-
"commentCount": 3
114-
}
115-
}
116-
```
117-
"""
81+
특정 게시글의 상세 정보를 조회합니다.
82+
83+
✅ 요청 예시:
84+
`GET /api/studies/posts/{post-id}`
85+
86+
✅ 응답 예시:
87+
```json
88+
{
89+
"data": {
90+
"postInfo": {
91+
"postId": 15,
92+
"title": "스터디에 참여해주세요",
93+
"category": "NOTICE",
94+
"content": "매주 월요일 정기모임 진행합니다.",
95+
"createdDate": "2025-07-21T15:32:00",
96+
"commentCount": 3
97+
},
98+
"comments": [
99+
{
100+
"userId": 3,
101+
"nickname": "너굴코더",
102+
"profileImageUrl": "https://cdn.example.com/profile.jpg",
103+
"id": 100,
104+
"content": "정말 좋은 정보 감사합니다!",
105+
"createdAt": "2025-07-10T14:45:00"
106+
},
107+
{
108+
"userId": 4,
109+
"nickname": "코딩곰",
110+
"profileImageUrl": "https://cdn.example.com/codingbear.png",
111+
"id": 101,
112+
"content": "참석하겠습니다!",
113+
"createdAt": "2025-07-10T15:12:00"
114+
}
115+
],
116+
"commentCount": 3
117+
}
118+
}
119+
```
120+
"""
118121
)
119122
ApiResponse<StudyPostDetailResponse> findOne(
120123
@Parameter(description = "게시글 ID", example = "15") Long postId
@@ -130,4 +133,7 @@ ApiResponse<Void> update(
130133
@Operation(summary = "게시글 삭제", description = "특정 게시글을 삭제합니다.")
131134
ApiResponse<Void> delete(@Parameter(description = "게시글 ID", example = "15") Long postId,
132135
@AuthenticationPrincipal Principal userDetails);
136+
137+
@Operation(summary = "스터디 게시글 이미지 등록", description = "게시글에 이미지를 등록 합니다.")
138+
ApiResponse<String> uploadPostImage(MultipartFile file, Principal userDetails) throws IOException;
133139
}

src/main/java/grep/neogul_coder/domain/studypost/controller/dto/request/StudyPostSaveRequest.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,13 @@
55
import grep.neogul_coder.domain.studypost.StudyPost;
66
import io.swagger.v3.oas.annotations.media.Schema;
77
import jakarta.validation.constraints.NotBlank;
8-
import jakarta.validation.constraints.NotNull;
98
import lombok.Builder;
109
import lombok.Getter;
1110

1211
@Getter
1312
@Schema(description = "스터디 게시글 저장 요청 DTO")
1413
public class StudyPostSaveRequest {
1514

16-
@Schema(description = "3", example = "스터디 ID")
17-
@NotNull
18-
private long studyId;
19-
2015
@Schema(description = "제목", example = "스터디 공지")
2116
@NotBlank
2217
private String title;
@@ -33,8 +28,7 @@ private StudyPostSaveRequest() {
3328
}
3429

3530
@Builder
36-
private StudyPostSaveRequest(long studyId, String title, Category category, String content) {
37-
this.studyId = studyId;
31+
private StudyPostSaveRequest(String title, Category category, String content) {
3832
this.title = title;
3933
this.category = category;
4034
this.content = content;

src/main/java/grep/neogul_coder/domain/studypost/repository/StudyPostQueryRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ private OrderSpecifier<?> resolveOrderSpecifier(String attributeName, String dir
159159
}
160160

161161
private BooleanBuilder likeContent(String content) {
162-
return nullSafeBuilder(() -> studyPost.content.contains(content));
162+
return nullSafeBuilder(() -> studyPost.content.contains(content).or(studyPost.title.contains(content)));
163163
}
164164

165165
private BooleanBuilder equalsCategory(Category category) {

0 commit comments

Comments
 (0)