Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0144409
Update main-cd.yml
wodydl0 Feb 24, 2025
d6b15cc
Merge pull request #16 from Ring-Us/main-cd/fix/2
wodydl0 Feb 24, 2025
fc17b48
Fix/main cd/v3 (#18)
wodydl0 Feb 24, 2025
2f89d3b
RINGUS-34 feat: 멘티 프로필 등록 기능 구현 (#20)
wlgns12370 Feb 24, 2025
1938d49
RINGUS-36: feat: 멤버Id 및 파일경로 매핑 테이블 생성 (#21)
jbh010204 Feb 24, 2025
ca39adc
RINGUS-35 feat: 멘토 멘티 프로필 수정 API 개발 (#22)
wlgns12370 Feb 25, 2025
cf5d132
RINGUS-37 chore: 스웨거 접속 경로 변경 (#23)
jbh010204 Feb 25, 2025
8ca92cb
refactor: 프론트엔드 배포 도메인 CORS 허용
jbh010204 Feb 25, 2025
03685b9
chore: DB 마이그레이션을 위한 Flyway 도입 (#24)
jbh010204 Feb 27, 2025
7bffbf4
RINGUS-40 feat: 북마크 생성 및 삭제 API 구현 (#25)
jbh010204 Feb 27, 2025
6ce9e23
RINGUS-45 feat: SessionMemberId 커스텀 어노테이션 구현 (#26)
jbh010204 Feb 28, 2025
e2494db
RINGUS-44 refactor: 파일 로드 api 리팩토링 (#28)
wodydl0 Feb 28, 2025
2f78be1
fix: ci 코드 수정 (#31)
wodydl0 Feb 28, 2025
b7f9be7
feat: storage swagger docs 작성 (#32)
wodydl0 Mar 1, 2025
a69f1f1
RINGUS-48 refactor: 멘토 엔티티 세부필드 변경 (#33)
jbh010204 Mar 4, 2025
2662f85
RINGUS-49 docs: 내 프로필 상세 조회 Docs 작성 (#34)
wlgns12370 Mar 5, 2025
57cc5b7
RINGUS-52 fix: 내 멤버 조회 imgUrl 필드 추가 (#35)
wlgns12370 Mar 6, 2025
896f5b9
RINGUS-46 feat: 멘토링 제안 api (#36)
wodydl0 Mar 7, 2025
9cce0df
RINGUS-53 feat: 세션검증을 담당할 어노테이션 기능 구현 (#37)
jbh010204 Mar 10, 2025
78fe040
RINGUS-58 chore: multipart 파일크기 제한 수정 및 멘토링 flyway 스키마 추가(#38)
wodydl0 Mar 13, 2025
aa78523
RINGUS-27 feat: 멘토 프로필 목록 조회 API 구현 (#39)
wlgns12370 Mar 13, 2025
862feb0
RINGUS-57 feat: 닉네임 중복 검사 API 구현 (#40)
jbh010204 Mar 15, 2025
b9585c1
RINGUS-61 feat: 내 프로필 조회 API 구현 (#41)
wlgns12370 Mar 15, 2025
fc22c19
RINGUS-62 feat: 북마크 멘토 목록 조회 기능 추가 (#42)
jbh010204 Mar 15, 2025
1870361
RINGUS-62 fix: 로그인 아닐 떄 멘토 목록 조회 안되는 오류 수정 (#43)
jbh010204 Mar 16, 2025
f2a7563
RINGUS-63 feat: 내 멤버 조회 닉네임 필드 추가 (#44)
wlgns12370 Mar 18, 2025
ee0374d
RINGUS-60 feat: MentoringStatus ENUM 변경 및 MentorQueryDsl queryFilter …
wodydl0 Mar 21, 2025
0ba4af0
RINGUS-64 feat: 멘토링 멘티 목록 조회 (#46)
jbh010204 Mar 22, 2025
f40c94b
RINGUS-64 fix: git 스테이징 안된 파일 push (#47)
jbh010204 Mar 22, 2025
289f4f6
RINGUS-64 refactor: 닉네임 중복 검사 POST에서 GET으로 변경 (#48)
jbh010204 Mar 23, 2025
759d232
RINGUS-66 feat: 멘토 멘토링 수락 API 개발 (#49)
wlgns12370 Mar 24, 2025
7a0362b
Fix: CORS 문제 해결 (#50)
wlgns12370 Mar 24, 2025
371ff2d
RINGUS-70 rename: 변경된 이미지 응답 필드 반영 (#51)
wlgns12370 Mar 25, 2025
a51e3cf
RINGUS-70 feat: 멘토링 count 필드 추가 (#52)
wlgns12370 Mar 25, 2025
a4d33ea
Update main-cd.yml/v4
wodydl0 Mar 26, 2025
f48cf9a
Update main-cd.yml/v5 (#54)
wodydl0 Mar 26, 2025
dddbc02
RINGUS-70 feat: 멘토링 count 쿼리 구현 (#56)
wlgns12370 Mar 26, 2025
94f99c3
RINGUS-70 Fix: QueryDsl 생성자 주입 추가 (#57)
wlgns12370 Mar 26, 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
17 changes: 5 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
name: CI Workflow

on:
push:
branches:
- main # main 브랜치
- develop # develop 브랜치
- feature/* # 모든 feature/* 브랜치
pull_request:
branches:
- main # main 브랜치로의 PR
- develop # develop 브랜치로의 PR
- feature/* # feature/* 브랜치로의 PR

jobs:
build-and-test:
Expand Down Expand Up @@ -39,14 +33,13 @@ jobs:
restore-keys: |
${{ runner.os }}-gradle-

- name: Create .env.dev file
run: |
touch .env.dev
echo "${{ secrets.ENV }}" >> .env.dev

# 4. dev.sh 실행 (환경 변수 로드 및 빌드 준비)
- name: Run dev.sh
run: |
chmod +x ./dev.sh # dev.sh에 실행 권한 부여
./dev.sh # dev.sh 실행

# 5. Gradle 빌드 및 테스트 실행
- name: Build and Test (Gradle)
run: |
./gradlew clean build -x test
./gradlew test
13 changes: 11 additions & 2 deletions .github/workflows/main-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,18 @@ jobs:
git clone [email protected]:Ring-Us/ring-us-server.git /home/ubuntu/ring-us-server
cd /home/ubuntu/ring-us-server
fi

cd /home/ubuntu/ring-us-server

echo "${{ secrets.ENV }}" > .env.dev

# 🛠 Gradle 빌드 권한 설정
echo "[GitHub Actions] 🔧 Fixing Gradle permissions"
sudo chown -R $USER:$USER ~/.gradle
sudo chmod -R 777 ~/.gradle

# 권한 설정 (dev.sh 실행 가능하도록, 추후에 deploy.sh와 분리)
chmod +x dev.sh
sudo chmod +x dev.sh

# 스크립트 실행 (환경 변수 로드, 빌드, 배포 포함)
./dev.sh
sudo ./dev.sh
8 changes: 8 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-mysql'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.mysql:mysql-connector-j'
Expand All @@ -46,6 +48,12 @@ dependencies {
implementation 'software.amazon.awssdk:sts'
implementation 'software.amazon.awssdk:core:2.30.20'
implementation 'software.amazon.awssdk:ec2'

// QueryDSL
implementation "com.querydsl:querydsl-jpa:5.0.0:jakarta"
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api:3.0.0"
annotationProcessor "jakarta.persistence:jakarta.persistence-api:3.1.0"
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package es.princip.ringus.application.bookmark;

import es.princip.ringus.domain.bookmark.Bookmark;
import es.princip.ringus.domain.bookmark.BookmarkRepository;
import es.princip.ringus.domain.exception.BookmarkErrorCode;
import es.princip.ringus.domain.exception.MenteeErrorCode;
import es.princip.ringus.domain.exception.MentorErrorCode;
import es.princip.ringus.domain.mentee.Mentee;
import es.princip.ringus.domain.mentee.MenteeRepository;
import es.princip.ringus.domain.mentor.Mentor;
import es.princip.ringus.domain.mentor.MentorRepository;
import es.princip.ringus.global.exception.CustomRuntimeException;
import es.princip.ringus.presentation.bookmark.dto.BookmarkRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class BookmarkService {
private final BookmarkRepository bookmarkRepository;
private final MentorRepository mentorRepository;
private final MenteeRepository menteeRepository;

@Transactional
public Long addBookmark(BookmarkRequest request){
Mentor mentor = findMentorById(request.mentorId());
Mentee mentee = findMenteeById(request.menteeId());

if(bookmarkRepository.findByMentorAndMentee(mentor, mentee).isPresent()){
throw new CustomRuntimeException(BookmarkErrorCode.BOOKMARK_ALREADY_EXIST);
}

Bookmark bookmark = request.toEntity(mentor, mentee);
mentee.addBookmark(bookmark);

return bookmarkRepository.save(bookmark).getId();
}

@Transactional
public void deleteBookmark(BookmarkRequest request){
Mentor mentor = findMentorById(request.mentorId());
Mentee mentee = findMenteeById(request.menteeId());

Bookmark bookmark = bookmarkRepository.findByMentorAndMentee(mentor, mentee)
.orElseThrow(() -> new CustomRuntimeException(BookmarkErrorCode.BOOKMARK_NOT_FOUND));

bookmarkRepository.delete(bookmark);
mentee.deleteBookmark(bookmark);
}

private Mentor findMentorById(Long mentorId) {
return mentorRepository.findById(mentorId)
.orElseThrow(() -> new CustomRuntimeException(MentorErrorCode.MENTOR_PROFILE_NOT_FOUND));
}

private Mentee findMenteeById(Long menteeId) {
return menteeRepository.findById(menteeId)
.orElseThrow(() -> new CustomRuntimeException(MenteeErrorCode.MENTEE_PROFILE_NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package es.princip.ringus.application.member.service;

import es.princip.ringus.domain.mentor.vo.Organization;
import es.princip.ringus.infra.storage.domain.ProfileImage;

public record MemberMentorProfile(
ProfileImage profileImage,
Organization organization
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,36 @@
import es.princip.ringus.domain.exception.SignUpErrorCode;
import es.princip.ringus.domain.member.Member;
import es.princip.ringus.domain.member.MemberRepository;
import es.princip.ringus.domain.mentee.Mentee;
import es.princip.ringus.domain.mentee.MenteeRepository;
import es.princip.ringus.domain.mentor.Mentor;
import es.princip.ringus.domain.mentor.MentorRepository;
import es.princip.ringus.domain.mentoring.MentoringRepository;
import es.princip.ringus.domain.serviceTerm.ServiceTermAgreement;
import es.princip.ringus.global.exception.CustomRuntimeException;
import es.princip.ringus.global.util.UniversityDomainUtil;
import es.princip.ringus.presentation.auth.dto.request.SignUpRequest;
import es.princip.ringus.presentation.member.dto.MemberResponse;
import es.princip.ringus.presentation.member.dto.MenteeProfileResponse;
import es.princip.ringus.presentation.member.dto.MentorProfileResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Set;

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {
private final MemberRepository memberRepository;
private final MentorRepository mentorRepository;
private final MenteeRepository menteeRepository;
private final PasswordEncoder passwordEncoder;
private final MentoringRepository mentoringRepository;

/**
* 회원 저장 (이메일 인증 후 회원가입 진행)
Expand All @@ -43,10 +55,29 @@ public Member createMember(SignUpRequest request, Set<ServiceTermAgreement> serv
return member;
}

public MemberResponse getMemberById(Long memberId){
public MemberResponse getMember(Long memberId) {
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new CustomRuntimeException(MemberErrorCode.MEMBER_NOT_FOUND));

return MemberResponse.from(member);
if (member.isProfileRegistered()) {
if (member.isMentee()) {
Mentee mentee = menteeRepository.findByMemberId(memberId)
.orElseThrow(() -> new CustomRuntimeException(MemberErrorCode.MEMBER_NOT_FOUND));
MenteeProfileResponse profile = MenteeProfileResponse.from(mentee);
//null check 필요
return MemberResponse.of(member, profile);
} else if (member.isMentor()) {
Mentor mentor = mentorRepository.findByMemberId(memberId)
.orElseThrow(() -> new CustomRuntimeException(MemberErrorCode.MEMBER_NOT_FOUND));

MentorProfileResponse profile = MentorProfileResponse.from(mentor, mentoringRepository.findMentoringCountBy(mentor.getId()));
return MemberResponse.of(member, profile);
}
}
return MemberResponse.of(member);
}

public boolean isUniqueNickname(String nickname) {
return !mentorRepository.existsByNickname(nickname) && !menteeRepository.existsByNickname(nickname);
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package es.princip.ringus.application.mentee.service;

import es.princip.ringus.application.support.MenteeCursorParser;
import es.princip.ringus.domain.exception.MenteeErrorCode;
import es.princip.ringus.domain.exception.SignUpErrorCode;
import es.princip.ringus.domain.member.Member;
import es.princip.ringus.domain.member.MemberRepository;
import es.princip.ringus.domain.mentee.Mentee;
import es.princip.ringus.domain.mentee.MenteeRepository;
import es.princip.ringus.domain.mentor.MentorRepository;
import es.princip.ringus.domain.support.CursorResponse;
import es.princip.ringus.global.exception.CustomRuntimeException;
import es.princip.ringus.presentation.mentee.dto.EditMenteeRequest;
import es.princip.ringus.presentation.mentee.dto.MenteeCardResponse;
import es.princip.ringus.presentation.mentee.dto.MenteeCursorRequest;
import es.princip.ringus.presentation.mentee.dto.MenteeRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -21,10 +28,37 @@ public class MenteeService {
private final MenteeRepository menteeRepository;

@Transactional
public Long register(MenteeRequest request) {
Member member = memberRepository.findByEmail(request.email())
.orElseThrow(() -> new CustomRuntimeException(SignUpErrorCode.WRONG_EMAIL));
Mentee mentee = request.toEntity();
public Long register(Long memberId, MenteeRequest request) {
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new CustomRuntimeException(SignUpErrorCode.NOT_FOUND_MEMBER));

if (menteeRepository.existsByMemberId(memberId)) {
throw new CustomRuntimeException(MenteeErrorCode.ALREADY_REGISTERED_MENTEE);
}

if (member.isNotMentee()) {
throw new CustomRuntimeException(MenteeErrorCode.MEMBER_TYPE_NOT_MENTEE);
}

member.registerProfile();

Mentee mentee = request.toEntity(member.getId());
return menteeRepository.save(mentee).getId();
}

@Transactional
public Long edit(Long memberId, EditMenteeRequest request) {
Mentee mentee = menteeRepository.findByMemberId(memberId)
.orElseThrow(() -> new CustomRuntimeException(MenteeErrorCode.MENTEE_PROFILE_NOT_FOUND));

mentee.edit(request);
return mentee.getId();
}

public CursorResponse<MenteeCardResponse> getMenteeBy(MenteeCursorRequest request, Pageable pageable, Long memberId){
final Slice<MenteeCardResponse> response = menteeRepository.findMenteeBy(request, pageable, memberId);
final Long cursor = MenteeCursorParser.parse(request.cursor(), response);

return CursorResponse.of(response, cursor);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package es.princip.ringus.application.mentee.service;

import es.princip.ringus.domain.exception.MenteeErrorCode;
import es.princip.ringus.domain.mentee.Mentee;
import es.princip.ringus.domain.mentee.MenteeRepository;
import es.princip.ringus.global.exception.CustomRuntimeException;
import es.princip.ringus.presentation.mentee.dto.MyMenteeResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MyMenteeService {
private final MenteeRepository menteeRepository;

public MyMenteeResponse getDetailBy(Long mentorId) {
Mentee mentee = menteeRepository.findByMemberId(mentorId)
.orElseThrow(() -> new CustomRuntimeException(MenteeErrorCode.MENTEE_NOT_FOUND));
return MyMenteeResponse.from(mentee);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package es.princip.ringus.application.mentor.service;

import es.princip.ringus.domain.exception.MenteeErrorCode;
import es.princip.ringus.domain.exception.MentorErrorCode;
import es.princip.ringus.domain.exception.MentoringErrorCode;
import es.princip.ringus.domain.mentee.Mentee;
import es.princip.ringus.domain.mentee.MenteeRepository;
import es.princip.ringus.domain.mentor.Mentor;
import es.princip.ringus.domain.mentor.MentorRepository;
import es.princip.ringus.domain.mentoring.Mentoring;
import es.princip.ringus.domain.mentoring.MentoringRepository;
import es.princip.ringus.domain.mentoring.MentoringTime;
import es.princip.ringus.domain.mentoring.accept.MentoringAccept;
import es.princip.ringus.domain.mentoring.accept.MentoringAcceptRepository;
import es.princip.ringus.global.exception.CustomRuntimeException;
import es.princip.ringus.presentation.mentoring.dto.AcceptMentoringRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class AcceptMentoringService {
private final MentorRepository mentorRepository;
private final MenteeRepository menteeRepository;
private final MentoringRepository mentoringRepository;
private final MentoringAcceptRepository mentoringAcceptRepository;

private boolean isRequestedTimeInMentoringTime(Mentoring mentoring, AcceptMentoringRequest request) {
return mentoring.getApplyTimes().stream()
.anyMatch(time -> MentoringTime.equals(time, request.mentoringTime()));
}

public Long accept(AcceptMentoringRequest request, Long memberId) {
Mentor mentor = mentorRepository.findByMemberId(memberId)
.orElseThrow(() -> new CustomRuntimeException(MentorErrorCode.MENTOR_NOT_FOUND));
Mentee mentee = menteeRepository.findById(request.menteeId())
.orElseThrow(() -> new CustomRuntimeException(MenteeErrorCode.MENTEE_NOT_FOUND));

Mentoring mentoring = mentoringRepository.findByMenteeIdAndMentorId(mentee.getId(), mentor.getId())
.orElseThrow(() -> new CustomRuntimeException(MentoringErrorCode.MENTORING_NOT_FOUND));

if (mentoring.isNotWaiting()) {
throw new CustomRuntimeException(MentoringErrorCode.MENTORING_STATUS_NOT_WAITING);
}
if (!isRequestedTimeInMentoringTime(mentoring, request)) {
throw new CustomRuntimeException(MentoringErrorCode.MENTORING_TIME_NOT_MATCH);
}

MentoringAccept accept = MentoringAccept.builder()
.mentee(mentee)
.mentor(mentor)
.mentoringTime(request.mentoringTime())
.build();
mentoring.accept();

return mentoringAcceptRepository.save(accept).getId();
}
}
Loading