Skip to content
This repository was archived by the owner on Jan 11, 2026. It is now read-only.
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 @@ -31,6 +31,7 @@ public enum SuccessStatus implements BaseCode {
_MEMBER_LOGIN_ID_CHECK_COMPLETED(HttpStatus.OK, "MEMBER2012", "회원 아이디 사용 가능 여부 조회 완료"),
_MEMBER_EMAIL_CHECK_COMPLETED(HttpStatus.OK, "MEMBER2013", "회원 이메일 사용 가능 여부 조회 완료"),
_RSA_PUBLIC_KEY_FOUND(HttpStatus.OK, "MEMBER2014", "RSA Public Key 조회 완료"),
_MEMBER_SIGNUP_CHECK_COMPLETED(HttpStatus.OK, "MEMBER2015", "회원 가입 유무 조회 완료"),

//스터디 게시글 관련 응답
_STUDY_POST_CREATED(HttpStatus.CREATED, "STUDYPOST3001", "스터디 게시글 작성 완료"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,22 @@

@Entity
@Getter
@Builder
@DynamicUpdate
@DynamicInsert
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class StudyPostImage extends BaseEntity {

@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Setter
@Column(nullable = false)
private String url;

@Setter
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "study_post_id", nullable = false)
private StudyPost studyPost;

/* ----------------------------- 생성자 ------------------------------------- */

public StudyPostImage(String url) {
this.url = url;
}
}
8 changes: 4 additions & 4 deletions src/main/java/com/example/spot/domain/study/StudyPost.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,6 @@ public void deleteLikedPost(StudyLikedPost likedPost) {
likedPosts.remove(likedPost);
}

public void updateImage(StudyPostImage studyPostImage) {
images.set(images.indexOf(studyPostImage), studyPostImage);
}

public void updateComment(StudyPostComment studyPostComment) {
comments.set(comments.indexOf(studyPostComment), studyPostComment);
}
Expand Down Expand Up @@ -152,4 +148,8 @@ public void updatePost(StudyPostRequestDTO.PostDTO requestDTO) {
member.updateStudyPost(this);
study.updateStudyPost(this);
}

public void updateImage(StudyPostImage studyPostImage) {
images.set(images.indexOf(studyPostImage), studyPostImage);
}
}
2 changes: 2 additions & 0 deletions src/main/java/com/example/spot/service/auth/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@ public interface AuthService {
MemberResponseDTO.AvailabilityDTO checkLoginIdAvailability(String loginId);

MemberResponseDTO.AvailabilityDTO checkEmailAvailability(String email);

MemberResponseDTO.CheckMemberDTO checkIsSpotMember(Long loginId);
}
11 changes: 11 additions & 0 deletions src/main/java/com/example/spot/service/auth/AuthServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.example.spot.repository.MemberThemeRepository;
import com.example.spot.repository.PreferredRegionRepository;
import com.example.spot.repository.StudyReasonRepository;
import com.example.spot.web.dto.member.MemberResponseDTO.CheckMemberDTO;
import com.example.spot.web.dto.rsa.Rsa;
import com.example.spot.domain.auth.RefreshToken;
import com.example.spot.domain.auth.VerificationCode;
Expand Down Expand Up @@ -670,6 +671,16 @@ public MemberResponseDTO.AvailabilityDTO checkEmailAvailability(String email) {
return MemberResponseDTO.AvailabilityDTO.toDTO(Boolean.TRUE, null);
}

@Override
public CheckMemberDTO checkIsSpotMember(Long loginId) {
Member member = memberRepository.findById(loginId)
.orElseThrow(() -> new MemberHandler(ErrorStatus._MEMBER_NOT_FOUND));

boolean memberExistsByCheckList = isMemberExistsByCheckList(member);

return CheckMemberDTO.toDTO(memberExistsByCheckList);
}

/**
* 임시 비밀번호를 발급하는 메서드입니다.
* 알파벳 대소문자, 숫자, 특수기호를 혼합하여 13자리 비밀번호를 생성합니다.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
Expand Down Expand Up @@ -96,26 +97,28 @@ public StudyPostResDTO.PostPreviewDTO createPost(Long studyId, StudyPostRequestD
.likeNum(0)
.hitNum(0)
.commentNum(0)
.member(member)
.study(study)
.build();

// 공지면 announcedAt 설정
if (studyPost.getIsAnnouncement()) {
studyPost.setAnnouncedAt(LocalDateTime.now());
}

studyPost = studyPostRepository.save(studyPost);
member.addStudyPost(studyPost);
study.addStudyPost(studyPost);
studyPost = studyPostRepository.save(studyPost);

if (postRequestDTO.getImages() != null && !postRequestDTO.getImages().isEmpty()) {
ImageResponse.ImageUploadResponse imageUploadResponse = s3ImageService.uploadImages(postRequestDTO.getImages());
for (ImageResponse.Images imageDTO : imageUploadResponse.getImageUrls()) {
String imageUrl = imageDTO.getImageUrl();
StudyPostImage studyPostImage = new StudyPostImage(imageUrl);
studyPost.addImage(studyPostImage); // image id가 저장되지 않음
studyPostImage = studyPostImageRepository.save(studyPostImage);
studyPost.updateImage(studyPostImage); // image id 저장
}
// 이미지가 있는 경우 이미지 저장
if (postRequestDTO.getImage() != null) {
String imageUrl = s3ImageService.upload(postRequestDTO.getImage());
StudyPostImage studyPostImage = StudyPostImage.builder()
.url(imageUrl)
.studyPost(studyPost)
.build();
studyPostImage = studyPostImageRepository.save(studyPostImage);
studyPost.addImage(studyPostImage);
}

if (studyPost.getIsAnnouncement()){
Expand Down Expand Up @@ -154,9 +157,9 @@ public StudyPostResDTO.PostPreviewDTO updatePost(Long studyId, Long postId, Stud
Long memberId = SecurityUtils.getCurrentUserId();
SecurityUtils.verifyUserId(memberId);

Member member = memberRepository.findById(memberId)
memberRepository.findById(memberId)
.orElseThrow(() -> new MemberHandler(ErrorStatus._MEMBER_NOT_FOUND));
Study study = studyRepository.findById(studyId)
studyRepository.findById(studyId)
.orElseThrow(() -> new StudyHandler(ErrorStatus._STUDY_NOT_FOUND));
StudyPost studyPost = studyPostRepository.findById(postId)
.orElseThrow(() -> new StudyHandler(ErrorStatus._STUDY_POST_NOT_FOUND));
Expand All @@ -174,25 +177,28 @@ public StudyPostResDTO.PostPreviewDTO updatePost(Long studyId, Long postId, Stud
throw new StudyHandler(ErrorStatus._STUDY_POST_ANNOUNCEMENT_INVALID);
}

// 스터디 게시글 이미지 업데이트
updateStudyPostImage(postDTO, studyPost);

// 스터디 게시글 업데이트
studyPost.updatePost(postDTO);
studyPost = studyPostRepository.save(studyPost);

// 기존 게시글 이미지 삭제
studyPostImageRepository.deleteAllByStudyPostId(postId);

if (postDTO.getImages() != null && !postDTO.getImages().isEmpty()) {
ImageResponse.ImageUploadResponse imageUploadResponse = s3ImageService.uploadImages(postDTO.getImages());
for (ImageResponse.Images imageDTO : imageUploadResponse.getImageUrls()) {
String imageUrl = imageDTO.getImageUrl();
StudyPostImage studyPostImage = new StudyPostImage(imageUrl);
studyPost.addImage(studyPostImage); // image id가 저장되지 않음
studyPostImage = studyPostImageRepository.save(studyPostImage);
studyPost.updateImage(studyPostImage); // image id 저장
return StudyPostResDTO.PostPreviewDTO.toDTO(studyPost);
}

private void updateStudyPostImage(StudyPostRequestDTO.PostDTO postDTO, StudyPost studyPost) {
List<StudyPostImage> studyPostImages = studyPost.getImages();
// 기존 이미지가 존재하는 경우 이미지 유지
if (!StringUtils.hasText(postDTO.getExistingImage())) {
// 기존 이미지가 없고 새로운 이미지를 등록한 경우 이미지 url 변경
if (postDTO.getImage() != null) {
String imageUrl = s3ImageService.upload(postDTO.getImage());
studyPostImages.forEach(studyPostImage -> {
studyPostImage.setUrl(imageUrl);
studyPost.updateImage(studyPostImage);
});
}
}

return StudyPostResDTO.PostPreviewDTO.toDTO(studyPost);
}

/**
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/com/example/spot/web/controller/AuthController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.example.spot.api.ApiResponse;
import com.example.spot.api.code.status.SuccessStatus;
import com.example.spot.security.utils.SecurityUtils;
import com.example.spot.web.dto.rsa.Rsa;
import com.example.spot.service.auth.AuthService;
import com.example.spot.validation.annotation.TextLength;
Expand Down Expand Up @@ -268,6 +269,19 @@ public ApiResponse<MemberResponseDTO.MemberSignInDTO> login(
return ApiResponse.onSuccess(SuccessStatus._MEMBER_SIGNED_IN, memberSignInDTO);
}

@Tag(name = "회원 관리 API - 개발 완료", description = "회원 관리 API")
@Operation(summary = "[가입 유무 확인] 서비스 가입 유무 확인 API",
description = """
## [가입 유무 확인] 서비스 가입 유무 확인 API입니다.
해당 유저가 가입 후 체크리스트를 작성 했는지 확인합니다.
* 가입 후 체크리스트를 작성한 경우 true, 작성하지 않은 경우 false를 반환합니다.
""")
@GetMapping("/check")
public ApiResponse<MemberResponseDTO.CheckMemberDTO> checkIsSpotMember() {
MemberResponseDTO.CheckMemberDTO checkMemberDTO = authService.checkIsSpotMember(SecurityUtils.getCurrentUserId());
return ApiResponse.onSuccess(SuccessStatus._MEMBER_SIGNUP_CHECK_COMPLETED, checkMemberDTO);
}

/* ----------------------------- 로그아웃 API ------------------------------------- */

@Tag(name = "회원 관리 API - 개발 중", description = "회원 관리 API")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ public class StudyPostController {
public ApiResponse<StudyPostResDTO.PostPreviewDTO> createPost(
@PathVariable @ExistStudy Long studyId,
@ModelAttribute(name = "post") @Valid StudyPostRequestDTO.PostDTO postRequestDTO) {
if (postRequestDTO.getImages() == null) {
postRequestDTO.initImages();
}
StudyPostResDTO.PostPreviewDTO postPreviewDTO = studyPostCommandService.createPost(studyId, postRequestDTO);
return ApiResponse.onSuccess(SuccessStatus._STUDY_POST_CREATED, postPreviewDTO);
}
Expand All @@ -74,9 +71,6 @@ public ApiResponse<StudyPostResDTO.PostPreviewDTO> updatePost(
@PathVariable @ExistStudyPost Long postId,
@ModelAttribute(name= "post") @Valid StudyPostRequestDTO.PostDTO postDTO
) {
if (postDTO.getImages() == null) {
postDTO.initImages();
}
StudyPostResDTO.PostPreviewDTO postPreviewDTO = studyPostCommandService.updatePost(studyId, postId, postDTO);
return ApiResponse.onSuccess(SuccessStatus._STUDY_POST_UPDATED, postPreviewDTO);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ public static SocialLoginSignInDTO toDTO(Boolean isSpotMember, MemberSignInDTO s
.build();
}
}
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@Builder(access = AccessLevel.PRIVATE)
public static class CheckMemberDTO {
private final Boolean isSpotMember;

public static CheckMemberDTO toDTO(Boolean isSpotMember) {
return CheckMemberDTO.builder()
.isSpotMember(isSpotMember)
.build();
}
}

@Getter
@RequiredArgsConstructor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,11 @@ public static class PostDTO {
@Schema(description = "내용", example = "content")
private String content;

@Schema(description = "이미지")
private List<MultipartFile> images;
@Schema(description = "신규 이미지")
private MultipartFile image;

public void initImages() {
this.images = new ArrayList<>();
}
@Schema(description = "기존 이미지")
private String existingImage;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.example.spot.domain.study.StudyPost;
import com.example.spot.domain.study.StudyPostComment;
import com.example.spot.repository.*;
import com.example.spot.service.s3.S3ImageService;
import com.example.spot.web.dto.memberstudy.request.StudyPostCommentRequestDTO;
import com.example.spot.web.dto.memberstudy.request.StudyPostRequestDTO;
import com.example.spot.web.dto.memberstudy.response.StudyPostCommentResponseDTO;
Expand All @@ -30,6 +31,7 @@
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -70,6 +72,9 @@ class StudyPostCommandServiceTest {
@Mock
private NotificationRepository notificationRepository;

@Mock
private S3ImageService s3ImageService;

@InjectMocks
private StudyPostCommandServiceImpl studyPostCommandService;

Expand Down Expand Up @@ -125,12 +130,15 @@ void setUp() {
when(studyLikedPostRepository.existsByMemberIdAndStudyPostId(3L, 1L))
.thenReturn(true);

// Comment
// Comment
when(studyPostCommentRepository.findAllByStudyPostId(1L))
.thenReturn(List.of(studyPost1Comment1, studyPost1Comment2));
when(studyPostCommentRepository.findById(1L)).thenReturn(Optional.of(studyPost1Comment1));
when(studyPostCommentRepository.findById(2L)).thenReturn(Optional.of(studyPost1Comment2));

// S3
when(s3ImageService.upload(any(MultipartFile.class))).thenReturn("url");

}

/*-------------------------------------------------------- 게시글 작성 ------------------------------------------------------------------------*/
Expand Down
Loading