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 @@ -5,9 +5,11 @@

import com.campus.campus.domain.councilpost.domain.entity.PostCategory;
import com.campus.campus.domain.councilpost.domain.entity.ThumbnailIcon;
import com.campus.campus.domain.place.application.dto.response.SavedPlaceInfo;
import com.fasterxml.jackson.annotation.JsonFormat;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

Expand All @@ -22,7 +24,26 @@ public record PostRequest(
@NotBlank
String content,

String place,
@Schema(example =
"""
"placeName": "숙명여자대학교",
"placeKey": "string",
"address": "서울특별시 용산구 청파로47길 99",
"category": "교육,학문>대학교",
"link": "https://map.naver.com/v5/search/%EC%88%99%EB%AA%85%EC%97%AC%EC%9E%90%EB%8C%80%ED%95%99%EA%B5%90+%EC%A0%9C1%EC%BA%A0%ED%8D%BC%EC%8A%A4?c=37.545947,126.964578,15,0,0,0,dh",
"telephone": "010-1234-1234",
"coordinate": {
"latitude": 0.1,
"longitude": 0.1
},
"imgUrls": [
"string"
]
""",
description = "/search API에서 반환된 결과 중 하나를 선택")
@NotNull
@Valid
SavedPlaceInfo place,

@Schema(example = "2025-04-10T18:00")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public record GetPostResponse(
PostCategory category,
String title,
String content,
String place,
String placeName,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Search for response DTOs with 'place' field to check current state
rg -n --type=java -B2 -A2 'String place[,;)]' src/main/java/com/campus/campus/domain/councilpost/application/dto/response/

Repository: our-campUS/our-campUS-BE

Length of output: 3621


🏁 Script executed:

# Also check for placeName to see which DTOs have been updated
rg -n --type=java -B2 -A2 'String placeName[,;)]' src/main/java/com/campus/campus/domain/councilpost/application/dto/response/

Repository: our-campUS/our-campUS-BE

Length of output: 1301


🏁 Script executed:

# List all response DTOs in councilpost domain to ensure comprehensive check
fd -e java "Response\.java" src/main/java/com/campus/campus/domain/councilpost/application/dto/response/

Repository: our-campUS/our-campUS-BE

Length of output: 922


응답 DTO들의 필드명 placeplaceName으로 통일하세요.

GetPostResponsePostListItemResponse에서만 placeName으로 변경되었고, 다음 5개 DTO에서는 여전히 place를 사용하고 있어 일관성 문제가 발생합니다:

  • GetPostListForCouncilResponse
  • GetUpcomingEventListForCouncilResponse
  • GetPostForUserResponse
  • GetLikedPostResponse
  • GetActivePartnershipListForUserResponse

모든 응답 DTO의 필드명을 placeName으로 통일하여 API 계약 일관성을 확보하세요.

🤖 Prompt for AI Agents
In
@src/main/java/com/campus/campus/domain/councilpost/application/dto/response/GetPostResponse.java
at line 25, Many DTOs still expose a field named place while GetPostResponse and
PostListItemResponse use placeName; update the five DTO classes
GetPostListForCouncilResponse, GetUpcomingEventListForCouncilResponse,
GetPostForUserResponse, GetLikedPostResponse, and
GetActivePartnershipListForUserResponse to rename the field from place to
placeName and adjust all related symbols—constructors, builders/static factory
methods, getters/setters, equals/hashCode/toString, and any JSON/serialization
annotations (e.g., @JsonProperty) and mapper code that populate or read that
field—to use placeName so the API contract is consistent across all response
DTOs.

LocalDate startDate,
LocalDate endDate,
LocalDateTime startDateTime,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public record PostListItemResponse(
Long id,
PostCategory category,
String title,
String place,
String placeName,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for place field usage in response DTOs
echo "=== Searching for 'place' field ==="
rg -n --type=java 'String place[,;)]' src/main/java/com/campus/campus/domain/councilpost/application/dto/response/

echo -e "\n=== Searching for 'placeName' field ==="
rg -n --type=java 'String placeName[,;)]' src/main/java/com/campus/campus/domain/councilpost/application/dto/response/

echo -e "\n=== List all response DTO files ==="
fd --type f --extension java 'Response\.java$' src/main/java/com/campus/campus/domain/councilpost/application/dto/response/

Repository: our-campUS/our-campUS-BE

Length of output: 1927


응답 DTO의 장소명 필드 일관성 문제를 해결해주세요.

응답 DTO들에서 동일한 개념의 필드가 서로 다른 이름으로 정의되어 있습니다:

  • place 사용: GetPostListForCouncilResponse, GetUpcomingEventListForCouncilResponse, GetPostForUserResponse, GetLikedPostResponse, GetActivePartnershipListForUserResponse (5개)
  • placeName 사용: PostListItemResponse, GetPostResponse (2개)

API 일관성을 위해 모든 응답 DTO가 동일한 필드명을 사용하도록 통일해야 합니다.

🤖 Prompt for AI Agents
In
@src/main/java/com/campus/campus/domain/councilpost/application/dto/response/PostListItemResponse.java
at line 12, PostListItemResponse currently defines the field placeName which is
inconsistent with other response DTOs that use place; change the DTO to use the
same field name "place" (update the field name in PostListItemResponse, its
constructor/builder/getter/setter, any Jackson/serialization annotations, and
all usages/mappers that populate PostListItemResponse) and likewise update
GetPostResponse if it uses placeName—ensure all mapping code (e.g., methods that
convert entities to PostListItemResponse or GetPostResponse) assigns to the
unified "place" property so all response DTOs share the same field name.

LocalDateTime endDateTime,
String thumbnailImageUrl,
ThumbnailIcon thumbnailIcon,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.campus.campus.domain.councilpost.application.exception;

import com.campus.campus.global.common.exception.ApplicationException;

public class AcademicInfoNotSetException extends ApplicationException {
public AcademicInfoNotSetException() {
super(ErrorCode.ACADEMIC_INFO_NOT_SET);
}
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
package com.campus.campus.domain.councilpost.application.exception;

import com.campus.campus.global.common.exception.ErrorCodeInterface;

import lombok.AllArgsConstructor;
import lombok.Getter;

import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum ErrorCode implements ErrorCodeInterface {

POST_NOT_FOUND(2401, HttpStatus.NOT_FOUND, "게시글을 찾을 수 없습니다."),
NOT_POST_WRITER(2402, HttpStatus.FORBIDDEN, "작성자만 해당 작업을 수행할 수 있습니다."),
THUMBNAIL_REQUIRED(2403, HttpStatus.BAD_REQUEST, "썸네일(이미지 또는 아이콘)은 반드시 필요합니다."),
POST_IMAGE_LIMIT_EXCEEDED(2404, HttpStatus.BAD_REQUEST, "게시글 이미지는 최대 10개까지 등록할 수 있습니다."),
POST_OCI_IMAGE_DELETE_FAILED(2405, HttpStatus.INTERNAL_SERVER_ERROR, "OCI 이미지 삭제에 실패했습니다."),
POST_NOT_FOUND(2401, HttpStatus.NOT_FOUND, "게시글을 찾을 수 없습니다."),
NOT_POST_WRITER(2402, HttpStatus.FORBIDDEN, "작성자만 해당 작업을 수행할 수 있습니다."),
THUMBNAIL_REQUIRED(2403, HttpStatus.BAD_REQUEST, "썸네일(이미지 또는 아이콘)은 반드시 필요합니다."),
POST_IMAGE_LIMIT_EXCEEDED(2404, HttpStatus.BAD_REQUEST, "게시글 이미지는 최대 10개까지 등록할 수 있습니다."),
POST_OCI_IMAGE_DELETE_FAILED(2405, HttpStatus.INTERNAL_SERVER_ERROR, "OCI 이미지 삭제에 실패했습니다."),

// EVENT 관련
EVENT_START_DATETIME_REQUIRED(2406, HttpStatus.BAD_REQUEST, "행사는 시작 일시가 필요합니다."),
EVENT_END_DATETIME_NOT_ALLOWED(2407, HttpStatus.BAD_REQUEST, "행사는 종료 일시를 가질 수 없습니다."),
// EVENT 관련
EVENT_START_DATETIME_REQUIRED(2406, HttpStatus.BAD_REQUEST, "행사는 시작 일시가 필요합니다."),
EVENT_END_DATETIME_NOT_ALLOWED(2407, HttpStatus.BAD_REQUEST, "행사는 종료 일시를 가질 수 없습니다."),

// PARTNERSHIP 관련
PARTNERSHIP_DATE_REQUIRED(2408, HttpStatus.BAD_REQUEST, "제휴는 시작일과 종료일이 필요합니다."),
// PARTNERSHIP 관련
PARTNERSHIP_DATE_REQUIRED(2408, HttpStatus.BAD_REQUEST, "제휴는 시작일과 종료일이 필요합니다."),

// 학생의 학생회 게시글 조회 관련
POST_ACCESS_DENIED(2409, HttpStatus.FORBIDDEN, "해당 게시글에 접근할 권한이 없습니다."),
COLLEGE_NOT_SET(2410, HttpStatus.BAD_REQUEST, "단과대 정보가 설정되지 않았습니다."),
MAJOR_NOT_SET(2411, HttpStatus.BAD_REQUEST, "학과 정보가 설정되지 않았습니다.");
// 학생의 학생회 게시글 조회 관련
POST_ACCESS_DENIED(2409, HttpStatus.FORBIDDEN, "해당 게시글에 접근할 권한이 없습니다."),
COLLEGE_NOT_SET(2410, HttpStatus.BAD_REQUEST, "단과대 정보가 설정되지 않았습니다."),
MAJOR_NOT_SET(2411, HttpStatus.BAD_REQUEST, "학과 정보가 설정되지 않았습니다."),
ACADEMIC_INFO_NOT_SET(2412, HttpStatus.BAD_REQUEST, "학적 정보가 설정되지 않았습니다."),

PLACE_INFO_NOT_FOUND(2413, HttpStatus.NOT_FOUND, "해당 게시글의 장소 정보를 찾을 수 없습니다.");

private final int code;
private final HttpStatus status;
private final String message;
private final int code;
private final HttpStatus status;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.campus.campus.domain.councilpost.application.exception;

import com.campus.campus.global.common.exception.ApplicationException;

public class PlaceInfoNotFoundException extends ApplicationException {
public PlaceInfoNotFoundException() {
super(ErrorCode.PLACE_INFO_NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@
import org.springframework.stereotype.Component;

import com.campus.campus.domain.council.domain.entity.StudentCouncil;
import com.campus.campus.domain.councilpost.application.dto.request.PostRequest;
import com.campus.campus.domain.councilpost.application.dto.response.GetActivePartnershipListForUserResponse;
import com.campus.campus.domain.councilpost.application.dto.response.GetLikedPostResponse;
import com.campus.campus.domain.councilpost.application.dto.response.GetPostResponse;
import com.campus.campus.domain.councilpost.application.dto.response.LikePostResponse;
import com.campus.campus.domain.councilpost.application.dto.response.GetPostForUserResponse;
import com.campus.campus.domain.councilpost.application.dto.response.GetPostListForCouncilResponse;
import com.campus.campus.domain.councilpost.application.dto.response.GetPostResponse;
import com.campus.campus.domain.councilpost.application.dto.response.GetUpcomingEventListForCouncilResponse;
import com.campus.campus.domain.councilpost.application.dto.response.GetActivePartnershipListForUserResponse;
import com.campus.campus.domain.councilpost.application.dto.response.LikePostResponse;
import com.campus.campus.domain.councilpost.application.dto.response.PostListItemResponse;
import com.campus.campus.domain.councilpost.application.dto.request.PostRequest;
import com.campus.campus.domain.councilpost.application.dto.response.GetPostForUserResponse;
import com.campus.campus.domain.councilpost.domain.entity.LikePost;
import com.campus.campus.domain.councilpost.domain.entity.PostImage;
import com.campus.campus.domain.councilpost.domain.entity.StudentCouncilPost;
import com.campus.campus.domain.place.domain.entity.Place;
import com.campus.campus.domain.user.domain.entity.User;

import lombok.RequiredArgsConstructor;
Expand All @@ -31,8 +32,10 @@ public PostListItemResponse toPostListItemResponse(StudentCouncilPost post, bool
post.getId(),
post.getCategory(),
post.getTitle(),
post.getPlace(),
post.isEvent() ? post.getStartDateTime() : post.getEndDateTime(),
post.getPlace().getPlaceName(),
post.isEvent()
? post.getStartDateTime()
: post.getEndDateTime(),
post.getThumbnailImageUrl(),
post.getThumbnailIcon(),
isLiked
Expand All @@ -44,7 +47,7 @@ public GetPostListForCouncilResponse toGetPostListForCouncilResponse(StudentCoun
post.getId(),
post.getCategory(),
post.getTitle(),
post.getPlace(),
post.getPlace().getPlaceName(),
post.isEvent() ? post.getStartDateTime() : post.getEndDateTime(),
post.getThumbnailImageUrl(),
post.getThumbnailIcon()
Expand All @@ -56,7 +59,7 @@ public GetUpcomingEventListForCouncilResponse toGetUpcomingEventListForCouncilRe
post.getId(),
post.getCategory(),
post.getTitle(),
post.getPlace(),
post.getPlace().getPlaceName(),
post.getStartDateTime(),
post.getThumbnailIcon()
);
Expand All @@ -66,7 +69,7 @@ public GetActivePartnershipListForUserResponse toGetActivePartnershipListForUser
return new GetActivePartnershipListForUserResponse(
post.getId(),
post.getTitle(),
post.getPlace(),
post.getPlace().getPlaceName(),
post.getThumbnailImageUrl()
);
}
Expand All @@ -81,7 +84,7 @@ public GetPostResponse toGetPostResponse(StudentCouncilPost post, List<String> i
.category(post.getCategory())
.title(post.getTitle())
.content(post.getContent())
.place(post.getPlace())
.placeName(post.getPlace().getPlaceName())
.thumbnailImageUrl(post.getThumbnailImageUrl())
.thumbnailIcon(post.getThumbnailIcon())
.images(images != null ? images : Collections.emptyList());
Expand All @@ -106,7 +109,7 @@ public GetPostForUserResponse toGetPostForUserResponse(StudentCouncilPost post,
.category(post.getCategory())
.title(post.getTitle())
.content(post.getContent())
.place(post.getPlace())
.place(post.getPlace().getPlaceName())
.thumbnailImageUrl(post.getThumbnailImageUrl())
.thumbnailIcon(post.getThumbnailIcon())
.isLiked(isLiked)
Expand Down Expand Up @@ -134,20 +137,20 @@ public GetLikedPostResponse toGetLikedPostResponse(StudentCouncilPost post) {
return new GetLikedPostResponse(
post.getId(),
post.getTitle(),
post.getPlace(),
post.getPlace().getPlaceName(),
post.isEvent() ? post.getStartDateTime() : post.getEndDateTime(),
post.getThumbnailImageUrl()
);
}

public StudentCouncilPost createStudentCouncilPost(StudentCouncil writer, PostRequest dto,
public StudentCouncilPost createStudentCouncilPost(StudentCouncil writer, Place place, PostRequest dto,
LocalDateTime startDateTime, LocalDateTime endDateTime) {
return StudentCouncilPost.builder()
.writer(writer)
.category(dto.category())
.title(dto.title())
.content(dto.content())
.place(dto.place())
.place(place)
.startDateTime(startDateTime)
.endDateTime(endDateTime)
.thumbnailImageUrl(dto.thumbnailImageUrl())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
import com.campus.campus.domain.council.application.exception.StudentCouncilNotFoundException;
import com.campus.campus.domain.council.domain.entity.StudentCouncil;
import com.campus.campus.domain.council.domain.repository.StudentCouncilRepository;
import com.campus.campus.domain.councilpost.application.dto.request.PostRequest;
import com.campus.campus.domain.councilpost.application.dto.response.GetPostListForCouncilResponse;
import com.campus.campus.domain.councilpost.application.dto.response.GetPostResponse;
import com.campus.campus.domain.councilpost.application.dto.response.GetUpcomingEventListForCouncilResponse;
import com.campus.campus.domain.councilpost.application.dto.response.NormalizedDateTime;
import com.campus.campus.domain.councilpost.application.dto.request.PostRequest;
import com.campus.campus.domain.councilpost.application.exception.NotPostWriterException;
import com.campus.campus.domain.councilpost.application.exception.PostImageLimitExceededException;
import com.campus.campus.domain.councilpost.application.exception.PostNotFoundException;
Expand All @@ -30,6 +30,9 @@
import com.campus.campus.domain.councilpost.domain.entity.StudentCouncilPost;
import com.campus.campus.domain.councilpost.domain.repository.PostImageRepository;
import com.campus.campus.domain.councilpost.domain.repository.StudentCouncilPostRepository;
import com.campus.campus.domain.partnership.application.service.PartnershipService;
import com.campus.campus.domain.place.application.service.PlaceService;
import com.campus.campus.domain.place.domain.entity.Place;
import com.campus.campus.global.oci.application.service.PresignedUrlService;

import lombok.RequiredArgsConstructor;
Expand All @@ -48,6 +51,9 @@ public class StudentCouncilPostService {

private static final int MAX_IMAGE_COUNT = 10;
private static final long UPCOMING_EVENT_WINDOW_HOURS = 72L;
private final PlaceService placeService;
private final StudentCouncilPostRepository studentCouncilPostRepository;
private final PartnershipService partnershipService;

@Transactional
public GetPostResponse create(Long councilId, PostRequest dto) {
Expand All @@ -65,8 +71,11 @@ public GetPostResponse create(Long councilId, PostRequest dto) {

NormalizedDateTime normalized = dto.category().validateAndNormalize(dto);

//Place 객체 생성
Place place = placeService.findOrCreatePlace(dto);

StudentCouncilPost post = studentCouncilPostMapper.createStudentCouncilPost(
writer, dto, normalized.startDateTime(), normalized.endDateTime()
writer, place, dto, normalized.startDateTime(), normalized.endDateTime()
);

postRepository.save(post);
Expand Down Expand Up @@ -203,10 +212,15 @@ public GetPostResponse update(Long councilId, Long postId, PostRequest dto) {
String oldThumbnailUrl = post.getThumbnailImageUrl();
List<PostImage> oldImages = postImageRepository.findAllByPost(post);

Place place = post.getPlace();
if (dto.place() != null && (place == null || !dto.place().placeName().equals(place.getPlaceName()))) {
place = placeService.findOrCreatePlace(dto);
}

post.update(
dto.title(),
dto.content(),
dto.place(),
place,
normalized.startDateTime(),
normalized.endDateTime(),
dto.thumbnailImageUrl(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.time.LocalDateTime;

import com.campus.campus.domain.council.domain.entity.StudentCouncil;
import com.campus.campus.domain.place.domain.entity.Place;
import com.campus.campus.global.entity.BaseEntity;

import jakarta.persistence.Column;
Expand Down Expand Up @@ -45,7 +46,9 @@ public class StudentCouncilPost extends BaseEntity {
@Column(columnDefinition = "TEXT")
private String content;

private String place;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "place_id")
private Place place;

private LocalDateTime startDateTime;
private LocalDateTime endDateTime;
Expand All @@ -58,7 +61,7 @@ public class StudentCouncilPost extends BaseEntity {
public void update(
String title,
String content,
String place,
Place place,
LocalDateTime startDateTime,
LocalDateTime endDateTime,
String thumbnailImageUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import com.campus.campus.domain.councilpost.domain.entity.PostImage;
import com.campus.campus.domain.councilpost.domain.entity.StudentCouncilPost;
Expand All @@ -14,4 +16,12 @@ public interface PostImageRepository extends JpaRepository<PostImage, Long> {
void deleteByPost(StudentCouncilPost post);

List<PostImage> findAllByPostOrderByIdAsc(StudentCouncilPost post);

@Query("""
select pi.imageUrl
from PostImage pi
where pi.post = :post
order by pi.id asc
""")
List<String> findImageUrlsByPost(@Param("post") StudentCouncilPost post);
}
Loading