Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
31ca4b3
[EA3-168] feature: 스터디 신청 기능
pia01190 Jul 21, 2025
23b7b08
[EA3-168] feature: 스터디 신청 목록 조회 기능
pia01190 Jul 21, 2025
6cfb996
[EA3-134] chore: 스터디 모임시간 조율 - service 제외
endorsement0912 Jul 22, 2025
ca8a599
Merge pull request #171 from prgrms-web-devcourse-final-project/featu…
pia01190 Jul 22, 2025
271f29e
[EA3-168] feature: 스터디 신청 승인 기능
pia01190 Jul 22, 2025
1a81270
[EA3-173] feature:구글 로그인 시 PR 템플릿 자동 생성 추가 및 회원 정보 조회에 OAuth정보 추가
hyeunS-P Jul 22, 2025
9be32ba
[EA3-168] feature: 스터디 신청 거절 기능
pia01190 Jul 22, 2025
ce964f2
[EA3-168] refactor: ApplicationController RequestMapping 변경
pia01190 Jul 22, 2025
f59f2bf
[EA3-111] refactor : dto 및 서비스 리팩토링
dbrkdgus00 Jul 22, 2025
36a27df
[EA3-168] refactor: ApplicationCreateRequest 변경 및 코드 리팩터링
pia01190 Jul 22, 2025
f27c120
[EA3-168] chore: import문 정리
pia01190 Jul 22, 2025
29a8eda
Merge branch 'develop' of https://github.com/prgrms-web-devcourse-fin…
dbrkdgus00 Jul 22, 2025
b362131
[EA3-168] feature: 스터디 신청 생성, 거절, 승인 테스트 작성
pia01190 Jul 22, 2025
92d1bb2
Merge branch 'develop' of https://github.com/prgrms-web-devcourse-fin…
pia01190 Jul 22, 2025
002fc80
[EA3-167] refactor: study finished 필드 추가
pia01190 Jul 22, 2025
c2376fc
[EA3-167] refactor: sql study insert문 finished 추가
pia01190 Jul 22, 2025
23b9161
[EA3-167] feature: 종료 7일 전 스터디 찾는 기능
pia01190 Jul 22, 2025
85ce98f
[EA3-167] feature: 종료 날짜 지난 스터디 종료 상태 변경 기능
pia01190 Jul 22, 2025
87078b9
[EA3-167] chore: import문 정리
pia01190 Jul 22, 2025
fe48dd5
[EA3-173] feature:회원가입 시 이메일 인증 과정 추가
hyeunS-P Jul 22, 2025
c80ba9b
[EA3-111] feature : data.sql comment 문 주석처리 및 그룹채팅 테스트 위한 html 파일 생성
dbrkdgus00 Jul 22, 2025
493fe8d
Merge pull request #172 from prgrms-web-devcourse-final-project/featu…
hyeunS-P Jul 22, 2025
285b198
Merge pull request #173 from prgrms-web-devcourse-final-project/featu…
hyeunS-P Jul 22, 2025
32748dd
Merge pull request #175 from prgrms-web-devcourse-final-project/featu…
pia01190 Jul 22, 2025
361bd92
Merge pull request #174 from prgrms-web-devcourse-final-project/featu…
pia01190 Jul 22, 2025
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
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ dependencies {

// WebSocket + STOMP 통신용
implementation 'org.springframework.boot:spring-boot-starter-websocket'

// 이메일 전송 의존성
implementation 'org.springframework.boot:spring-boot-starter-mail'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class AdminStudyResponse {
private Category category;

@Schema(description = "스터디 종료 여부", example = "false")
private boolean isFinished;
private boolean finished;

@Schema(description = "활성화 여부", example = "true")
private boolean activated;
Expand All @@ -33,7 +33,7 @@ private AdminStudyResponse(Long id, String name, Category category, boolean isFi
this.id = id;
this.name = name;
this.category = category;
this.isFinished = isFinished;
this.finished = isFinished;
this.activated = activated;
}

Expand All @@ -42,7 +42,7 @@ public static AdminStudyResponse from(Study study) {
.id(study.getId())
.name(study.getName())
.category(study.getCategory())
.isFinished(study.getEndDate().toLocalDate().isBefore(LocalDate.now()))
.isFinished(study.isFinished())
.activated(study.getActivated())
.build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package grep.neogul_coder.domain.groupchat.controller.dto.requset;

import grep.neogul_coder.domain.groupchat.entity.GroupChatMessage;
import grep.neogul_coder.domain.groupchat.entity.GroupChatRoom;
import io.swagger.v3.oas.annotations.Hidden;
import java.time.LocalDateTime;
import lombok.Getter;

@Hidden
Expand All @@ -18,15 +21,12 @@ public GroupChatMessageRequestDto(Long roomId, Long senderId, String message) {
this.message = message;
}

public void setRoomId(Long roomId) {
this.roomId = roomId;
}

public void setSenderId(Long senderId) {
this.senderId = senderId;
}

public void setMessage(String message) {
this.message = message;
public GroupChatMessage toEntity(GroupChatRoom room, Long senderId) {
return new GroupChatMessage(
room,
senderId,
this.message,
LocalDateTime.now()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,4 @@ public class GroupChatSwaggerRequest {

@Schema(description = "보낼 메시지", example = "안녕하세요!")
private String message;


public void setSenderId(Long senderId) { this.senderId = senderId; }

public void setRoomId(Long roomId) { this.roomId = roomId; }

public void setMessage(String message) { this.message = message; }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package grep.neogul_coder.domain.groupchat.controller.dto.response;

import grep.neogul_coder.domain.groupchat.entity.GroupChatMessage;
import grep.neogul_coder.domain.users.entity.User;
import io.swagger.v3.oas.annotations.Hidden;
import java.time.LocalDateTime;
import lombok.Getter;
Expand All @@ -16,10 +18,7 @@ public class GroupChatMessageResponseDto {
private String message; // 메시지 내용
private LocalDateTime sentAt; // 보낸 시간

public GroupChatMessageResponseDto() {
}

public GroupChatMessageResponseDto(Long id, Long roomId, Long senderId,
private GroupChatMessageResponseDto(Long id, Long roomId, Long senderId,
String senderNickname, String profileImageUrl,
String message, LocalDateTime sentAt) {
this.id = id;
Expand All @@ -31,31 +30,15 @@ public GroupChatMessageResponseDto(Long id, Long roomId, Long senderId,
this.sentAt = sentAt;
}

public void setId(Long id) {
this.id = id;
}

public void setRoomId(Long roomId) {
this.roomId = roomId;
}

public void setSenderId(Long senderId) {
this.senderId = senderId;
}

public void setSenderNickname(String senderNickname) {
this.senderNickname = senderNickname;
}

public void setProfileImageUrl(String profileImageUrl) {
this.profileImageUrl = profileImageUrl;
}

public void setMessage(String message) {
this.message = message;
}

public void setSentAt(LocalDateTime sentAt) {
this.sentAt = sentAt;
public static GroupChatMessageResponseDto from(GroupChatMessage message, User sender) {
return new GroupChatMessageResponseDto(
message.getMessageId(),
message.getGroupChatRoom().getRoomId(),
sender.getId(),
sender.getNickname(),
sender.getProfileImageUrl(),
message.getMessage(),
message.getSentAt()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,14 @@ public class GroupChatMessage extends BaseEntity {

private LocalDateTime sentAt;

public void setMessageId(Long messageId) {
this.messageId = messageId;
}

public void setGroupChatRoom(GroupChatRoom groupChatRoom) {
this.groupChatRoom = groupChatRoom;
}

public void setUserId(Long userId) {
public GroupChatMessage(GroupChatRoom room, Long userId, String message, LocalDateTime sentAt) {
this.groupChatRoom = room;
this.userId = userId;
}

public void setMessage(String message) {
this.message = message;
this.sentAt = sentAt;
}

public void setSentAt(LocalDateTime sentAt) {
this.sentAt = sentAt;
protected GroupChatMessage() {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@

public interface GroupChatMessageRepository extends JpaRepository<GroupChatMessage, Long> {


// 채팅방(roomId)에 속한 메시지를 전송 시간 내림차순으로 페이징 조회
@Query("SELECT m FROM GroupChatMessage m " +
"WHERE m.groupChatRoom.roomId = :roomId " +
"ORDER BY m.sentAt ASC")
Page<GroupChatMessage> findMessagesByRoomIdAsc(@Param("roomId") Long roomId, Pageable pageable);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
import grep.neogul_coder.domain.users.entity.User;
import grep.neogul_coder.domain.users.repository.UserRepository;
import grep.neogul_coder.global.response.PageResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;

@RequiredArgsConstructor
@Service
public class GroupChatService {

Expand All @@ -25,17 +27,6 @@ public class GroupChatService {
private final UserRepository userRepository;
private final StudyMemberRepository studyMemberRepository;

// 생성자 주입을 통한 의존성 주입
public GroupChatService(GroupChatMessageRepository messageRepository,
GroupChatRoomRepository roomRepository,
UserRepository userRepository,
StudyMemberRepository studyMemberRepository) {
this.messageRepository = messageRepository;
this.roomRepository = roomRepository;
this.userRepository = userRepository;
this.studyMemberRepository = studyMemberRepository;
}

public GroupChatMessageResponseDto saveMessage(GroupChatMessageRequestDto requestDto) {
// 채팅방 존재 여부 확인
GroupChatRoom room = roomRepository.findById(requestDto.getRoomId())
Expand All @@ -51,26 +42,14 @@ public GroupChatMessageResponseDto saveMessage(GroupChatMessageRequestDto reques
throw new IllegalArgumentException("해당 스터디에 참가한 사용자만 채팅할 수 있습니다.");
}

// 메시지 생성 및 저장
GroupChatMessage message = new GroupChatMessage();
message.setGroupChatRoom(room); // 엔티티에 있는 필드명 맞게 사용
message.setUserId(sender.getId()); // 연관관계 없이 userId만 저장
message.setMessage(requestDto.getMessage());
message.setSentAt(LocalDateTime.now());
// 메시지 생성
GroupChatMessage message = requestDto.toEntity(room, sender.getId());

// 메시지 저장
messageRepository.save(message);

// 저장된 메시지를 dto로 변환
return new GroupChatMessageResponseDto(
message.getMessageId(),
message.getGroupChatRoom().getRoomId(), // ← roomId 필드가 필요하면 여기서 꺼내야 함
sender.getId(),
sender.getNickname(),
sender.getProfileImageUrl(),
message.getMessage(),
message.getSentAt()
);
// 응답 dto 생성
return GroupChatMessageResponseDto.from(message, sender);
}

// 과거 채팅 메시지 페이징 조회 (무한 스크롤용)
Expand All @@ -86,15 +65,7 @@ public PageResponse<GroupChatMessageResponseDto> getMessages(Long roomId, int pa
User sender = userRepository.findById(message.getUserId())
.orElseThrow(() -> new IllegalArgumentException("사용자가 존재하지 않습니다."));

return new GroupChatMessageResponseDto(
message.getMessageId(),
message.getGroupChatRoom().getRoomId(),
sender.getId(),
sender.getNickname(),
sender.getProfileImageUrl(),
message.getMessage(),
message.getSentAt()
);
return GroupChatMessageResponseDto.from(message, sender);
});

// PageResponse로 감싸서 반환
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import grep.neogul_coder.domain.study.Study;
import grep.neogul_coder.domain.study.repository.StudyRepository;
import grep.neogul_coder.domain.studyapplication.StudyApplication;
import grep.neogul_coder.domain.studyapplication.repository.StudyApplicationRepository;
import grep.neogul_coder.domain.studyapplication.repository.ApplicationRepository;
import grep.neogul_coder.global.exception.business.BusinessException;
import grep.neogul_coder.global.exception.business.NotFoundException;
import lombok.RequiredArgsConstructor;
Expand All @@ -40,7 +40,7 @@ public class RecruitmentPostService {
private final RecruitmentPostRepository postRepository;
private final RecruitmentPostQueryRepository postQueryRepository;

private final StudyApplicationRepository studyApplicationRepository;
private final ApplicationRepository applicationRepository;
private final RecruitmentPostCommentQueryRepository commentQueryRepository;

public RecruitmentPostInfo get(long recruitmentPostId) {
Expand All @@ -49,7 +49,7 @@ public RecruitmentPostInfo get(long recruitmentPostId) {

RecruitmentPostWithStudyInfo postInfo = postQueryRepository.findPostWithStudyInfo(post.getId());
List<CommentsWithWriterInfo> comments = findCommentsWithWriterInfo(post);
List<StudyApplication> applications = studyApplicationRepository.findByRecruitmentPostId(post.getId());
List<StudyApplication> applications = applicationRepository.findByRecruitmentPostId(post.getId());

return new RecruitmentPostInfo(postInfo, comments, applications.size());
}
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/grep/neogul_coder/domain/study/Study.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public class Study extends BaseEntity {

private boolean extended;

private boolean finished;

protected Study() {}

@Builder
Expand All @@ -60,6 +62,7 @@ private Study(Long originStudyId, String name, Category category, int capacity,
this.introduction = introduction;
this.imageUrl = imageUrl;
this.extended = false;
this.finished = false;
}

public void update(String name, Category category, int capacity, StudyType studyType,
Expand All @@ -86,6 +89,10 @@ public long calculateRemainSlots(long currentCount) {
return this.capacity - currentCount;
}

public void increaseMemberCount() {
currentCount++;
}

public void decreaseMemberCount() {
currentCount--;
}
Expand All @@ -97,4 +104,8 @@ public boolean alreadyExtended() {
public void extend() {
this.extended = true;
}

public void finish() {
this.finished = true;
}
}
8 changes: 8 additions & 0 deletions src/main/java/grep/neogul_coder/domain/study/StudyMember.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ public StudyMember(Study study, Long userId, StudyMemberRole role) {
this.participated = false;
}

public static StudyMember createMember(Study study, Long userId) {
return StudyMember.builder()
.study(study)
.userId(userId)
.role(StudyMemberRole.MEMBER)
.build();
}

public void delete() {
this.activated = false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
package grep.neogul_coder.domain.study.controller.dto.response;

import com.querydsl.core.annotations.QueryProjection;
import grep.neogul_coder.domain.study.Study;
import grep.neogul_coder.domain.study.enums.Category;
import grep.neogul_coder.domain.study.enums.StudyType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;

import java.time.LocalDate;
import java.time.LocalDateTime;

@Getter
Expand Down Expand Up @@ -48,13 +45,11 @@ public class StudyItemResponse {
private StudyType studyType;

@Schema(description = "종료 여부", example = "false")
public boolean isFinished() {
return endDate.toLocalDate().isBefore(LocalDate.now());
}
private boolean finished;

@QueryProjection
public StudyItemResponse(Long studyId, String name, String leaderNickname, int capacity, int currentCount, LocalDateTime startDate,
LocalDateTime endDate, String imageUrl, String introduction, Category category, StudyType studyType) {
LocalDateTime endDate, String imageUrl, String introduction, Category category, StudyType studyType, boolean finished) {
this.studyId = studyId;
this.name = name;
this.leaderNickname = leaderNickname;
Expand All @@ -66,5 +61,6 @@ public StudyItemResponse(Long studyId, String name, String leaderNickname, int c
this.introduction = introduction;
this.category = category;
this.studyType = studyType;
this.finished = finished;
}
}
Loading