Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.back.web7_9_codecrete_be.domain.community.post.controller;

import com.back.web7_9_codecrete_be.domain.community.post.dto.request.JoinPostCreateRequest;
import com.back.web7_9_codecrete_be.domain.community.post.dto.request.JoinPostUpdateRequest;
import com.back.web7_9_codecrete_be.domain.community.post.dto.response.JoinPostResponse;
import com.back.web7_9_codecrete_be.domain.community.post.service.JoinPostService;
import com.back.web7_9_codecrete_be.domain.users.entity.User;
import com.back.web7_9_codecrete_be.global.rq.Rq;
import com.back.web7_9_codecrete_be.global.rsData.RsData;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/v1/join")
@RequiredArgsConstructor
@Tag(name = "Community - Join", description = "구인글 API")
public class JoinPostController {

private final JoinPostService joinPostService;
private final Rq rq;

@Operation(summary = "구인글 작성")
@PostMapping
public RsData<?> create(
@Valid @RequestBody JoinPostCreateRequest req
) {
User user = rq.getUser();
Long postId = joinPostService.create(req, user);
return RsData.success("구인글이 작성되었습니다.", postId);
}

@Operation(summary = "구인글 상세 조회")
@GetMapping("/{postId}")
public RsData<JoinPostResponse> get(
@PathVariable Long postId
) {
return RsData.success(
"구인글 조회 성공",
joinPostService.get(postId)
);
}

@Operation(summary = "구인글 수정")
@PutMapping("/{postId}")
public RsData<?> update(
@PathVariable Long postId,
@Valid @RequestBody JoinPostUpdateRequest req
) {
User user = rq.getUser();
joinPostService.update(postId, req, user.getId());
return RsData.success("구인글이 수정되었습니다.");
}

@Operation(summary = "구인글 삭제")
@DeleteMapping("/{postId}")
public RsData<?> delete(
@PathVariable Long postId
) {
User user = rq.getUser();
joinPostService.delete(postId, user.getId());
return RsData.success("구인글이 삭제되었습니다.");
}

@Operation(summary = "구인글 마감")
@PatchMapping("/{postId}/close")
public RsData<?> close(
@PathVariable Long postId
) {
User user = rq.getUser();
joinPostService.close(postId, user.getId());
return RsData.success("구인글이 마감되었습니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.back.web7_9_codecrete_be.domain.community.post.controller;


import com.back.web7_9_codecrete_be.domain.community.post.dto.request.ReviewPostMultipartRequest;
import com.back.web7_9_codecrete_be.domain.community.post.dto.request.ReviewPostUpdateMultipartRequest;
import com.back.web7_9_codecrete_be.domain.community.post.dto.response.ReviewPostResponse;
import com.back.web7_9_codecrete_be.domain.community.post.service.ReviewPostService;
import com.back.web7_9_codecrete_be.domain.users.entity.User;
import com.back.web7_9_codecrete_be.global.rq.Rq;
import com.back.web7_9_codecrete_be.global.rsData.RsData;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/v1/reviews")
@RequiredArgsConstructor
@Tag(name = "Community - Review", description = "후기 게시글 API")
public class ReviewPostController {

private final ReviewPostService reviewPostService;
private final Rq rq;

@Operation(summary = "후기 게시글 작성")
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public RsData<?> createReview(
@ModelAttribute @Valid ReviewPostMultipartRequest req
) {
User user = rq.getUser();
Long postId = reviewPostService.create(req, user);
return RsData.success("후기 게시글이 작성되었습니다.", postId);
}

@Operation(summary = "후기 게시글 상세 조회")
@GetMapping("/{postId}")
public RsData<ReviewPostResponse> getReview(
@PathVariable Long postId
) {
return RsData.success(
"후기 게시글 조회 성공",
reviewPostService.getReview(postId)
);
}

@Operation(summary = "후기 게시글 수정")
@PutMapping(
value = "/{postId}",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE
)
public RsData<?> updateReview(
@PathVariable Long postId,
@ModelAttribute @Valid ReviewPostUpdateMultipartRequest req
) {
User user = rq.getUser();
reviewPostService.update(postId, req, user.getId());
return RsData.success("후기 게시글이 수정되었습니다.");
}

@Operation(summary = "후기 게시글 삭제")
@DeleteMapping("/{postId}")
public RsData<?> deleteReview(
@PathVariable Long postId
) {
User user = rq.getUser();
reviewPostService.delete(postId, user.getId());
return RsData.success("후기 게시글이 삭제되었습니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.back.web7_9_codecrete_be.domain.community.post.dto.request;

import com.back.web7_9_codecrete_be.domain.community.post.entity.GenderPreference;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;

import java.time.LocalDateTime;
import java.util.List;

@Getter
@Schema(description = "구인글 작성 요청")
public class JoinPostCreateRequest {

@NotNull
@Schema(description = "콘서트 ID", example = "1")
private Long concertId;

@NotBlank
@Schema(description = "구인글 제목", example = "아이유 콘서트 같이 가실 분!")
private String title;

@NotBlank
@Schema(description = "구인글 내용", example = "혼자 가기 아쉬워서 같이 가실 분 구해요.")
private String content;

@Min(2)
@Schema(description = "모집 인원", example = "4")
private Integer maxParticipants;

@Schema(
description = "성별 선호",
allowableValues = {"MALE", "FEMALE", "ANY"},
example = "ANY"
)
private GenderPreference genderPreference;

@Schema(description = "연령대 최소", example = "20")
private Integer ageRangeMin;

@Schema(description = "연령대 최대", example = "35")
private Integer ageRangeMax;

@Schema(description = "만날 시간", example = "2025-01-05T18:30:00")
private LocalDateTime meetingAt;

@Schema(description = "만날 장소", example = "잠실역 3번 출구")
private String meetingPlace;

@Schema(
description = "활동 태그",
example = "[\"Dinner before\", \"Photo taking\"]"
)
private List<String> activityTags;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.back.web7_9_codecrete_be.domain.community.post.dto.request;

import com.back.web7_9_codecrete_be.domain.community.post.entity.GenderPreference;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;

import java.time.LocalDateTime;
import java.util.List;

@Getter
@Schema(description = "구인글 수정 요청")
public class JoinPostUpdateRequest {

@NotBlank(message = "제목은 필수입니다.")
@Schema(
description = "구인글 제목",
example = "아이유 콘서트 같이 가실 분 구해요!"
)
private String title;

@NotBlank(message = "내용은 필수입니다.")
@Schema(
description = "구인글 내용",
example = "혼자 가기 아쉬워서 같이 즐기실 분 찾습니다."
)
private String content;

@NotNull(message = "모집 인원은 필수입니다.")
@Min(value = 1, message = "모집 인원은 최소 1명 이상이어야 합니다.")
@Schema(description = "모집 인원", example = "4")
private Integer maxParticipants;

@Schema(
description = "성별 선호",
allowableValues = {"MALE", "FEMALE", "ANY"},
example = "ANY"
)
private GenderPreference genderPreference;

@Schema(description = "연령대 최소", example = "20")
private Integer ageRangeMin;

@Schema(description = "연령대 최대", example = "35")
private Integer ageRangeMax;

@Schema(description = "만날 시간", example = "2025-01-05T18:30:00")
private LocalDateTime meetingAt;

@Schema(description = "만날 장소", example = "잠실역 3번 출구")
private String meetingPlace;

@Schema(
description = "활동 태그",
example = "[\"Dinner before\", \"Photo taking\"]"
)
private List<String> activityTags;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.back.web7_9_codecrete_be.domain.community.post.dto.request;

import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

@Getter
@Setter
@Schema(description = "후기 게시글 작성 요청 (multipart/form-data)")
public class ReviewPostMultipartRequest {

@NotNull(message = "콘서트 ID는 필수입니다.")
@Schema(
description = "후기를 작성할 콘서트 ID",
example = "1"
)
private Long concertId;

@NotBlank(message = "제목은 필수입니다.")
@Schema(
description = "후기 게시글 제목",
example = "아이유 콘서트 후기"
)
private String title;

@NotBlank(message = "내용은 필수입니다.")
@Schema(
description = "후기 게시글 내용",
example = "라이브가 정말 미쳤습니다. 음향도 최고였어요."
)
private String content;

@NotNull(message = "평점은 필수입니다.")
@Min(value = 0, message = "평점은 0 이상이어야 합니다.")
@Max(value = 5, message = "평점은 5 이하여야 합니다.")
@Schema(
description = "콘서트 평점 (0~5)",
example = "5"
)
private Integer rating;

@Parameter(
description = "후기 이미지 파일 (다중 업로드 가능)",
content = @Content(
mediaType = MediaType.MULTIPART_FORM_DATA_VALUE,
array = @ArraySchema(
schema = @Schema(type = "string", format = "binary")
)
)
)
private List<MultipartFile> images;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.back.web7_9_codecrete_be.domain.community.post.dto.request;

import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

@Getter
@Setter
@Schema(description = "후기 게시글 수정 요청 (multipart/form-data)")
public class ReviewPostUpdateMultipartRequest {

@NotBlank(message = "제목은 필수입니다.")
@Schema(
description = "수정할 후기 게시글 제목",
example = "아이유 콘서트 후기 (수정)"
)
private String title;

@NotBlank(message = "내용은 필수입니다.")
@Schema(
description = "수정할 후기 게시글 내용",
example = "2층 좌석이었지만 시야도 괜찮고 전반적으로 만족스러웠어요."
)
private String content;

@NotNull(message = "평점은 필수입니다.")
@Min(value = 0, message = "평점은 0 이상이어야 합니다.")
@Max(value = 5, message = "평점은 5 이하여야 합니다.")
@Schema(
description = "수정할 콘서트 평점 (0~5)",
example = "4"
)
private Integer rating;

@Schema(
description = """
수정 후에도 유지할 기존 이미지 URL 목록
- 프론트에서 기존 이미지 중 '삭제하지 않은 이미지'만 전달
- 전달되지 않은 기존 이미지는 삭제 처리됨
""",
example = "[\"https://s3.amazonaws.com/reviews/images/abc.jpg\"]"
)
private List<String> remainImageUrls;

@Parameter(
description = "새로 추가할 후기 이미지 파일 목록 (다중 업로드 가능)",
content = @Content(
mediaType = MediaType.MULTIPART_FORM_DATA_VALUE,
array = @ArraySchema(
schema = @Schema(type = "string", format = "binary")
)
)
)
private List<MultipartFile> images;
}
Loading