Skip to content

Commit

Permalink
[ALL] 하루스터디 v1.1.2 배포 👏 (#555)
Browse files Browse the repository at this point in the history
* [FE] 참여코드가 없을 때 모달로 띄우기, 구글로 로그인 버튼 구현 (#434)

* feat: 참여코드 오류 시 모달 띄우기

* feat: 구글로 로그인 버튼 구현

* [FE] 참여코드가 없을 때 모달로 띄우기, 구글로 로그인 버튼 구현 리팩터링 (#435)

* feat: 참여코드 오류 시 모달 띄우기

* feat: 구글로 로그인 버튼 구현

* refactor: errorHandler Error 타입 변경

* feat: GoogleButton 분리 및 Button 컴포넌트 상속

* refactor: Login 구분선 스타일컴포넌트 수정

* [BE] 로컬 프로파일에서 flyway를 사용하지 않도록 변경 (#429)

* [BE] 로컬 환경 ddl-auto 설정 명시, placeholder 제거 (#436)

* fix: 로컬 환경에서는 flyway를 사용하지 않도록 변경

* fix: placeholder 제거, ddl-auto 명시

* [BE] 변경된 테스트 작성 (#437)

* test: Auth, Member, PomodoroRoom 통합 테스트 추가

* test: 인수 테스트 및 통합 테스트 추가

Co-authored-by: woosung1223 <[email protected]>
Co-authored-by: MODI <[email protected]>
Co-authored-by: MoonJeWoong <[email protected]>

* test: api 변경에 따른 /api/me 테스트 수정

/api/members/{memberId} 통합 테스트를 /api/me 테스트로 변경

---------

Co-authored-by: aak2075 <[email protected]>
Co-authored-by: woosung1223 <[email protected]>
Co-authored-by: MoonJeWoong <[email protected]>

* [BE] 에러코드 명세 페이지 구현 (#439)

* chore: thymeleaf 의존성 추가

* chore: 에러코드 템플릿 추가

* refactor: 에러 코드 순서 보존을 위해 `LinkedHashMap`으로 변경

* feat: 에러코드용 컨트롤러 생성

* chore: 예외와 관련된 패키지 별도로 분리

* refactor: swagger 커스텀 어노테이션 삭제

* chore: 사용하지 않는 메소드 삭제

* refactor: `RequestMapping` -> `GetMapping` 변경

* [BE] refreshToken 쿠키 수명 설정 시 입력 값 오류 #441

* [BE] 참여코드 만료 기능 구현 (#442)

* chore: 기존 participantCode 관련 테스트의 패키지 이동

프로덕션 코드 기준에 맞게 participantcode 패키지가 아닌
room 패키지 하위로 이동

* feat: InMemoryParticipantCodeRepository 구현

* test: 참여 코드 만료 테스트 구현

* fix: 참여 코드 삭제 스케줄 주기 1시간으로 수정

* chore: 1300번 에러 메시지 변경

기존: 해당하는 참여코드가 없습니다.
변경 후: 참여 코드가 만료되었거나 존재하지 않습니다.

* test: 테스트에서 reflection을 사용하지 않도록 변경

* [BE] 인수테스트 시나리오 추가 (#445)

* feat: PomodoroRoomServiceTest 쪽 의존성 주입 annotation 수정

* test: 비회원 로그인 인수테스트 시나리오 추가

* test: 회원으로 진행했었던 스터디 목록 조회 인수테스트 시나리오 추가

* [BE] Auth 관련 테스트를 추가한다 (#446)

* refactor: 인증 헤더 파싱하는 중복 로직을 파서로 분리

* test: auth 관련 테스트 추가

* refactor: 메서드 분리 및 MockHttpServletResponse 사용

* refactor: any()에 파라미터 타입 명시 및 개행 추가

* [BE] AuthController RequestMapping 방식 통일 (#451)

* refactor: requestMapping URI 명시 방식 통일

* fix: api path 수정

Co-authored-by: aak2075 <[email protected]>
Co-authored-by: jaehee329 <[email protected]>
Co-authored-by: MoonJeWoong <[email protected]>

---------

Co-authored-by: teo <[email protected]>
Co-authored-by: woosung1223 <[email protected]>
Co-authored-by: aak2075 <[email protected]>
Co-authored-by: MoonJeWoong <[email protected]>

* [BE] 참여 코드 관련 서비스를 만료 가능한 버전으로 변경 (#455)

Co-authored-by: jaehee329 <[email protected]>
Co-authored-by: aak2075 <[email protected]>
Co-authored-by: MoonJeWoong <[email protected]>

* [FE] Http 클래스 구현 및 기타 사항 리팩토링 (#458)

* refactor: params 파일 삭제

* refactor: 커스텀 에러 네이밍 변경

* refactor: tokenStorage 객체 생성

* refactor: http version 2 구현

* refactor: httpInstance 구현

* refactor: cookie 네이밍 변경

* refactor: 기존 http를 prevHttp로 변경

* [FE] 스터디 기록 및 멤버 정보 불러오기 API 리팩터링 (#462)

* refactor: 멤버의 스터디 기록 불러오기 API 리팩터링

* refactor: 스터디 정보 및 스터디 참여 멤버 정보 불러오기 API 리팩터링

* refactor: 자신의 스터디 기록 불러오기 API 리팩터링

* refactor: 게스트, oauth 로그인 API 리팩터링

* refactor: 내 정보 불러오기 API 리팩터링

* refactor: 로그인 관련 API 네이밍 리팩터링

* refactor: boolCheckCookie 메서드 변경

* refactor: Authorization으로 수정

* refactor: 토근이 없을 때, 로그인 페이지로 이동하는 로직 재추가

* refactor: tokenStorage에서 accessToken 가져오기

* refactor: refreshAndRefetch api 주소 변경 및 MSW 제거

* [FE] 개설하기 및 참여하기 플로우 API 호출 로직 리팩터링 (#465)

* refactor: Authorization 및 auth refetch 엔드포인트 수정

* refactor: 스터디 개설하기 플로우 요청 로직 변경

* refactor: 개설하기 플로우 요청 로직 재변경

* refactor: 참여 코드 입력 플로우 api 요청 로직 변경

* refactor: progresses 확인 요청 및 progress 삭제 요청 로직 변경

* test: progress 삭제 요청 msw 코드 작성

* refactor: progress 등록 플로우 api 요청 로직 수정

* chore: error인자 reason으로 변경

* refactor: 훅에서 데이터 가공 후 리턴하도록 변경

* refactor: throw 로직 수정

* chore: 필요없는 import 구문 제거

* [FE] 스터디 대기 인원 컴포넌트 UI 구현 (#469)

* feat: 스터디 대기 인원 컴포넌트 구현

* test: 스터디 대기 인원 컴포넌트 스토리북 작성

* [FE] 진행 페이지 Http api 리팩토링 (#472)

* refactor: BASE_URL 환경 변수 추가

* refactor: msw 요청 body 가져오는 로직 수정

* refactor: api 함수 리팩토링

* refactor: usePlanningForm 엑세스토큰 로직 제거

* refactor: useRetrospectForm 엑세스토큰 로직 제거

* refactor: useStudyBoard 엑세스토큰 로직 제거

* refactor: useStudyingForm 엑세스토큰 로직 제거

* refactor: http2 -> Http로 변경

* refactor: boolCheckCookie 함수 삭제

* refactor: http.ts 파일 삭제

* [FE] 랜딩 페이지 개선 (#471)

* feat: Landing UI

* feat: 로딩중일 때의 UI 개발

* feat: 로그인 기능 추가

* feat: 사진 변경 및 그림자 효과 추가

* refactor: 랜딩페이지 컴포넌트 분리

* feat: haruServiceImage 변경

* chore: 1402, 1405에러에 대한 주석 추가

* refactor: GUIDE 객체로 분리

* feat: 반응형 추가

그리고 GuideSection 컴포넌트 위치 변경

* chore: 스크린샷 제거

* fix: example.test.tsx 삭제

* refactor: DownArrowIcon 제거 및 기존 아이콘 사용

* feat: LoginModalContents 페이지에서 제거

* refactor: LandingButton 컴포넌트 분리

* [FE] env 파일 BASE_URL 추가 (#479)

* [BE] 에러코드 명세 페이지 API Path 수정  (#460)

* refactor: api path 수정

* fix: 비회원 path '/' 추가

* [BE] 에러코드 페이지에서는 Interceptor가 작동하지 않도록 수정  (#485)

* refactor: 에러코드 1405번 추가

* fix: 인터셉터에서 error code 경로 배제

* [BE] 정적 자원을 찾을 수 있도록 경로 매핑 (#488)

* feat: 정적 자원을 찾을 수 있도록 경로 매핑

`api/resources` -> `classpath:/static/`

* chore: excludePathPatterns 수정

* [BE] progress 조회 시 없으면 null을 반환하는 임시 API 생성  (#490)

* feat: progress 임시 조회용 API 생성

* chore: 코드 스타일 수정

* fix: progress 조회 결과가 빈 배열일 경우 null을 반환하도록 변경

* [ALL] README를 추가한다 (#496)

* [BE] room -> study로 네이밍 변경 (#498)

* [BE] OSIV 전역 설정 끄기 (#497)

* [BE] Oauth 로그인 외부 API 호출 로직 분리 및 읽기 전용 트랜잭션 적용 (#499)

* refactor: 외부 호출 API 트랜잭션 분리를 위한 OauthService, AuthService 분리

* feat: 읽기 전용 트랜잭션 애너테이션 적용

* refactor: OauthService 네이밍 OauthLoginFacade로 수정

* refactor: MemberService findOauthProfile 메서드 네이밍 수정

* fix: conflict 해결

* [FE] 진행 페이지 리팩토링 및 Error Boundary, fetch 훅 구현 (#500)

* chore: env 변경

* refactor: StudyBoard 페이지 StudyProgress로 변경, StudyBoard 컴포넌트 분리

* refactor: ROUTES_PATH board에서 progress로 변경

* refactor: progress hooks 폴더 이동

* fix: httpInstance 1404 에러 로직 추가

* fix: Http config headers 중복안되는 문제 해결

* refactor: LoadingLayout 추가

* refactor: StudyProgressProvider 분리

* refactor: PlanningForm Context 적용

* refactor: useRetrospectForm 컨텍스트 적용

* refactor: StudyingForm 컨텍스트 적용

* refactor: StudyBoard 컨텍스트 적용

* refactor: useFetch 구현

* refactor: useMutation 구현

* refactor: Sidebar 컨텍스트 사용하도록 변경

* refactor: ApiError, UnknownApiError config도 포함하도록 변경

* refactor: eslint no-throw-literal 옵션 추가

* refactor: useFetch suspense 옵션 적용

* refactor: CycleIcon, ResetIcon 컬러 프롭스 옵셔널하게 변경

* feat: GlobalErrorBoundary, AlertErrorBoundary, ErrorFallback 구현 및 적용

* refactor: ModalProvider 컨텍스트 및 타입 export로 변경

* refactor: StudyBoard 컨텍스트 적용 및 AlertErrorBoundary 적용

* fix: router StudyBoard import 제거

* fix: AlertErrorBoundary 1402, 1405 re-throw 로직 추가

* refactor: useFetch 훅 내부 useEffect dependency 제거

* [BE] interceptor와 sse관련 로깅 문제 해결 (#511)

* [FE] 메인 페이지 Ver 2.0 업데이트 완료 (#512)

* chore: 랜딩 페이지 이미지 변경

* refactor: NotFoundPage -> NotFound로 네이밍 변경

* refactor: Landing 페이지 컴포넌트 컨테이너 추가

* feat: LandingMainSection 디자인 리뉴얼

* refactor: LandingButton 리팩토링

* refactor: GuideSection 리팩토링

* feat: 사이클 요소 별 학습 효과 추가

* feat: Footer 구현

* refactor: GuideSection 컴포넌트 분리화 작업

* refactor: LandingButton 반응형 사이즈 수정

* refactor: StepGuide 방향 정하는 로직 규칙에 맞게 변경

* fix: 반응형 width 깨지는 문제 수정

* fix: StudyEffectGuide 반복문 key값 추가

* [FE] MemberInfoProvider 로직 수정 및 useFetch, useMutation 옵션 추가 (#517)

* refactor: eslint 속성 변경

* refactor: useFetch 옵션 enable, onSuccess, onError 추가

* refactor: useMutation 옵션 onSuccess, onError 추가

* refactor: MemberInfoProvider 로직 수정

* refactor: useFetch enable -> enabled로 네이밍 변경

* fix: useStudyBoard memberInfo 에러 수정

* refactor: MemberInfo 서스펜스 적용

* refactor: useFetch fetch 함수 디펜던시 제거

* [FE] 개설하기, 참여하기, 시작하기 플로우 에러바운더리 적용 및 테스트코드 작성 (#503)

* feat: ErrorBoundary 컴포넌트 및 훅 구현

* feat: useFetch 훅 구현

* feat: useMutation 훅 구현

* feat: 개설하기 플로우 ErrorBoundary 적용

* feat: 참여코드 입력 플로우 ErrorBoundary 적용

* feat: ErrorPage 구현

* chore: ErrorPage 삭제

* refactor: 스터디 개설하기 플로우 변경사항 적용

* refactor: 참여코드 입력 플로우 변경사항 적용

* chore: useErrorBoundary 삭제

* refactor: progresses 확인하는 플로우 변경사항 적용

* chore: lint 수정

* refactor: Http 클래스 수정

* chore: icon 프롭스 변경

* feat: 에러바운더리 구현

* refactor: 스터디 시작하는 플로우 변경 사항 적용

* feat: useFetch 및 useMutation 구현

* test: msw 핸들러 수정

* refactor: custom error 수정

* chore: App 컴포넌트 수정

* refactor: suspense 인자 추가

* chore: EOL 적용

* chore: testing-library use-event 의존성 추가

* chore: 린트 수정

* chore: jest 셋팅 변경

* refactor: data-id 프롭 추가

* test: 참여페이지, 개설페이지, 준비페이지 테스트 코드 작성

* refactor: if문으로 분기

* refactor: mutate 함수 createStudy로 함수명 변경

* chore: 도메인 hook 컴포넌트 하위 hooks 폴더로 경로 이동

* chore: import 경로 변경

* refactor: mutate 함수 authenticateParticipationCode로 함수명 변경

* refactor: mutate를 registerProgress로 함수명 변경

* chore: useRegisterProgress로 변경

* chore: 룩소 변경안 적용

* chore: 노아 변경사항 반영

* refactor: memberInfo 변경사항 적용

* refactor: suspense 옵션 제거 및 if문 수정

* chore: EOL 적용

* [FE] 기록 페이지 useFetch, errorBoundary 적용 (#518)

* chore: gitkeep 파일 제거

* chore: 린트 규칙 설정

* feat: 멤버 기록 페이지 useFetch 적용 및 Suspense 추가

* chore: 주석 추가

* refactor: memberId 타입 가드

* chore: MSW 버전 업데이트

* feat: useFetch훅에 refetch 기능 추가

* chore: 주석제거

* refactor: ProgressRecord에 useFetch 훅 적용

* refactor: ProgressMemberRecord에 useFetch 훅 적용

* refactor: useMemberRecord 훅 수정

* refactor: useStudyRecordData 훅 분리

* refactor: useStudyMembers 훅 분리

* refactor: useMemberRecordContents 훅 분리

* refactor: record 관련 훅 네이밍 수정

* refactor: MemberRecordListSkeleton 컴포넌트 분리

* refactor: css 속성 수정

* refactor: useMemberInfo 훅 반환값 수정

* refactor: forwardRef 제거

* refactor: 함수 중괄호 생략

* refactor: ProgressRecord 서스펜스 제거 및 isLoading으로 페이지 렌더링

* refactor: useMemberInfo, MemberInfoProvider 수정 적용

* chore: 변경사항 적용

* chore: 변경사항 적용

* refactor: record hook 폴더 이동

* refactor: 조건문 처리 리팩터링

* [FE] 랜딩 페이지 토큰 에러 수정 및 구글 애널리틱스 태그 삽입 (#524)

* refactor: url 관련 유틸 함수 url 객체로 응집화

* refactor: GlobalErrorBoundary 삭제 후 일반 ErrorBoundary로 변경

* refactor: LandingButton 사용하지 않는 import 제거

* refactor: useFetch, useMutation 훅 errorBoundary 옵션 추가

* refactor: 리프레시 토큰 에러 로직 httpInstance로 이동

* refactor: MemberInfoProvider 스코프 변경

* refactor: Auth 페이지 로그인 로직 수정

* refactor: MemberInfoProvider 콘솔 로그 제거

* feat: 구글 애널리틱스 태그 삽입

* fix: changePathname 수정 및 Auth 페이지 로직 일부 수정

* [FE] 개설하기, 참여하기, 준비하기 페이지 반응형 작업 (#520)

* style: 반응형 적용

* style: 반응형 width 변경

* [FE] 개설하기, 참여하기, 준비하기 반응형 작업 v2 (#530)

* refactor: Input, Select 컴포넌트 label 및 bottomtext 반응형 작업

* refactor: Select 하위 컴포넌트 반응형 작업

* refactor: StudyParticipationLayout 헤더 반응형 적용 및 Input 폰트 사이즈 반응형 적용

* refactor: MemberRestart 반응형 작업

* [FE] 기록 페이지 반응형 및 테스트 코드 추가 (#528)

* feat: 기록페이지 반응형 추가

* feat: modal 반응형 추가

* test: 랜딩 페이지 test

* test: 나의 기록 페이지 test

* test: 렌딩 페이지 테스트 코드 개선

* feat: 스터디 기록 페이지 test

* refactor: modal width 수정

* refactor: LoginModal width 변경

* refactor: StudyNameDate UI 통일

* refactor: 텍스트 크기 및 모달 리뷰 반영

* refactor: Tabs.Item 스크롤 기능 개선

* [FE] 진행 페이지 fetch 로직 리팩토링 작업 (#531)

* refactor: url 관련 유틸 함수 url 객체로 응집화

* refactor: GlobalErrorBoundary 삭제 후 일반 ErrorBoundary로 변경

* refactor: LandingButton 사용하지 않는 import 제거

* refactor: useFetch, useMutation 훅 errorBoundary 옵션 추가

* refactor: 리프레시 토큰 에러 로직 httpInstance로 이동

* refactor: MemberInfoProvider 스코프 변경

* refactor: Auth 페이지 로그인 로직 수정

* refactor: MemberInfoProvider 콘솔 로그 제거

* feat: 구글 애널리틱스 태그 삽입

* fix: changePathname 수정 및 Auth 페이지 로직 일부 수정

* refactor: useFetch 리팩토링

* refactor: LoadingFallback 구현

* refactor: api 반환 형식 변경

* refactor: MemberInfoGuard 구현 및 적용

* refactor: useStudyBoard 삭제

* refactor: Landing import 순서 변경

* refactor: usePlanningForm 리팩토링

* refactor: StudyProgressProvider 리팩토링

* refactor: useRetrospectForm fetch 훅 리팩토링

* refactor: StudyingForm fetch 훅 리팩토링

* fix: 닉네임 입력 페이지 memberInfo 호출 순서 버그 수정

* [FE] 타이머 기능 추가 (#535)

* feat: useTimer, useStepTimer 분할 및 타이머 자동 시작 기능 구현

* refactor: SelectList composeEventHandler 함수 합병

* refactor: dom 유틸함수 객체 생성 및 적용

* feat: 타이머 브라우저 탭에 시간 띄우는 기능 구현

* feat: 알람 mp3파일 삽입 및 audioPlayer 구현

* refactor: useTimer 및 useStepTimer on 함수들 인자로 받도록 수정

* feat: 타이머 끝났을 때 알람 소리 출력 기능 구현

* refactor: useStepTimer 주석 파일 상단으로 수정

* [FE] 하루스터디 카카오톡 오픈카톡방으로 이동하기 (#534)

* feat: ChatIcon

* feat: 카카오 채팅방 링크 연결

* refactor: ChattingLink 훅 분리

* refator: ChattingLink 반응형 개선

* feat: StartSection 추가

* test: 랜딩 페이지 테스트 수정

* refactor: StartSection padding 간격 조정

* feat: BugReportingLink 추가

* refactor: BugReportingLink background color 수정

* [FE] 로그인 페이지(Auth) 요청 순서 보장하지 못하는 버그 (#539)

* refactor: httpInstance 콘솔 로그 제거

* fix: Auth 페이지에서는 초기 멤버 정보 fetching 안하도록 변경

* [FE] 프론트엔드 성능 개선 (#540)

* perf: 번들 최적화

Co-authored-by: Jungkyun Woo <[email protected]>
Co-authored-by: Geonyeop Kim <[email protected]>

* perf: 이미지 webp, jpg 변환

Co-authored-by: Jungkyun Woo <[email protected]>
Co-authored-by: Geonyeop Kim <[email protected]>

* perf: Image 컴포넌트 구현 및 적용

Co-authored-by: Jungkyun Woo <[email protected]>
Co-authored-by: Geonyeop Kim <[email protected]>

* perf: 폰트 최적화

Co-authored-by: Jungkyun Woo <[email protected]>
Co-authored-by: Geonyeop Kim <[email protected]>

* chore: assets 폴더이름 통일

Co-authored-by: Jungkyun Woo <[email protected]>
Co-authored-by: Geonyeop Kim <[email protected]>

* refactor: alarm 위치 변경

Co-authored-by: Jungkyun Woo <[email protected]>
Co-authored-by: Geonyeop Kim <[email protected]>

---------

Co-authored-by: Jungkyun Woo <[email protected]>
Co-authored-by: Geonyeop Kim <[email protected]>

* [FE] html 파일 style sheet 경로 변경

fix: stylesheet 경로 수정 (#542)

* fix: sourceFiles 경로 변경 (#543)

* [FE] 모바일 환경에서의 구글 로그인 아이콘 위치 수정 (#548)

* refactor: 구글 로그인 아이콘 모바일 환경에서 위치 변경

* refactor: 모바일 환경에서 SideLink GuideMessage 제거하기

* [FE] favicon 및 og 태그 설정 (#549)

* chore: favicon 추가 및 index.html 변경

* feat: 학습 진행시 동적 파비콘 적용

* feat: 타이머 탭 title에 서비스 명 삽입

* feat: og 태그 설정

* [FE] 빌드 설정 변경 및 favicon, og image 경로 수정 (#551)

* build: 빌드 시 dist 폴더에 assets폴더 복사

* refactor: favicon 및 og 이미지 경로 수정

* [BE] 참여 코드 저장 위치를 in memory에서 MySQL로 옮긴다 (#550)

* [BE] 참여 코드 엔티티가 BaseEntity를 상속하도록 한다.

* [FE] production jenkins 스크립트 변경

* build: production jenkins 스크립트 변경 (#556)

---------

Co-authored-by: noah <[email protected]>
Co-authored-by: MODI <[email protected]>
Co-authored-by: aak2075 <[email protected]>
Co-authored-by: MoonJeWoong <[email protected]>
Co-authored-by: hiiro <[email protected]>
Co-authored-by: jaehee329 <[email protected]>
Co-authored-by: Jungkyun Woo <[email protected]>
Co-authored-by: Geonyeop Kim <[email protected]>
Co-authored-by: Jungkyun Woo <[email protected]>
  • Loading branch information
10 people authored Sep 21, 2023
1 parent 04dbeec commit c7fab75
Show file tree
Hide file tree
Showing 303 changed files with 6,868 additions and 4,784 deletions.
92 changes: 92 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# 📖 하루스터디([haru-study.com](haru-study.com))

### 시스템 구성도
![image](https://github.com/woowacourse-teams/2023-haru-study/assets/77962265/15963d75-ca21-4662-8a60-8381cab0523b)


### 팀 구성
<table>
<tr>
<td align="center" width="140px">
<p>Backend</p>
</td>
<td align="center" width="140px">
<p>Backend</p>
</td>
<td align="center" width="140px">
<p>Backend</p>
</td>
<td align="center" width="140px">
<p>Backend</p>
</td>
<td align="center" width="140px">
<p>Frontend</p>
</td>
<td align="center" width="140px">
<p>Frontend</p>
</td>
<td align="center" width="140px">
<p>Frontend</p>
</td>
</tr>
<tr>
<td align="center" width="120px">
<img src="https://avatars.githubusercontent.com/u/78679830?v=4" alt="테오(최우성) 프로필" />
</td>
<td align="center" width="120px">
<img src="https://avatars.githubusercontent.com/u/35948985?v=4" alt="마코(이규성) 프로필" />
</td>
<td align="center" width="120px">
<img src="https://avatars.githubusercontent.com/u/77962265?v=4" alt="모디(전제희) 프로필" />
</td>
<td align="center" width="120px">
<img src="https://avatars.githubusercontent.com/u/31722737?v=4" alt="히이로(문제웅) 프로필" />
</td>
<td align="center" width="120px">
<img src="https://avatars.githubusercontent.com/u/78894403?v=4" alt="엽토(김건엽) 프로필" />
</td>
<td align="center" width="120px">
<img src="https://avatars.githubusercontent.com/u/57981252?v=4" alt="노아(김홍동) 프로필" />
</td>
<td align="center" width="120px">
<img src="https://avatars.githubusercontent.com/u/73513965?v=4" alt="룩소(우정균) 프로필" />
</td>
</tr>
<tr>
<td align="center">
<a href="https://github.com/woosung1223" target="_blank">
테오(최우성)
</a>
</td>
<td align="center">
<a href="https://github.com/aak2075" target="_blank">
마코(이규성)
</a>
</td>
<td align="center">
<a href="https://github.com/jaehee329" target="_blank">
모디(전제희)
</a>
</td>
<td align="center">
<a href="https://github.com/MoonJeWoong" target="_blank">
히이로(문제웅)
</a>
</td>
<td align="center">
<a href="https://github.com/yeopto" target="_blank">
엽토(김건엽)
</a>
</td>
<td align="center">
<a href="https://github.com/nlom0218" target="_blank">
노아(김홍동)
</a>
</td>
<td align="center">
<a href="https://github.com/woo-jk" target="_blank">
룩소(우정균)
</a>
</td>
</tr>
</table>
2 changes: 1 addition & 1 deletion backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'


implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-registry-prometheus'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
@EnableJpaAuditing
@SpringBootApplication
public class HaruStudyApplication {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import harustudy.backend.auth.dto.AuthMember;
import harustudy.backend.auth.service.AuthService;
import java.util.Objects;
import harustudy.backend.auth.util.BearerAuthorizationParser;
import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
Expand All @@ -16,10 +16,10 @@
@Component
public class AuthArgumentResolver implements HandlerMethodArgumentResolver {

private static final int ACCESS_TOKEN_LOCATION = 1;

private final AuthService authService;

private final BearerAuthorizationParser bearerAuthorizationParser;

@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(Authenticated.class);
Expand All @@ -29,8 +29,7 @@ public boolean supportsParameter(MethodParameter parameter) {
public AuthMember resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
String authorizationHeader = webRequest.getHeader(HttpHeaders.AUTHORIZATION);
Objects.requireNonNull(authorizationHeader);
String accessToken = authorizationHeader.split(" ")[ACCESS_TOKEN_LOCATION];
String accessToken = bearerAuthorizationParser.parse(authorizationHeader);
long memberId = Long.parseLong(authService.parseMemberId(accessToken));
return new AuthMember(memberId);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package harustudy.backend.auth;

import harustudy.backend.auth.exception.InvalidAuthorizationHeaderException;
import harustudy.backend.auth.service.AuthService;
import harustudy.backend.auth.util.BearerAuthorizationParser;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
Expand All @@ -15,6 +15,7 @@
public class AuthInterceptor implements HandlerInterceptor {

private final AuthService authService;
private final BearerAuthorizationParser bearerAuthorizationParser;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Expand All @@ -23,12 +24,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons
return true;
}
String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
String[] splitAuthorizationHeader = authorizationHeader.split(" ");
if (splitAuthorizationHeader.length != 2 ||
!splitAuthorizationHeader[0].equals("Bearer")) {
throw new InvalidAuthorizationHeaderException();
}
String accessToken = authorizationHeader.split(" ")[1];
String accessToken = bearerAuthorizationParser.parse(authorizationHeader);
authService.validateAccessToken(accessToken);
return HandlerInterceptor.super.preHandle(request, response, handler);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import harustudy.backend.auth.dto.OauthLoginRequest;
import harustudy.backend.auth.dto.TokenResponse;
import harustudy.backend.auth.exception.RefreshTokenCookieNotExistsException;
import harustudy.backend.auth.exception.RefreshTokenNotExistsException;
import harustudy.backend.auth.service.AuthService;
import harustudy.backend.auth.service.OauthLoginFacade;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.Cookie;
Expand All @@ -15,61 +16,63 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "인증 관련 기능")
@RequiredArgsConstructor
@RequestMapping("api/auth")
@RestController
public class AuthController {

@Value("${refresh-token.expire-length}")
private Long refreshTokenExpireLength;

private final OauthLoginFacade oauthLoginFacade;
private final AuthService authService;

@Operation(summary = "비회원 로그인 요청")
@PostMapping("/api/auth/guest")
public ResponseEntity<TokenResponse> guestLogin() {
TokenResponse tokenResponse = authService.guestLogin();
return ResponseEntity.ok(tokenResponse);
}

@Operation(summary = "소셜 로그인 요청")
@PostMapping("/login")
@PostMapping("/api/auth/login")
public ResponseEntity<TokenResponse> oauthLogin(
HttpServletResponse httpServletResponse,
@RequestBody OauthLoginRequest request
) {
TokenResponse tokenResponse = authService.oauthLogin(request);
Cookie cookie = new Cookie("refreshToken", tokenResponse.refreshToken().toString());
cookie.setMaxAge(refreshTokenExpireLength.intValue());
cookie.setPath("/");
TokenResponse tokenResponse = oauthLoginFacade.oauthLogin(request);
Cookie cookie = setUpRefreshTokenCookie(tokenResponse);
httpServletResponse.addCookie(cookie);
return ResponseEntity.ok(tokenResponse);
}

@Operation(summary = "비회원 로그인 요청")
@PostMapping("/guest")
public ResponseEntity<TokenResponse> guestLogin() {
TokenResponse tokenResponse = authService.guestLogin();
return ResponseEntity.ok(tokenResponse);
}

@Operation(summary = "access 토큰, refresh 토큰 갱신")
@PostMapping("/refresh")
@PostMapping("/api/auth/refresh")
public ResponseEntity<TokenResponse> refresh(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse
) {
String refreshToken = extractRefreshTokenFromCookie(httpServletRequest);
TokenResponse tokenResponse = authService.refresh(refreshToken);
Cookie cookie = new Cookie("refreshToken", tokenResponse.refreshToken().toString());
cookie.setMaxAge(refreshTokenExpireLength.intValue());
cookie.setPath("/");
Cookie cookie = setUpRefreshTokenCookie(tokenResponse);
httpServletResponse.addCookie(cookie);
return ResponseEntity.ok(tokenResponse);
}

private Cookie setUpRefreshTokenCookie(TokenResponse tokenResponse) {
Cookie cookie = new Cookie("refreshToken", tokenResponse.refreshToken().toString());
cookie.setMaxAge(refreshTokenExpireLength.intValue() / 1000);
cookie.setPath("/");
return cookie;
}

private String extractRefreshTokenFromCookie(HttpServletRequest httpServletRequest) {
return Arrays.stream(httpServletRequest.getCookies())
.filter(cookie -> cookie.getName().equals("refreshToken"))
.map(Cookie::getValue)
.findAny()
.orElseThrow(RefreshTokenCookieNotExistsException::new);
.orElseThrow(RefreshTokenNotExistsException::new);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package harustudy.backend.auth.exception;

import harustudy.backend.common.HaruStudyException;
import harustudy.backend.common.exception.HaruStudyException;

public class AuthorizationException extends HaruStudyException {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package harustudy.backend.auth.exception;

import harustudy.backend.common.HaruStudyException;
import harustudy.backend.common.exception.HaruStudyException;

public class InvalidAccessTokenException extends
HaruStudyException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package harustudy.backend.auth.exception;

import harustudy.backend.common.HaruStudyException;
import harustudy.backend.common.exception.HaruStudyException;

public class InvalidAuthorizationHeaderException extends
HaruStudyException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package harustudy.backend.auth.exception;

import harustudy.backend.common.HaruStudyException;
import harustudy.backend.common.exception.HaruStudyException;

public class InvalidProviderNameException extends HaruStudyException {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package harustudy.backend.auth.exception;

import harustudy.backend.common.HaruStudyException;
import harustudy.backend.common.exception.HaruStudyException;

public class InvalidRefreshTokenException extends HaruStudyException {

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package harustudy.backend.auth.exception;

import harustudy.backend.common.HaruStudyException;
import harustudy.backend.common.exception.HaruStudyException;

public class RefreshTokenExpiredException extends HaruStudyException {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package harustudy.backend.auth.exception;

import harustudy.backend.common.exception.HaruStudyException;

public class RefreshTokenNotExistsException extends HaruStudyException {

}
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
package harustudy.backend.auth.service;

import harustudy.backend.auth.config.OauthProperties;
import harustudy.backend.auth.config.OauthProperty;
import harustudy.backend.auth.config.TokenConfig;
import harustudy.backend.auth.domain.RefreshToken;
import harustudy.backend.auth.dto.OauthLoginRequest;
import harustudy.backend.auth.dto.OauthTokenResponse;
import harustudy.backend.auth.dto.TokenResponse;
import harustudy.backend.auth.dto.UserInfo;
import harustudy.backend.auth.exception.InvalidAccessTokenException;
import harustudy.backend.auth.exception.InvalidRefreshTokenException;
import harustudy.backend.auth.infrastructure.GoogleOauthClient;
import harustudy.backend.auth.repository.RefreshTokenRepository;
import harustudy.backend.auth.util.JwtTokenProvider;
import harustudy.backend.auth.util.OauthUserInfoExtractor;
import harustudy.backend.member.domain.LoginType;
import harustudy.backend.member.domain.Member;
import harustudy.backend.member.repository.MemberRepository;
import io.jsonwebtoken.JwtException;
import java.util.Map;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -29,29 +23,18 @@
@Service
public class AuthService {

private final OauthProperties oauthProperties;
private final GoogleOauthClient googleOauthClient;
private final JwtTokenProvider jwtTokenProvider;
private final TokenConfig tokenConfig;
private final MemberRepository memberRepository;
private final RefreshTokenRepository refreshTokenRepository;

public TokenResponse oauthLogin(OauthLoginRequest request) {
UserInfo userInfo = requestUserInfo(request.oauthProvider(), request.code());
Member member = saveOrUpdateMember(request.oauthProvider(), userInfo); // TODO: 트랜잭션 분리
public TokenResponse userLogin(OauthLoginRequest request, UserInfo userInfo) {
Member member = saveOrUpdateMember(request.oauthProvider(), userInfo);
String accessToken = generateAccessToken(member.getId());
RefreshToken refreshToken = saveRefreshTokenOf(member);
return TokenResponse.forLoggedIn(accessToken, refreshToken);
}

private UserInfo requestUserInfo(String oauthProvider, String code) {
OauthProperty oauthProperty = oauthProperties.get(oauthProvider);
OauthTokenResponse oauthToken = googleOauthClient.requestOauthToken(code, oauthProperty);
Map<String, Object> oauthUserInfo =
googleOauthClient.requestOauthUserInfo(oauthProperty, oauthToken.accessToken());
return OauthUserInfoExtractor.extract(oauthProvider, oauthUserInfo);
}

private Member saveOrUpdateMember(String oauthProvider, UserInfo userInfo) {
Member member = memberRepository.findByEmail(userInfo.email())
.map(entity -> entity.updateUserInfo(userInfo.name(), userInfo.email(), userInfo.imageUrl()))
Expand Down
Loading

0 comments on commit c7fab75

Please sign in to comment.