Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
221 commits
Select commit Hold shift + click to select a range
40edfff
chore: lottie 라이브러리 설치
ShipFriend0516 Nov 17, 2024
501b0bf
chore: lottie 라이브러리 타입 설치
ShipFriend0516 Nov 17, 2024
846fee6
feat: 에러페이지 구현
ShipFriend0516 Nov 17, 2024
464b6be
feat: 테스트를 위한 Jest 설치 및 기본 환경 설정
yiseungyun Nov 17, 2024
a77cf58
refactor: 세션 페이지 useSession 훅 분리
yiseungyun Nov 17, 2024
530b6a0
test: useSession 테스트 코드 작성
yiseungyun Nov 17, 2024
273ba3c
feat: 애니메이션 옆에 4 2개 붙이기
ShipFriend0516 Nov 17, 2024
6560e75
test: 소켓 연결, 이미 연결 됐을 때 연결 테스트
yiseungyun Nov 18, 2024
acd5828
feat: text 추가
ShipFriend0516 Nov 18, 2024
554610d
Merge branch 'dev' of https://github.com/boostcampwm-2024/web27-Previ…
yiseungyun Nov 18, 2024
21a645c
test: 스터디룸 입장 테스트
yiseungyun Nov 18, 2024
8b07d78
test: 닉네임 없이 입장 테스트
yiseungyun Nov 18, 2024
a0baf42
fix: joinRoom 토스트 에러 메시지 오류 수정
yiseungyun Nov 18, 2024
2abe710
test: 미디어 스트림 획득 실패 에러 테스트 및 닉네임 없이 입장 테스트 수정
yiseungyun Nov 18, 2024
a22efd4
test: 리액션 이벤트 발생 테스트
yiseungyun Nov 18, 2024
ff5e717
test: 소켓 이벤트 리스너 테스트
yiseungyun Nov 18, 2024
cf7971d
refactor: 불필요 테스트 삭제 및 MockPeerConnections 타입 추가
yiseungyun Nov 18, 2024
23a4435
Merge pull request #124 from ShipFriend0516/feature/error-page
yiseungyun Nov 18, 2024
fc05b4a
chore: lottie player 라이브러리 설치
ShipFriend0516 Nov 18, 2024
2caeecd
chore: 프로젝트에서 lottie 확장자를 인식할 수 있도록 타입 및 assets 설정
ShipFriend0516 Nov 18, 2024
e94ed06
feat: 로그인페이지 UI 구현
ShipFriend0516 Nov 18, 2024
70ab941
chore: index.html 페이지 타이틀 수정
ShipFriend0516 Nov 18, 2024
ded03b7
feat: 로그인 페이지 애니메이션 섹션, 반응형으로 수정
ShipFriend0516 Nov 18, 2024
acbce07
Merge remote-tracking branch 'origin/dev-fe' into feature/study-session
blu3fishez Nov 18, 2024
6d053e6
chore: `OAuth`에 필요한 패키지 설치
blu3fishez Nov 18, 2024
2ae27ba
chore: `TypeORM`과 트랜잭션에 필요한 패키지 설치
blu3fishez Nov 18, 2024
7b893e2
feat: `Nest.js`와 `TypeORM` 모듈 연동
blu3fishez Nov 18, 2024
d714558
feat: `UserRepository` 기능 추가
blu3fishez Nov 18, 2024
caf0214
feat: 깃허브 OAuth 연동 기능 추가
blu3fishez Nov 18, 2024
3b232bc
feat: sidebar 컴포넌트 구현
ShipFriend0516 Nov 18, 2024
22a3531
feat: 세션페이지에 사이드바를 추가
ShipFriend0516 Nov 18, 2024
205277a
fix: 마이페이지 누를 시 로그인 페이지로
ShipFriend0516 Nov 18, 2024
eceb3ef
feat: 로고 호버시 애니메이션
ShipFriend0516 Nov 18, 2024
eb7fc1b
style: 호버시 배경색 트랜지션
ShipFriend0516 Nov 18, 2024
4b57597
style: repository로 이동하는 링크 옆에 아이콘 추가
ShipFriend0516 Nov 18, 2024
2f6ba8b
feat: 접근성 aria-label 추가
ShipFriend0516 Nov 18, 2024
231b438
test: 세션 id 없이 스터디룸 입장 테스트
yiseungyun Nov 18, 2024
1689a65
test: 리액션 테스트 타이머 추가 테스트
yiseungyun Nov 18, 2024
7712236
refactor: useSession 타입 분리
yiseungyun Nov 18, 2024
784ce8f
Merge pull request #126 from ShipFriend0516/feature/sidebar
yiseungyun Nov 19, 2024
bb9e89c
refactor: useSession 테스트 코드 mock 객체 분리
yiseungyun Nov 19, 2024
5b4514c
test: 정리 테스트의 master_changed, room_finished 리스너 제거 추가
yiseungyun Nov 19, 2024
d9afbb8
refactor: `github.strategy.ts` 파일 위치 변경
blu3fishez Nov 19, 2024
3228840
Merge pull request #125 from ShipFriend0516/feature/login-page
yiseungyun Nov 19, 2024
8bad16c
refactor: 사이드바 레포지토리 이동 버튼 옆에 깃허브아이콘으로 변경
ShipFriend0516 Nov 19, 2024
e19199c
style: 사이드바 로고 폰트 변경
ShipFriend0516 Nov 19, 2024
623b696
style: 사이드바 다크모드 지원
ShipFriend0516 Nov 19, 2024
70fc806
feat: darkmode 커스텀훅 구현 및 tailwind config 다크모드 클래스방식으로 설정
ShipFriend0516 Nov 19, 2024
24ade39
style: 기본 테마 관련 css 삭제
ShipFriend0516 Nov 19, 2024
bac9926
feat: 사이드바에 다크모드 토글 버튼 추가 및 사이드바 다크모드 지원
ShipFriend0516 Nov 19, 2024
75bd05d
feat: typeorm 설정 파일 분리, strategy 파일 이동
twalla26 Nov 19, 2024
1df3b3f
feat: 질문지 리스트 페이지 route 추가
ShipFriend0516 Nov 19, 2024
fbbd738
chore: question module 생성 및 초기화
twalla26 Nov 19, 2024
bb0a47b
Merge pull request #136 from ShipFriend0516/feature/darkmode
yiseungyun Nov 19, 2024
27efdfd
style: 사이드바 색상 수정 및 전체 배경색 다크모드 지원하도록 수정
ShipFriend0516 Nov 19, 2024
73269da
feat: 질문지 리스트 페이지 구현
ShipFriend0516 Nov 19, 2024
20dfc21
Merge branch 'dev-fe' into feature/session-refactoring
yiseungyun Nov 19, 2024
3d4fb7e
Merge pull request #135 from boostcampwm-2024/feature/session-refacto…
yiseungyun Nov 19, 2024
a16e492
style: 서치바 컴포넌트 margin bottom 제거
ShipFriend0516 Nov 19, 2024
94f15de
feat: 공통 컴포넌트 Select 분리 구현
ShipFriend0516 Nov 19, 2024
c82d13b
refactor: 기존 select 태그를 Select 컴포넌트를 사용하도록 수정
ShipFriend0516 Nov 19, 2024
c6baefe
feat: 생성 폼 타이틀 공통 컴포넌트로 분리
yiseungyun Nov 19, 2024
1c98216
feat: 질문지 생성 폼 페이지 생성
yiseungyun Nov 19, 2024
f142bbf
feat: 질문지 카드 클릭시 토스트 메시지출력하도록
ShipFriend0516 Nov 19, 2024
4632a20
style: 다크모드 전환 버튼 테두리 추가
ShipFriend0516 Nov 19, 2024
0ffac97
feat: 로딩인디케이터 애니메이션 컴포넌트 구현
ShipFriend0516 Nov 19, 2024
8849259
refactor: 더미데이터 3초 뒤에 불러오도록 수정 및 로딩 적용
ShipFriend0516 Nov 19, 2024
c444ed3
feat: 질문지 생성 기능 구현
twalla26 Nov 19, 2024
3b3e135
chore: question을 question-list로 변경
twalla26 Nov 19, 2024
418b0c3
refactor: useSocket에서 socket 연결하도록 수정
yiseungyun Nov 19, 2024
6cef30f
refactor: path alias 적용
yiseungyun Nov 19, 2024
12cfff5
feat: 카테고리 선택 컴포넌트를 공통 컴포넌트로 분리
yiseungyun Nov 19, 2024
89b7e41
feat: 생성 폼 타이틀 입력 컴포넌트를 공통 컴포넌트로 생성
yiseungyun Nov 19, 2024
b929a59
feat: 공개/비공개 선택 컴포넌트를 공통 컴포넌트로 생성
yiseungyun Nov 19, 2024
598bbb8
Merge pull request #151 from boostcampwm-2024/feature/github-oauth
ShipFriend0516 Nov 19, 2024
c44c76c
refactor: 그리드 최대 3열로 수정
ShipFriend0516 Nov 19, 2024
5738d49
Merge pull request #152 from ShipFriend0516/feature/question-list-page
ShipFriend0516 Nov 19, 2024
2612ed6
feat: 질문지 생성 페이지 생성
yiseungyun Nov 19, 2024
8957c1b
feat: 세션 생성, 질문 생성에서 타이틀 최소 글자 수 검사
yiseungyun Nov 19, 2024
1d3c948
refactor: 토스트 스택 순서 반대로 변경
ShipFriend0516 Nov 19, 2024
1fe8316
feat: 질문 생성 폼에서 입력 질문 추가
yiseungyun Nov 19, 2024
7408aa6
test: 스터디세션 기능 테스트 코드 작성
blu3fishez Nov 19, 2024
31d8e41
refactor: 시간 타임스탬프에 0~200사이의 수를 더한 값을 아이디로 사용
ShipFriend0516 Nov 19, 2024
8c79e0b
fix: 스터디 레포지토리 버그 수정
blu3fishez Nov 19, 2024
e325ef4
fix: 화면 스크롤시 토스트 프로바이더가 가려지던 문제를 해결
ShipFriend0516 Nov 19, 2024
b2ca431
test: 스터디 세션 웹소켓 테스트 코드 추가
blu3fishez Nov 19, 2024
286321a
test: 레디스 서비스 테스트 코드 추가
blu3fishez Nov 19, 2024
53e4614
test: `OAuth` 테스트 코드 추가
blu3fishez Nov 19, 2024
f3148b0
refactor: controller에서 service로 DTO 넘겨주기
twalla26 Nov 19, 2024
04c7bcf
refactor: 클라이언트에게 질문지 생성 성공 여부 전달
twalla26 Nov 19, 2024
9bd89f4
refactor: dataSource 삭제
twalla26 Nov 19, 2024
d09b453
refactor: 접근성 태그를 사용
ShipFriend0516 Nov 19, 2024
7c7628e
refactor: timeout 클린업함수 추가
ShipFriend0516 Nov 19, 2024
35a1f13
refactor: dto를 interface로 변경
twalla26 Nov 19, 2024
c6d69c5
Merge pull request #169 from twalla26/feature/question-list
twalla26 Nov 19, 2024
007016f
Merge remote-tracking branch 'upstream/dev-be' into feature/login
ShipFriend0516 Nov 19, 2024
4c1e5ab
feat: 질문 글자수 10자 미만 시 토스트 에러 및 질문 고유 id 추가
yiseungyun Nov 19, 2024
9ea6d8e
chore: 라이브러리 설치
twalla26 Nov 19, 2024
7eb4e86
feat: 질문 생성 폼에서 질문 추가 및 추가된 질문 삭제/수정 기능 추가
yiseungyun Nov 19, 2024
10f8422
feat: 질문지 생성 폼에서 질문 입력과 수정 시 입력 값에 따라 높이 조절 기능 추가
yiseungyun Nov 19, 2024
ab086a7
feat: access token, refresh token 발급
twalla26 Nov 19, 2024
edf9200
feat: refresh token을 디비에 저장하기 위해 user dto, entity 수정
twalla26 Nov 19, 2024
178a536
feat: access token 검증 미들웨어 구현
twalla26 Nov 19, 2024
b5d78bf
feat: 질문 추가 버튼 생성
yiseungyun Nov 20, 2024
6cf9cb8
refactor: textarea 높이 조절 함수 utils에 분리
yiseungyun Nov 20, 2024
ffba5fd
fix: 영어로 입력 시 박스 밖을 벗어나는 문제 해결
yiseungyun Nov 20, 2024
391bf67
Merge pull request #173 from ShipFriend0516/refactor/toast
yiseungyun Nov 20, 2024
a524ba0
feat: vite proxy 설정
ShipFriend0516 Nov 20, 2024
5868b44
feat: 로그인페이지 깃허브 인증으로 리다이렉트 하는 함수 구현
ShipFriend0516 Nov 20, 2024
d1c342a
fix: 질문 10자 미만 추가 시 토스트 에러 2개 나타나는 오류 수정
yiseungyun Nov 20, 2024
12978d5
fix: 질문 추가 입력 폼 10자 미만 한글 입력 시 토스트 에러 2번 뜨는 오류 수정
yiseungyun Nov 20, 2024
ed54bfa
feat: payload에 githubId 대신 userId 담기
twalla26 Nov 20, 2024
45058f8
Merge pull request #174 from twalla26/feature/github-oauth
twalla26 Nov 20, 2024
4efd88b
chore: 주석삭제
ShipFriend0516 Nov 20, 2024
eb63334
chore: 프론트엔드 axios 라이브러리 설치
ShipFriend0516 Nov 20, 2024
d96fe3a
chore: 백엔드 axios 라이브러리 설치
ShipFriend0516 Nov 20, 2024
da11ac1
feat: github 로그인 콜백 route 구현
ShipFriend0516 Nov 20, 2024
716176f
fix: 로딩인디케이터 컴포넌트에 텍스트를 추가할 수 있도록 수정
ShipFriend0516 Nov 20, 2024
98591d9
refactor: react StrictMode 제거
ShipFriend0516 Nov 20, 2024
5fd20d7
feat: routes에 콜백 라우트 추가
ShipFriend0516 Nov 20, 2024
70c93dd
refactor: custom passport strategy로 변경
ShipFriend0516 Nov 20, 2024
42e66bb
feat: github 프로필 데코레이터 생성
ShipFriend0516 Nov 20, 2024
8120551
refactor: auth service 변경
ShipFriend0516 Nov 20, 2024
8db16a0
fix: custom guard를 사용하도록 변경
ShipFriend0516 Nov 20, 2024
f3d80c3
Merge remote-tracking branch 'upstream/dev-be' into feature/login
ShipFriend0516 Nov 20, 2024
499f6d7
chore: pnpm-lock update
ShipFriend0516 Nov 20, 2024
fa3c2a7
Merge pull request #175 from boostcampwm-2024/feature/create-question
ShipFriend0516 Nov 20, 2024
0868f36
chore: tanstack query 설치 및 provider 설정
yiseungyun Nov 20, 2024
09a5dfc
feat: 질문지 생성 기능에 카테고리 추가하여 구현
twalla26 Nov 20, 2024
eb2c3b5
feat: 전체 공개 질문지 조회 기능 구현
twalla26 Nov 20, 2024
be4b18d
feat: 카테고리별 공개 질문지 검색 기능 구현
twalla26 Nov 20, 2024
39a5dab
style: 페이지별 디자인 통일
yiseungyun Nov 20, 2024
b102eb2
chore: jwt 토큰 연동에 필요한 패키지 설치
blu3fishez Nov 20, 2024
cc0d86d
feat: 쿠키 설정에 필요한 설정 추가
blu3fishez Nov 20, 2024
9455e03
feat: 시간 개념에 날짜 개념도 추가
blu3fishez Nov 20, 2024
a4be9d5
feat: passport strategy 를 두개로 분리
blu3fishez Nov 20, 2024
4f9f623
feat: jwt 기능 구현시 필요한 데이터 구조 설계
blu3fishez Nov 20, 2024
8d750bc
feat: jwt module로 분리
blu3fishez Nov 20, 2024
ef32d92
feat: jwt 서비스 추가
blu3fishez Nov 20, 2024
f0d2d3e
feat: jwt 가드 삭제
blu3fishez Nov 20, 2024
7dd9d48
feat: auth 도메인 수정
blu3fishez Nov 20, 2024
807918b
feat: jwt 데코레이터 추가
blu3fishez Nov 20, 2024
e59b045
fix: 변경된 데이터 구조에 맞게 컴포넌트 props 변경
ShipFriend0516 Nov 20, 2024
44bcdec
fix: 세션 인터페이스 구조 수정 및 세션 리스트 렌더링 함수 구현
ShipFriend0516 Nov 20, 2024
0a4563a
Merge pull request #177 from boostcampwm-2024/feature/create-question
ShipFriend0516 Nov 20, 2024
bec819c
Merge pull request #179 from ShipFriend0516/feature/session-list-page…
ShipFriend0516 Nov 20, 2024
340b85c
feat: 질문지 생성 api 연결
yiseungyun Nov 20, 2024
04cffc1
Merge branch 'dev-fe' into feature/create-question
yiseungyun Nov 20, 2024
ac53af8
feat: 질문지 리스트 서버에 요청
yiseungyun Nov 20, 2024
d49d577
Merge pull request #178 from boostcampwm-2024/feature/login
twalla26 Nov 20, 2024
744eec8
feat: 질문지 생성할 떄 userGuards 사용
twalla26 Nov 20, 2024
dfb33af
Merge pull request #186 from twalla26/feature/question-list
twalla26 Nov 20, 2024
aae7c67
Merge pull request #172 from boostcampwm-2024/feature/backend-refactor
twalla26 Nov 20, 2024
05867fd
Merge pull request #187 from boostcampwm-2024/dev-be
ShipFriend0516 Nov 20, 2024
b727965
Merge branch 'dev' into dev-fe
ShipFriend0516 Nov 20, 2024
28c6fec
Merge pull request #188 from boostcampwm-2024/dev-fe
ShipFriend0516 Nov 20, 2024
20d9cec
refactor: 잘못된 데이터가 내려올 경우 빈 배열로 상태를 유지하도록 수정
ShipFriend0516 Nov 20, 2024
b0c481e
fix: 토스트 메시지가 사라지지 않던 오류 해결
ShipFriend0516 Nov 20, 2024
700355f
feat: 세션리스트에 로딩인디케이터 추가
ShipFriend0516 Nov 20, 2024
8bddf47
refactor: 세션생성 페이지 사이드바 추가
ShipFriend0516 Nov 20, 2024
11b6714
fix: 세션리스트 불러오기 실패시 빈배열 넣는 부분 린트 수정
ShipFriend0516 Nov 20, 2024
df9acc5
feat: 사이드바를 추가하는 section 태그의 스타일을 constraint로 분리
ShipFriend0516 Nov 20, 2024
bfb2da8
fix: 세션리스트 없으면 기존 mock 데이터 사용하도록 수정
ShipFriend0516 Nov 20, 2024
7aa4ed0
feat: 페이지네이션 컴포넌트 생성
yiseungyun Nov 20, 2024
917b34f
feat: 페이지네이션 탭 별 상태관리
yiseungyun Nov 20, 2024
d2b1e17
feat: 질문지 상세 페이지 생성
yiseungyun Nov 21, 2024
8ad503c
Merge branch 'dev' into feature/create-question
yiseungyun Nov 21, 2024
67f0583
fix: 질문지 생성 기능에서 유저 payload 가져오기
twalla26 Nov 21, 2024
541656f
fix: 테이블 명을 questionListCategory에서 스네이크 케이스로 변경
twalla26 Nov 21, 2024
2b092f2
Merge pull request #189 from ShipFriend0516/refactor/session-list-page
yiseungyun Nov 21, 2024
bb9a4bd
Merge branch 'dev-fe' of https://github.com/boostcampwm-2024/web27-Pr…
yiseungyun Nov 21, 2024
65e9b80
chore: `docker-compose.yml` 추가
blu3fishez Nov 21, 2024
cbcd3be
fix: 로티 애니메이션 최적화
ShipFriend0516 Nov 21, 2024
92660b9
fix: lottie 파일을 쓰면서 DotLottiePlayer 사용하도록 수정
ShipFriend0516 Nov 21, 2024
89523b5
Merge pull request #191 from ShipFriend0516/refactor/session-list-page
yiseungyun Nov 21, 2024
42ff9d8
feat: 질문지의 질문 내용 조회 기능
twalla26 Nov 21, 2024
cf21ee6
fix: 질문지 내용을 전달해줄 때 userId 대신 username 전달
twalla26 Nov 21, 2024
cb7cbfc
feat: useAuthStore와 useAuth 커스텀 훅 구현
ShipFriend0516 Nov 21, 2024
05eb2a8
chore: 로그인페이지 pages/Login 폴더 내부로 이동
ShipFriend0516 Nov 21, 2024
4d77cce
feat: zustand persist middleware를 사용해서 새로고침해도 로그인 상태가 초기화되지 않도록 구현
ShipFriend0516 Nov 21, 2024
75a84b8
feat: 로그인 성공시 전역상태 토글
ShipFriend0516 Nov 21, 2024
410a86a
feat: 질문지 생성 로그인한 유저만 가능하도록 구현
ShipFriend0516 Nov 21, 2024
ad094bf
feat: 로그인하지 않은 상태로 질문지생성 페이지 접근시 외부로 리다이렉팅
ShipFriend0516 Nov 21, 2024
ee88015
style: 구분선 내부 텍스트 배경색 수정
ShipFriend0516 Nov 21, 2024
4b04781
feat: 마이페이지 라우팅 및 유저 정보 불러오는 기능 구현
ShipFriend0516 Nov 21, 2024
9f2618c
feat: 내가 만든 질문지 조회 기능
twalla26 Nov 21, 2024
444fbaa
feat: 질문지 조회 기능에 usage, questionCount 추가
twalla26 Nov 21, 2024
52d6f47
feat: 입력 글자 수 표시 추가
yiseungyun Nov 21, 2024
d1cc140
fix: 질문지 리스트 페이지 interface 수정
ShipFriend0516 Nov 21, 2024
cc0b8ab
Merge pull request #192 from twalla26/feature/question-list
ShipFriend0516 Nov 21, 2024
2674566
Merge remote-tracking branch 'upstream/dev' into feature/questions-li…
ShipFriend0516 Nov 21, 2024
edfd059
fix: 최대 입력 20자가 아닌 21자까지 작성되는 오류 수정
yiseungyun Nov 21, 2024
e91e14d
feat: vite 환경변수 타입 설정 및 vite.config.ts에서도 환경변수 사용할 수 있도록 구현
ShipFriend0516 Nov 21, 2024
d66d7bb
feat: 방 생성할 때 question contents도 함께 보내주기
twalla26 Nov 21, 2024
f4eb2f9
chore: `.gitignore` 파일 수정
blu3fishez Nov 21, 2024
67e03b1
fix: 질문 contents 길이 20 -> 200 으로 늘리기
twalla26 Nov 21, 2024
4a877dd
feat: 로딩이 끝났는데 데이터가 하나도 없다면 생성해달라는 문구를 출력하도록 구현
ShipFriend0516 Nov 21, 2024
cc407bb
feat: 질문지 상세페이지 생성
yiseungyun Nov 21, 2024
990bc90
feat: 질문지 생성 및 가져오기 api 연결, 훅 분리
yiseungyun Nov 21, 2024
5a66379
feat: 폼에서 글자 입력 시 글자 수 표시
yiseungyun Nov 21, 2024
756ccdf
fix: 질문 글자수 100자에서 200자로 변경
yiseungyun Nov 21, 2024
7ddea28
fix: 열려있는 세션이 없을 경우에 대한 예외처리
blu3fishez Nov 21, 2024
db51171
fix: 스터디세션 레포지토리 버그 수정
blu3fishez Nov 21, 2024
fb54ef0
feat: 질문과 질문지 생성 기능을 트랜젝션으로 묶기
twalla26 Nov 21, 2024
ee8b85e
feat: 세션 리스트 GET API 데이터 수정
blu3fishez Nov 21, 2024
8c1bbb6
Merge pull request #190 from boostcampwm-2024/chore/docker-compose
blu3fishez Nov 21, 2024
f4353ba
chore: 필요없는 코드 삭제
twalla26 Nov 21, 2024
4ed4e14
feat: 세션 생성 모달창에서 질문지 리스트 불러오는 API 연동
ShipFriend0516 Nov 21, 2024
a1abc23
chore: mock 데이터 제거
ShipFriend0516 Nov 21, 2024
98d3ff9
feat: 각 리스트에 대한 로딩인디케이터 추가
ShipFriend0516 Nov 21, 2024
0221b07
feat: create_room 이벤트에 질문지 아이디 전달
ShipFriend0516 Nov 21, 2024
02b3de2
Merge pull request #194 from boostcampwm-2024/feature/create-question
ShipFriend0516 Nov 21, 2024
c2d3916
Merge pull request #195 from boostcampwm-2024/fix/study-session
ShipFriend0516 Nov 21, 2024
716ee13
Merge pull request #196 from twalla26/feature/question-list
ShipFriend0516 Nov 21, 2024
892ab59
Merge branch 'dev-fe' into feature/questions-list-api
ShipFriend0516 Nov 21, 2024
6ce357f
Merge pull request #193 from ShipFriend0516/feature/auth-store
yiseungyun Nov 21, 2024
073b3b4
Merge branch 'dev-fe' into feature/questions-list-api
ShipFriend0516 Nov 21, 2024
cb5821c
Merge pull request #197 from ShipFriend0516/feature/questions-list-api
ShipFriend0516 Nov 21, 2024
6325019
Merge pull request #198 from boostcampwm-2024/dev-fe
ShipFriend0516 Nov 21, 2024
e8d6381
feat: 카테고리 시드 데이터 추가
twalla26 Nov 21, 2024
763cb87
Merge pull request #200 from twalla26/feature/question-list
twalla26 Nov 21, 2024
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
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@ node_modules

# husky 관련
.husky/_
.husky/.gitignore
.husky/.gitignore

# docker-compose 관련 파일

mysql-data
redis-data
17 changes: 16 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,37 @@
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/jwt": "^10.2.0",
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/platform-socket.io": "^10.4.6",
"@nestjs/typeorm": "^10.0.2",
"@nestjs/websockets": "^10.4.6",
"@types/passport-jwt": "^4.0.1",
"axios": "^1.7.7",
"cookie-parser": "^1.4.7",
"dotenv": "^16.4.5",
"ioredis": "^5.4.1",
"mysql2": "^3.11.4",
"passport": "^0.7.0",
"passport-custom": "^1.1.1",
"passport-jwt": "^4.0.1",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1",
"socket.io": "^4.8.1"
"socket.io": "^4.8.1",
"typeorm": "^0.3.20",
"typeorm-naming-strategies": "^4.1.0",
"typeorm-transactional": "^0.5.0"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0",
"@nestjs/testing": "^10.0.0",
"@types/cookie-parser": "^1.4.7",
"@types/express": "^5.0.0",
"@types/jest": "^29.5.2",
"@types/node": "^20.3.1",
"@types/passport-github": "^1.1.12",
"@types/supertest": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
Expand Down
21 changes: 20 additions & 1 deletion backend/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
import { Module } from "@nestjs/common";

import { AppController } from "./app.controller";
import { AppService } from "./app.service";

import { SocketModule } from "./signaling-server/socket.module";
import { RoomModule } from "./room/room.module";
import { RedisModule } from "./redis/redis.module";
import { AuthModule } from "./auth/auth.module";
import { UserModule } from "./user/user.module";
import { TypeOrmModule } from "@nestjs/typeorm";

import "dotenv/config";

import { createDataSource, typeOrmConfig } from "./config/typeorm.config";
import { QuestionListModule } from "./question-list/question-list.module";

@Module({
imports: [SocketModule, RoomModule, RedisModule],
imports: [
TypeOrmModule.forRootAsync({
useFactory: async () => typeOrmConfig, // 설정 객체를 직접 반환
dataSourceFactory: async () => await createDataSource(), // 분리된 데이터소스 생성 함수 사용
}),
SocketModule,
RoomModule,
RedisModule,
AuthModule,
UserModule,
QuestionListModule,
],
controllers: [AppController],
providers: [AppService],
})
Expand Down
18 changes: 18 additions & 0 deletions backend/src/auth/auth.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from "@nestjs/testing";
import { AuthController } from "./auth.controller";

describe("AuthController", () => {
let controller: AuthController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [AuthController],
}).compile();

controller = module.get<AuthController>(AuthController);
});

it("should be defined", () => {
expect(controller).toBeDefined();
});
});
65 changes: 65 additions & 0 deletions backend/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Controller, Get, Post, Res, Req, UseGuards } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
import { Request, Response } from "express";
import { AuthService } from "./auth.service";
import { GithubProfile } from "./github/gitub-profile.decorator";
import { Profile } from "passport-github";
import { setCookieConfig } from "../config/cookie.config";
import { JwtPayload, JwtTokenPair } from "./jwt/jwt.decorator";
import { IJwtPayload, IJwtTokenPair } from "./jwt/jwt.model";

@Controller("auth")
export class AuthController {
private static ACCESS_TOKEN = "accessToken";
private static REFRESH_TOKEN = "refreshToken";

constructor(private readonly authService: AuthService) {}

@Post("github")
@UseGuards(AuthGuard("github"))
async githubCallback(
@Req() req: Request,
@Res({ passthrough: true }) res: Response,
@GithubProfile() profile: Profile
) {
const id = parseInt(profile.id);

const result = await this.authService.getTokenByGithubId(id);

res.cookie("accessToken", result.accessToken.token, {
maxAge: result.accessToken.expireTime,
...setCookieConfig,
});

res.cookie("refreshToken", result.refreshToken.token, {
maxAge: result.refreshToken.expireTime,
...setCookieConfig,
});

return {
success: true,
};
}

@Get("whoami")
@UseGuards(AuthGuard("jwt"))
async handleWhoami(@Req() req: Request, @JwtPayload() token: IJwtPayload) {
return token;
}

@Get("refresh")
@UseGuards(AuthGuard("jwt-refresh"))
async handleRefresh(
@Res({ passthrough: true }) res: Response,
@JwtTokenPair() token: IJwtTokenPair
) {
res.cookie("accessToken", token.accessToken.token, {
maxAge: token.accessToken.expireTime,
...setCookieConfig,
});

return {
success: true,
};
}
}
13 changes: 13 additions & 0 deletions backend/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Module } from "@nestjs/common";
import { AuthController } from "./auth.controller";
import { AuthService } from "./auth.service";
import { GithubStrategy } from "./github/github.strategy";
import { UserRepository } from "../user/user.repository";
import { JwtModule } from "./jwt/jwt.module";

@Module({
imports: [JwtModule],
controllers: [AuthController],
providers: [AuthService, GithubStrategy, UserRepository],
})
export class AuthModule {}
129 changes: 129 additions & 0 deletions backend/src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { Test, TestingModule } from "@nestjs/testing";
import { AuthService } from "./auth.service";
import { UserRepository } from "../user/user.repository";
import { Profile } from "passport-github";

// typeorm-transactional 모킹
jest.mock("typeorm-transactional", () => ({
Transactional: () => () => ({}),
runOnTransactionCommit: () => () => ({}),
runOnTransactionRollback: () => () => ({}),
runOnTransactionComplete: () => () => ({}),
initializeTransactionalContext: () => ({}),
}));

describe("AuthService", () => {
let authService: AuthService;
let userRepository: UserRepository;

// Mock GitHub 프로필 데이터
const mockGithubProfile: Profile = {
id: "12345",
displayName: "Test User",
username: "testuser",
profileUrl: "https://abcd/",
photos: [],
provider: "github",
_raw: "",
_json: {},
};

// Mock 유저 데이터
const mockUser = {
id: 1,
loginId: null,
passwordHash: null,
githubId: 12345,
username: "camper_12345",
};

beforeEach(async () => {
// Mock Repository 생성
const mockUserRepository = {
getUserByGithubId: jest.fn(),
createUser: jest.fn(),
};

const module: TestingModule = await Test.createTestingModule({
providers: [
AuthService,
{
provide: UserRepository,
useValue: mockUserRepository,
},
],
}).compile();

authService = module.get<AuthService>(AuthService);
userRepository = module.get<UserRepository>(UserRepository);
});

describe("githubLogin", () => {
it("기존 사용자가 있을 경우 해당 사용자를 반환해야 한다", async () => {
// Given
jest.spyOn(userRepository, "getUserByGithubId").mockResolvedValue(
mockUser
);

// When
const result = await authService.githubLogin(mockGithubProfile);

// Then
expect(userRepository.getUserByGithubId).toHaveBeenCalledWith(
parseInt(mockGithubProfile.id)
);
expect(result).toEqual(mockUser);
expect(userRepository.createUser).not.toHaveBeenCalled();
});

it("새로운 사용자의 경우 새 계정을 생성해야 한다", async () => {
// Given
jest.spyOn(userRepository, "getUserByGithubId").mockResolvedValue(
null
);
jest.spyOn(userRepository, "createUser").mockResolvedValue(
mockUser
);

// When
const result = await authService.githubLogin(mockGithubProfile);

// Then
expect(userRepository.getUserByGithubId).toHaveBeenCalledWith(
parseInt(mockGithubProfile.id)
);
expect(userRepository.createUser).toHaveBeenCalledWith({
githubId: parseInt(mockGithubProfile.id),
username: `camper_${mockGithubProfile.id}`,
});
expect(result).toEqual(mockUser);
});

it("getUserByGithubId 에러 발생 시 예외를 던져야 한다", async () => {
// Given
const error = new Error("Database error");
jest.spyOn(userRepository, "getUserByGithubId").mockRejectedValue(
error
);

// When & Then
await expect(
authService.githubLogin(mockGithubProfile)
).rejects.toThrow(error);
});

it("createUser 에러 발생 시 예외를 던져야 한다", async () => {
// Given
const error = new Error("Database error");
jest.spyOn(userRepository, "getUserByGithubId").mockResolvedValue(
null
);
jest.spyOn(userRepository, "createUser").mockRejectedValue(error);

// When & Then
await expect(
authService.githubLogin(mockGithubProfile)
).rejects.toThrow(error);
});
});
});
31 changes: 31 additions & 0 deletions backend/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Injectable, UnauthorizedException } from "@nestjs/common";
import { UserRepository } from "../user/user.repository";
import { Transactional } from "typeorm-transactional";
import "dotenv/config";
import { DAY, HOUR } from "../utils/time";
import { JwtService } from "./jwt/jwt.service";

@Injectable()
export class AuthService {
private static ACCESS_TOKEN_EXPIRATION_TIME = 3 * HOUR;
private static ACCESS_TOKEN_EXPIRATION = 30 * DAY;

constructor(
private readonly userRepository: UserRepository,
private readonly jwtService: JwtService
) {}

@Transactional()
public async getTokenByGithubId(id: number) {
let user = await this.userRepository.getUserByGithubId(id);

if (!user) {
user = await this.userRepository.createUser({
githubId: id,
username: `camper_${id}`,
});
}

return await this.jwtService.createJwtToken(user.id);
}
}
51 changes: 51 additions & 0 deletions backend/src/auth/github/github.strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// github-auth.strategy.ts
import { Injectable, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Strategy } from "passport-custom";
import { Request } from "express";
import axios from "axios";
import "dotenv/config";

@Injectable()
export class GithubStrategy extends PassportStrategy(Strategy, "github") {
private static REQUEST_ACCESS_TOKEN_URL =
"https://github.com/login/oauth/access_token";
private static REQUEST_USER_URL = "https://api.github.com/user";

constructor() {
super();
}

async validate(req: Request, done: any) {
const { code } = req.body;

if (!code) {
throw new UnauthorizedException("Authorization code not found");
}

const tokenResponse = await axios.post(
GithubStrategy.REQUEST_ACCESS_TOKEN_URL,
{
client_id: process.env.OAUTH_GITHUB_ID,
client_secret: process.env.OAUTH_GITHUB_SECRET,
code: code,
},
{
headers: { Accept: "application/json" },
}
);

const { access_token } = tokenResponse.data;

// GitHub 사용자 정보 조회
const userResponse = await axios.get(GithubStrategy.REQUEST_USER_URL, {
headers: {
Authorization: `Bearer ${access_token}`,
},
});

return done(null, {
profile: userResponse.data,
});
}
}
Loading