Skip to content

Commit

Permalink
Dev (#291)
Browse files Browse the repository at this point in the history
* Refactor/file include url chat byte : 채팅 String으로 이미지 입력을 받자 (#203)

* refactor/file-includeUrl-chatByte-1: 파일 upload시 url에 presignURL 적히도록 수정

* refactor/file-includeUrl-chatByte-2:

- 1. 파일 List형태의 imgCode (여러개 이미지 파일)로 전송 시 MultipartFile로 바꿈

- 2. File업로드 진행
- 3. Redis로 파일 List형태의 presign URL 전송

- 실패 : 파일 저장도 안되고 전송도 안됨

* refactor/file-includeUrl-chatByte-3:

- imgCode에 따른 DTO의 수정사항

* refactor/file-includeUrl-chatByte-4:

- else

* Refactor/file include url chat byte : 채팅 String으로 이미지 입력을 받자 (#203) (#209)

* refactor/file-includeUrl-chatByte-1: 파일 upload시 url에 presignURL 적히도록 수정

* refactor/file-includeUrl-chatByte-2:

- 1. 파일 List형태의 imgCode (여러개 이미지 파일)로 전송 시 MultipartFile로 바꿈

- 2. File업로드 진행
- 3. Redis로 파일 List형태의 presign URL 전송

- 실패 : 파일 저장도 안되고 전송도 안됨

* refactor/file-includeUrl-chatByte-3:

- imgCode에 따른 DTO의 수정사항

* refactor/file-includeUrl-chatByte-4:

- else

* fix(채팅): 채팅 파일 전송 수정 (#205)

* fix(채팅): 채팅 파일 전송 수정

개요

- 수연님이 구현해주신 PR #203에서 에러나는 부분을 수정하고 동작을
확인한다.

수정 사항

- CustomMulipartFile을 Base64MultipartFile로 이름 변경
  - 기존에 DiskFileItem으로 생성했다면, content, type, name을 직접
전달하여 명시적으로 생성하도록 변경
- 불필요한 DiskFileItem 등 삭제. 파일 생성 후 저장 방식을 수연님이 만든
Base64MultipartFile로 생성하여 fileService에 전달
- DisconnectHandler의 함수명 조금 더 명시적으로 변경
- 불필요한 모듈 삭제

* chore(ws): 웹소켓 디버깅 로깅 활성화

개요

- 앞으로 웹소켓 관련 디버깅을 조금 더 정확히 하기 위해 로컬에서 웹소켓
로깅을 활성화 한다.

* fix(sql): 채팅방 setting dummy data 수정

개요 및 수정사항

- 현재 dummyData에 count = 0이 들어가지 않아서, 채팅방 입장시
getCount에서 null으로 인식되어 에러가 뜸.

* Fix/members chatrooms display tmp (#210)

* fix/members-chatrooms-display-1:
내가 쓴 글 / 내가 쓴 댓글 조회 시 좋아요/댓글 , isLiked, isPublic 표시

* fix/members-chatrooms-display-2:
불필요해진 maxCount 삭제

* fix/members-chatrooms-display-3:
게시글 글자수 제한 해제 -> LONGTEXT로 변경

---------

Co-authored-by: suyeon <[email protected]>

* fix/notificationToken-byDeviceId-1: DeviceId마다 알림 리스트를 GET할 수 있도록 (#207)

* fix/notificationToken-byDeviceId-1:

- NotificationController, getNotifications:
- 알림 리스트를 받아올 때 pathVariable에 deviceId 추가해 deviceId별 알림 리스트를 받아올 수 있도록 함
- 이때 deviceId를 가진 회원만이 알림들을 가져올 수 있음

- sendNotificationTokens:
- deviceId 마다 하나의 토큰만이 생성되도록 로직 수정
- isTokenAlive 메서드를 추가해 이전에 해당 device 앞으로 된 토큰이 있는지 확인하고 없다면 새로 만들고
- 기존에 회원이 등록했던 deviceIdfh 된 토큰이라면 새로 만들지 않고 응답 DTO를 작성함

* fix/notificationToken-byDeviceId-2: 테스트 편의성을 위한 sql 수정

* refactor/enum-string-1: (#208)

- 국가코드, 여가, 언어코드 : NOT ENUM
- 게시글 타입, 북마크 타입, 채팅방 타입, 채팅 타입, 커넥트 상태, 파일 포맷, 채팅방 목적,  MBTI, 좋아요 타입, 알림 타입, 신고 타입 : ENUM
- 회원 생성, 채팅방 생성 테스트 완료

* chore(db): Liquibase 적용 및 수정 (#212)

* feat/liquibase-implementation-1: Liquibase 적용을 위한 yml 설정

- application.yml:
- Liquibase를 통한 DDL 생성으로 인한 ddl-auto 해제
- Liquibase와 import.sql 을 함께 사용하기 위해서 hibernate 초기화 이후 import.sql을 실행하는 옵션값인 defer-datasource-initialization값을 false 로 되돌림

- application-local.yml:
- Liquibase 사용 가능하도록 local에 추가
- master인 application.yml과 설정값 통일 시키기

* feat/liquibase-implementation-2: Liquibase XML

- migration 시키기 전 테이블 수 26개 작성
- 관계 연결 완료

* feat/liquibase-implementation-3:
test의 application.yml

- ./gradlew build 통과를 위한 liquibase 명시

* chore(db): Liquibase 적용 및 수정

개요

- 수연님이 작성해주신 Liquibase PR #204를 바탕으로 수정 진행

수정 사항

- Liquibase를 release 버전 별로 관리를 할 수 있도록 폴더 및 구조 추가
- changeset ID를 조금 더 랜덤화하고(중복 방지), type을 대문자로 하여 가독성을 높임
- FK constraint 이름은 자동 생성으로 하여 정하였음.
- liquibase가 prod, local에 둘 다 적용이 필요하므로,
application.yml에 추가
- ddl-auto 및 defer-datasourc-initialization등 기본값이 none, false이기
때문에 불필요한 코드 삭제

- 추가로, PR #208의 변경 사항으로 ENUM 관련 column들이 string으로 바뀌어서
column type도 함께 liquibase에서 변경해준다. (PR로 squash
- 초기 스크립트 에러도 고쳤음
- application-prod가 빈파일이어서 불필요하므로 삭제

---------

Co-authored-by: suyeon <[email protected]>

* feat/chatroom-random-1: 랜덤하게 10개 그룹 채팅방 뽑아오는 API 추가 및 탈퇴 시 댓글 삭제 처리 로직 수정 (#211)

* feat/chatroom-random-1: 랜덤하게 10개 그룹 채팅방 뽑아오는 API 추가

- 랜덤한 채팅방 10개의 후보군으로는 그룹 채팅방, 인원수가 꽉 차지 않은 채팅방이 보여짐

* feat/chatroom-random-2: 댓글 삭제 로직 변경

- 솔로 댓글일 경우 -> 탈퇴 시 자동 삭제
- 자식 댓글일 경우 -> 탈퇴 시 자동 삭제
- 부모 댓글일 경우 -> 탈퇴 시 NULL 처리

* feat/chatroom-random-3: 방장인 그룹 채팅방은 랜덤 호출 시 안 보이게 수정

* fix(db): 잘못 수정된 group purpose TYPE을 liquibase에 추가 (#213)

개요 및 수정사항

- group_purpose의 type 컬럼을 삭제했었는데, 필요한 컬림이므로 다시
추가해준다.

* refactor(file): File 모델의 URL 컬럼 삭제, Exception 리팩토링 (#214)

* chore(file): S3 File에 관한 Exception 정의

개요

- S3 upload 과정에서 문제가 생겼을 때 custom exception을 정의하자.

수정 사항

- S3 File 이름의 validation을 위한 S3FileNameInvalidException 정의
- 찾는 S3 파일이 DB에 없을 때를 위한 S3FileNotFoundException 정의

* refactor(file): File 모델의 URL 컬럼 삭제, Exception 리팩토링

개요

- 현재 DB에 pre-signed url을 저장하고 있는데, pre-signed url은
일시적으로만 사용하는 것이므로 DB에 저장을 하지않도록 한다.
  - 프론트엔드 코드에서는 다행히 File 모델의 url 값을 필요로 하는 부분은 없어서
리팩토링 진행 (presignedImgProfile로 이미지 렌더링을 하더라구요)

- 반복되는 코드 genereatePresignedUrl 함수로 리팩토링
- exception의 경우에 global exception handler가 있으므로, try catch 걸지
않아도, 괜찮아서 삭제

* refactor/board-getall-1: 게시글 모든 타입도 가져올 수 있게 수정 (#215)

- 파라미터 변경사항 -> type 존재

* fix/blockservice-mistake-1: 잘못 비교했던 id 비교 수정 & 메서드 재활용 UP (#216)

* refactor/board-getall-1: 게시글 모든 타입도 가져올 수 있게 수정
- 파라미터 변경사항 -> type 존재

* fix/blockservice-mistake-1: 잘못 비교했던 id 비교 수정 & 메서드 재활용 UP

* fix/blockservice-mistake-1: 본인이 방장인 채팅방 불러오기 추가

- 기존 채팅방을 불러오는 API인 GET: /chatrooms 에서 파라미터를 아무것도 넣지 않을 때 방장을 불러올 수 있음
- 파리미터 GROUP -> 속하거나 방장인 그룹 채팅방
- 파라미터 SINGLE -> 속한 싱글 채팅방

* release(v1.0.0)-alpha 배포 (#217)

* Refactor/file include url chat byte : 채팅 String으로 이미지 입력을 받자 (#203)

* refactor/file-includeUrl-chatByte-1: 파일 upload시 url에 presignURL 적히도록 수정

* refactor/file-includeUrl-chatByte-2:

- 1. 파일 List형태의 imgCode (여러개 이미지 파일)로 전송 시 MultipartFile로 바꿈

- 2. File업로드 진행
- 3. Redis로 파일 List형태의 presign URL 전송

- 실패 : 파일 저장도 안되고 전송도 안됨

* refactor/file-includeUrl-chatByte-3:

- imgCode에 따른 DTO의 수정사항

* refactor/file-includeUrl-chatByte-4:

- else

* fix(채팅): 채팅 파일 전송 수정 (#205)

* fix(채팅): 채팅 파일 전송 수정

개요

- 수연님이 구현해주신 PR #203에서 에러나는 부분을 수정하고 동작을
확인한다.

수정 사항

- CustomMulipartFile을 Base64MultipartFile로 이름 변경
  - 기존에 DiskFileItem으로 생성했다면, content, type, name을 직접
전달하여 명시적으로 생성하도록 변경
- 불필요한 DiskFileItem 등 삭제. 파일 생성 후 저장 방식을 수연님이 만든
Base64MultipartFile로 생성하여 fileService에 전달
- DisconnectHandler의 함수명 조금 더 명시적으로 변경
- 불필요한 모듈 삭제

* chore(ws): 웹소켓 디버깅 로깅 활성화

개요

- 앞으로 웹소켓 관련 디버깅을 조금 더 정확히 하기 위해 로컬에서 웹소켓
로깅을 활성화 한다.

* fix(sql): 채팅방 setting dummy data 수정

개요 및 수정사항

- 현재 dummyData에 count = 0이 들어가지 않아서, 채팅방 입장시
getCount에서 null으로 인식되어 에러가 뜸.

* Fix/members chatrooms display tmp (#210)

* fix/members-chatrooms-display-1:
내가 쓴 글 / 내가 쓴 댓글 조회 시 좋아요/댓글 , isLiked, isPublic 표시

* fix/members-chatrooms-display-2:
불필요해진 maxCount 삭제

* fix/members-chatrooms-display-3:
게시글 글자수 제한 해제 -> LONGTEXT로 변경

---------

Co-authored-by: suyeon <[email protected]>

* fix/notificationToken-byDeviceId-1: DeviceId마다 알림 리스트를 GET할 수 있도록 (#207)

* fix/notificationToken-byDeviceId-1:

- NotificationController, getNotifications:
- 알림 리스트를 받아올 때 pathVariable에 deviceId 추가해 deviceId별 알림 리스트를 받아올 수 있도록 함
- 이때 deviceId를 가진 회원만이 알림들을 가져올 수 있음

- sendNotificationTokens:
- deviceId 마다 하나의 토큰만이 생성되도록 로직 수정
- isTokenAlive 메서드를 추가해 이전에 해당 device 앞으로 된 토큰이 있는지 확인하고 없다면 새로 만들고
- 기존에 회원이 등록했던 deviceIdfh 된 토큰이라면 새로 만들지 않고 응답 DTO를 작성함

* fix/notificationToken-byDeviceId-2: 테스트 편의성을 위한 sql 수정

* refactor/enum-string-1: (#208)

- 국가코드, 여가, 언어코드 : NOT ENUM
- 게시글 타입, 북마크 타입, 채팅방 타입, 채팅 타입, 커넥트 상태, 파일 포맷, 채팅방 목적,  MBTI, 좋아요 타입, 알림 타입, 신고 타입 : ENUM
- 회원 생성, 채팅방 생성 테스트 완료

* chore(db): Liquibase 적용 및 수정 (#212)

* feat/liquibase-implementation-1: Liquibase 적용을 위한 yml 설정

- application.yml:
- Liquibase를 통한 DDL 생성으로 인한 ddl-auto 해제
- Liquibase와 import.sql 을 함께 사용하기 위해서 hibernate 초기화 이후 import.sql을 실행하는 옵션값인 defer-datasource-initialization값을 false 로 되돌림

- application-local.yml:
- Liquibase 사용 가능하도록 local에 추가
- master인 application.yml과 설정값 통일 시키기

* feat/liquibase-implementation-2: Liquibase XML

- migration 시키기 전 테이블 수 26개 작성
- 관계 연결 완료

* feat/liquibase-implementation-3:
test의 application.yml

- ./gradlew build 통과를 위한 liquibase 명시

* chore(db): Liquibase 적용 및 수정

개요

- 수연님이 작성해주신 Liquibase PR #204를 바탕으로 수정 진행

수정 사항

- Liquibase를 release 버전 별로 관리를 할 수 있도록 폴더 및 구조 추가
- changeset ID를 조금 더 랜덤화하고(중복 방지), type을 대문자로 하여 가독성을 높임
- FK constraint 이름은 자동 생성으로 하여 정하였음.
- liquibase가 prod, local에 둘 다 적용이 필요하므로,
application.yml에 추가
- ddl-auto 및 defer-datasourc-initialization등 기본값이 none, false이기
때문에 불필요한 코드 삭제

- 추가로, PR #208의 변경 사항으로 ENUM 관련 column들이 string으로 바뀌어서
column type도 함께 liquibase에서 변경해준다. (PR로 squash
- 초기 스크립트 에러도 고쳤음
- application-prod가 빈파일이어서 불필요하므로 삭제

---------

Co-authored-by: suyeon <[email protected]>

* feat/chatroom-random-1: 랜덤하게 10개 그룹 채팅방 뽑아오는 API 추가 및 탈퇴 시 댓글 삭제 처리 로직 수정 (#211)

* feat/chatroom-random-1: 랜덤하게 10개 그룹 채팅방 뽑아오는 API 추가

- 랜덤한 채팅방 10개의 후보군으로는 그룹 채팅방, 인원수가 꽉 차지 않은 채팅방이 보여짐

* feat/chatroom-random-2: 댓글 삭제 로직 변경

- 솔로 댓글일 경우 -> 탈퇴 시 자동 삭제
- 자식 댓글일 경우 -> 탈퇴 시 자동 삭제
- 부모 댓글일 경우 -> 탈퇴 시 NULL 처리

* feat/chatroom-random-3: 방장인 그룹 채팅방은 랜덤 호출 시 안 보이게 수정

* fix(db): 잘못 수정된 group purpose TYPE을 liquibase에 추가 (#213)

개요 및 수정사항

- group_purpose의 type 컬럼을 삭제했었는데, 필요한 컬림이므로 다시
추가해준다.

* refactor(file): File 모델의 URL 컬럼 삭제, Exception 리팩토링 (#214)

* chore(file): S3 File에 관한 Exception 정의

개요

- S3 upload 과정에서 문제가 생겼을 때 custom exception을 정의하자.

수정 사항

- S3 File 이름의 validation을 위한 S3FileNameInvalidException 정의
- 찾는 S3 파일이 DB에 없을 때를 위한 S3FileNotFoundException 정의

* refactor(file): File 모델의 URL 컬럼 삭제, Exception 리팩토링

개요

- 현재 DB에 pre-signed url을 저장하고 있는데, pre-signed url은
일시적으로만 사용하는 것이므로 DB에 저장을 하지않도록 한다.
  - 프론트엔드 코드에서는 다행히 File 모델의 url 값을 필요로 하는 부분은 없어서
리팩토링 진행 (presignedImgProfile로 이미지 렌더링을 하더라구요)

- 반복되는 코드 genereatePresignedUrl 함수로 리팩토링
- exception의 경우에 global exception handler가 있으므로, try catch 걸지
않아도, 괜찮아서 삭제

* refactor/board-getall-1: 게시글 모든 타입도 가져올 수 있게 수정 (#215)

- 파라미터 변경사항 -> type 존재

* fix/blockservice-mistake-1: 잘못 비교했던 id 비교 수정 & 메서드 재활용 UP (#216)

* refactor/board-getall-1: 게시글 모든 타입도 가져올 수 있게 수정
- 파라미터 변경사항 -> type 존재

* fix/blockservice-mistake-1: 잘못 비교했던 id 비교 수정 & 메서드 재활용 UP

* fix/blockservice-mistake-1: 본인이 방장인 채팅방 불러오기 추가

- 기존 채팅방을 불러오는 API인 GET: /chatrooms 에서 파라미터를 아무것도 넣지 않을 때 방장을 불러올 수 있음
- 파리미터 GROUP -> 속하거나 방장인 그룹 채팅방
- 파라미터 SINGLE -> 속한 싱글 채팅방

* Revert "Refactor/file include url chat byte : 채팅 String으로 이미지 입력을 받자 (#203) (#209)"

This reverts commit 3b0404467888810c8bce4fcec4b131c46475cd94.

---------

Co-authored-by: Koo Su Yeon <[email protected]>
Co-authored-by: suyeon <[email protected]>

* refactor/swagger-add-1: 배제해두었던 ChatroomSwagger 되살리기 & 모든 Controller 스… (#218)

* refactor/swagger-add-1: 배제해두었던 ChatroomSwagger 되살리기 & 모든 Controller 스웨거 작성완료

- ENUM 타입 중에 DTO를 통해서만 전달되는 값들은 스웨거에 명시가 안되어서 멘트로 추가해두었음

* refactor/swagger-add-2: 파일 Presign URL 접근 방법 변경 -> id로 접근

- 제한 사항 : 본인의 학생증 인증 파일에 관해 URL 접근 권한자를 지정함
- File 엔티티에 isSecret 칼럼 추가해 추후 유연하게 조절할 예정

- MemberService:
- 기존에는 회원은 최초의 온보딩 과정에서만 학생증 인증사진을 올릴 수 있었으나 verfied된 회원도 사진을 올릴 수 있도록 수정

- Liquibase 칼럼 추가 (v1.0.1) 및 master -> include 명령으로 수정

* refactor/swagger-add-3: 누락된 update Null 방지 코드 추가

* refactor/swagger-add-4: 과도기 단계 - 구버전의 파일 name으로 PresignUrl 가져오기 남겨두기

* refactor/report-add-chatroom-1: 그룹 채팅방 신고 추가 (#219)

* refactor/report-add-chatroom-1: 그룹 채팅방 신고 추가

- Report에 외래키 chatroom 추가
- 로직은 기존 신고와 댓글/게시글과의 연관관계와 동일
- swagger, liquibase 작성완료

* refactor/report-add-chatroom-2: 그룹 채팅방 조회 시 참여 여부 표시 -> isEntered

- 그룹 채팅방 생성 시에도 조회와 같은 DTO 사용한다.
- 때문에 isEntered가 불러와지는데 생성 후에는 본인만 보일 응답 DTO이기 때문에 DTO를 적을 필요가 없다 판단 -> 조회 시에만 isEntered값이 들어감

* hotfix(translate): production에서 부재한 deepl key 추가 (#222)

개요

- production에서 에러가 나서 확인해보니, production에서 deepL key가
부재한다. 따라서, 이를 추가해준다.

수정 사항

- 추가로, 한시적으로 웹소켓 디버깅을하기 위해, logging을 활성화한다.

* Perf/fix response dto : DTO에 민감한 정보 포함되지 않도록 (#220)

* perf/fix-response-dto-1: 그룹 채팅방 응답 DTO 수정

- Member -> MemberResponseDto 변경:
- 커스텀한 MemberModelMapper 사용
- 제외한 민감한 정보:
- 비밀번호, 전공, 실명

- Chatroom -> ChatroomResponseDto 변경
- 커스텀 Mapper ChatroomModelMapper 사용
- 제외한 민감한 정보:
- 그룹 채팅방의 비밀번호

* perf/fix-response-dto-2: 게시글/댓글 응답 DTO에 민감한 정보를 제외한 Member가 아닌 MemberResponseDto가 적히도록 수정

+신고 서비스 응답 로직 변경 -> ResponseDto보이지 않고 Created Status만 표시하도록

* perf/fix-response-dto-3: Chore

* perf/fix-response-dto-4: isBookmarked 값 Post GET요청 시 보이게 추가 및 나머지 DTO 보안화 진행

* perf/fix-response-dto-5: Build 파일 작성

* perf/fix-response-dto-6: 좋아요 응답 DTO 생성

- 기존에는 PostResponse를 재활용했으나 like Id를 가져올 수 있는 LikeResponseDto 로 수정

* perf/fix-response-dto-7: Comment 조회 시 부모 게시글의 좋아요/댓글 갯수 표시되도록

* fix(db): DB Migration 꼬인 부분을 정상화 (#224)

개요

- 현재 Migration 관련해서 히스토리가 꼬여서 이를 정상화하자.

수정 사항

- includeAll로 v1.0 하위 폴더의 모든 changeSet 감지하도록
- chatroom_id가 report에 컬럼이 없어서 FK를 못거는 상황이어서 추가해줌

* fix(chat): 채팅 이미지 사이즈 관련 조정 및 멤버 채팅 DTO에 포함 (#225)

* fix(db): DB Migration 꼬인 부분을 정상화

개요

- 현재 Migration 관련해서 히스토리가 꼬여서 이를 정상화하자.

수정 사항

- includeAll로 v1.0 하위 폴더의 모든 changeSet 감지하도록
- chatroom_id가 report에 컬럼이 없어서 FK를 못거는 상황이어서 추가해줌

* fix(chat): 채팅 이미지 사이즈 관련 조정 및 멤버 채팅 DTO에 포함

개요

- 채팅 이미지를 10MB 이상으로 받으려면 스프링 자체에도 설정이 필요해서
추가
- Member를 Response 타입에 포함시켜 프론트에 전달 (정보가 필요)

* Feat/translate community-1 : 사용자에게 기기 언어 추가 및 커뮤니티 서비스 번역 추가 (#223)

* feat/translate-community-1: 사용자에게 기기언어 추가
- PUT 요청에서 추가 가능
- EN, KO, ZH, JA, ES (ENUM 타입)
- null일 경우 자동 EN 처리

* feat/translate-community-2: 댓글 작성 시에 번역된 알림 추가 및 DOCS 작업 추가

* feat/translate-community-3: 커넥트 생성, 성공 / 게시글 좋아요 / 댓글 좋아요 / 채팅방 입장 시에 번역된 알림 전송

* feat/translate-community-4: 번역 언어는 String으로 받기 (DEEPL 번역 언어 String)

* feat/translate-community-5: 제한이 존재하는 번역진행

- 게시글, 채팅 번역 추가
- 게시글은 title, content가 그 범위임
- 회원당 번역 제한 15개

* feat/translate-community-6: DOCS & chore

* feat/translate-community-6-add:./spotlessapply

* feat/translate-community-6-chore:Liquibase 지정 및 ENUM LanguageType 삭제

* feat/translate-community-7-rebase-liquibase

* feat/translate-community-8:
댓글 번역 추가

* feat/translate-community-9:
ResourceBundle을 이용한 알림 번역본 properties화

* feat/translate-community-10:
피드백 반영 중복되는 Transalte 엔티티 인터페이스 & Override 이용

- 게시글의 경우 title과 content의 분리는 \n로 하였음

* Perf/member module : MemberService 모듈화 및 비밀번호 변경 후 로직 추가 (#226)

* perf/member-module-1: 불필요한 DTO 정보 제외 & 비밀번호 변경 후 로직 추가

- 비밀번호 변경 시:
- 1. 변경된 비밀번호 발급과 동시에 member.setIsPassword를 true로 업데이트
- 2. 변경된 비밀번호로 로그인 후 IsPassword가 true에 한해 비밀번호를 update 가능하게 해줌 PUT :/api/members
- 변경과 함께 다시 IsPasswordChanged False로 변환
- 즉, change-password API를 실행한 후에야 비밀번호 편집 자격 부여

* perf/member-module-2: memberService 모듈화 진행 및 chore

* perf/member-module-3: 비밀번호 재설정 로직 변경

- 1. 비밀번호 변경 시 -> 메일 발송 (인증번호 용도) GET :/members/change-password (NO AUTH)
- 2. 해당 인증번호로 비밀번호 재설정 API PATCH 요청 (NO AUTH)
- 파라미터로 인증번호와 새로 설정할 비밀번호와 계정 이메일을 넣고 요청을 보냄
- 인증번호 불일치 시 403에러 내뱉음

* perf/member-module-4: 비밀번호 인증번호 일치 여부를 새로운 비밀번호 설정 전에 확인할 수 있도록 함

* fix(chat): 그룹 채팅 전용 조회 API를 1:1 겸용으로 개조 (#227)

* fix(chat): 그룹 채팅 전용 조회 API를 1:1 겸용으로 개조

개요

- 현재 그룹채팅 전용으로 사용 중인 /chatrooms/getGroupChatrooms와 /chatrooms/getGroupChatroom을 1:1도 사용할 수 있도록 겸용으로 바꾼다.

수정 사항

- 함수명 변경
- 1:1 채팅의 경우에는 방장이 없으므로, null 값이 들어가서 에러가 남.
따라서, GROUP이 있는 경우에만 값처리를 해주자

* fix(chat): 1:1 채팅방에서 상대방이 멤버 목록에서 빠져있음

개요

- 상대방이 1:1 채팅방 정보 요청을 하면 거기에 정보가 빠져 있다. 원인은
member에 본인만 등록해주는 부분이 있었음.

* fix/translate-get-1: 게시글 가져올 때 \n 이 아닌 각각으로 가져오기 (#228)

* release(v1.0.2): v1.0.2 merge (#229)

* Refactor/file include url chat byte : 채팅 String으로 이미지 입력을 받자 (#203)

* refactor/file-includeUrl-chatByte-1: 파일 upload시 url에 presignURL 적히도록 수정

* refactor/file-includeUrl-chatByte-2:

- 1. 파일 List형태의 imgCode (여러개 이미지 파일)로 전송 시 MultipartFile로 바꿈

- 2. File업로드 진행
- 3. Redis로 파일 List형태의 presign URL 전송

- 실패 : 파일 저장도 안되고 전송도 안됨

* refactor/file-includeUrl-chatByte-3:

- imgCode에 따른 DTO의 수정사항

* refactor/file-includeUrl-chatByte-4:

- else

* fix(채팅): 채팅 파일 전송 수정 (#205)

* fix(채팅): 채팅 파일 전송 수정

개요

- 수연님이 구현해주신 PR #203에서 에러나는 부분을 수정하고 동작을
확인한다.

수정 사항

- CustomMulipartFile을 Base64MultipartFile로 이름 변경
  - 기존에 DiskFileItem으로 생성했다면, content, type, name을 직접
전달하여 명시적으로 생성하도록 변경
- 불필요한 DiskFileItem 등 삭제. 파일 생성 후 저장 방식을 수연님이 만든
Base64MultipartFile로 생성하여 fileService에 전달
- DisconnectHandler의 함수명 조금 더 명시적으로 변경
- 불필요한 모듈 삭제

* chore(ws): 웹소켓 디버깅 로깅 활성화

개요

- 앞으로 웹소켓 관련 디버깅을 조금 더 정확히 하기 위해 로컬에서 웹소켓
로깅을 활성화 한다.

* fix(sql): 채팅방 setting dummy data 수정

개요 및 수정사항

- 현재 dummyData에 count = 0이 들어가지 않아서, 채팅방 입장시
getCount에서 null으로 인식되어 에러가 뜸.

* Fix/members chatrooms display tmp (#210)

* fix/members-chatrooms-display-1:
내가 쓴 글 / 내가 쓴 댓글 조회 시 좋아요/댓글 , isLiked, isPublic 표시

* fix/members-chatrooms-display-2:
불필요해진 maxCount 삭제

* fix/members-chatrooms-display-3:
게시글 글자수 제한 해제 -> LONGTEXT로 변경

---------

Co-authored-by: suyeon <[email protected]>

* fix/notificationToken-byDeviceId-1: DeviceId마다 알림 리스트를 GET할 수 있도록 (#207)

* fix/notificationToken-byDeviceId-1:

- NotificationController, getNotifications:
- 알림 리스트를 받아올 때 pathVariable에 deviceId 추가해 deviceId별 알림 리스트를 받아올 수 있도록 함
- 이때 deviceId를 가진 회원만이 알림들을 가져올 수 있음

- sendNotificationTokens:
- deviceId 마다 하나의 토큰만이 생성되도록 로직 수정
- isTokenAlive 메서드를 추가해 이전에 해당 device 앞으로 된 토큰이 있는지 확인하고 없다면 새로 만들고
- 기존에 회원이 등록했던 deviceIdfh 된 토큰이라면 새로 만들지 않고 응답 DTO를 작성함

* fix/notificationToken-byDeviceId-2: 테스트 편의성을 위한 sql 수정

* refactor/enum-string-1: (#208)

- 국가코드, 여가, 언어코드 : NOT ENUM
- 게시글 타입, 북마크 타입, 채팅방 타입, 채팅 타입, 커넥트 상태, 파일 포맷, 채팅방 목적,  MBTI, 좋아요 타입, 알림 타입, 신고 타입 : ENUM
- 회원 생성, 채팅방 생성 테스트 완료

* chore(db): Liquibase 적용 및 수정 (#212)

* feat/liquibase-implementation-1: Liquibase 적용을 위한 yml 설정

- application.yml:
- Liquibase를 통한 DDL 생성으로 인한 ddl-auto 해제
- Liquibase와 import.sql 을 함께 사용하기 위해서 hibernate 초기화 이후 import.sql을 실행하는 옵션값인 defer-datasource-initialization값을 false 로 되돌림

- application-local.yml:
- Liquibase 사용 가능하도록 local에 추가
- master인 application.yml과 설정값 통일 시키기

* feat/liquibase-implementation-2: Liquibase XML

- migration 시키기 전 테이블 수 26개 작성
- 관계 연결 완료

* feat/liquibase-implementation-3:
test의 application.yml

- ./gradlew build 통과를 위한 liquibase 명시

* chore(db): Liquibase 적용 및 수정

개요

- 수연님이 작성해주신 Liquibase PR #204를 바탕으로 수정 진행

수정 사항

- Liquibase를 release 버전 별로 관리를 할 수 있도록 폴더 및 구조 추가
- changeset ID를 조금 더 랜덤화하고(중복 방지), type을 대문자로 하여 가독성을 높임
- FK constraint 이름은 자동 생성으로 하여 정하였음.
- liquibase가 prod, local에 둘 다 적용이 필요하므로,
application.yml에 추가
- ddl-auto 및 defer-datasourc-initialization등 기본값이 none, false이기
때문에 불필요한 코드 삭제

- 추가로, PR #208의 변경 사항으로 ENUM 관련 column들이 string으로 바뀌어서
column type도 함께 liquibase에서 변경해준다. (PR로 squash
- 초기 스크립트 에러도 고쳤음
- application-prod가 빈파일이어서 불필요하므로 삭제

---------

Co-authored-by: suyeon <[email protected]>

* feat/chatroom-random-1: 랜덤하게 10개 그룹 채팅방 뽑아오는 API 추가 및 탈퇴 시 댓글 삭제 처리 로직 수정 (#211)

* feat/chatroom-random-1: 랜덤하게 10개 그룹 채팅방 뽑아오는 API 추가

- 랜덤한 채팅방 10개의 후보군으로는 그룹 채팅방, 인원수가 꽉 차지 않은 채팅방이 보여짐

* feat/chatroom-random-2: 댓글 삭제 로직 변경

- 솔로 댓글일 경우 -> 탈퇴 시 자동 삭제
- 자식 댓글일 경우 -> 탈퇴 시 자동 삭제
- 부모 댓글일 경우 -> 탈퇴 시 NULL 처리

* feat/chatroom-random-3: 방장인 그룹 채팅방은 랜덤 호출 시 안 보이게 수정

* fix(db): 잘못 수정된 group purpose TYPE을 liquibase에 추가 (#213)

개요 및 수정사항

- group_purpose의 type 컬럼을 삭제했었는데, 필요한 컬림이므로 다시
추가해준다.

* refactor(file): File 모델의 URL 컬럼 삭제, Exception 리팩토링 (#214)

* chore(file): S3 File에 관한 Exception 정의

개요

- S3 upload 과정에서 문제가 생겼을 때 custom exception을 정의하자.

수정 사항

- S3 File 이름의 validation을 위한 S3FileNameInvalidException 정의
- 찾는 S3 파일이 DB에 없을 때를 위한 S3FileNotFoundException 정의

* refactor(file): File 모델의 URL 컬럼 삭제, Exception 리팩토링

개요

- 현재 DB에 pre-signed url을 저장하고 있는데, pre-signed url은
일시적으로만 사용하는 것이므로 DB에 저장을 하지않도록 한다.
  - 프론트엔드 코드에서는 다행히 File 모델의 url 값을 필요로 하는 부분은 없어서
리팩토링 진행 (presignedImgProfile로 이미지 렌더링을 하더라구요)

- 반복되는 코드 genereatePresignedUrl 함수로 리팩토링
- exception의 경우에 global exception handler가 있으므로, try catch 걸지
않아도, 괜찮아서 삭제

* refactor/board-getall-1: 게시글 모든 타입도 가져올 수 있게 수정 (#215)

- 파라미터 변경사항 -> type 존재

* fix/blockservice-mistake-1: 잘못 비교했던 id 비교 수정 & 메서드 재활용 UP (#216)

* refactor/board-getall-1: 게시글 모든 타입도 가져올 수 있게 수정
- 파라미터 변경사항 -> type 존재

* fix/blockservice-mistake-1: 잘못 비교했던 id 비교 수정 & 메서드 재활용 UP

* fix/blockservice-mistake-1: 본인이 방장인 채팅방 불러오기 추가

- 기존 채팅방을 불러오는 API인 GET: /chatrooms 에서 파라미터를 아무것도 넣지 않을 때 방장을 불러올 수 있음
- 파리미터 GROUP -> 속하거나 방장인 그룹 채팅방
- 파라미터 SINGLE -> 속한 싱글 채팅방

* refactor/swagger-add-1: 배제해두었던 ChatroomSwagger 되살리기 & 모든 Controller 스… (#218)

* refactor/swagger-add-1: 배제해두었던 ChatroomSwagger 되살리기 & 모든 Controller 스웨거 작성완료

- ENUM 타입 중에 DTO를 통해서만 전달되는 값들은 스웨거에 명시가 안되어서 멘트로 추가해두었음

* refactor/swagger-add-2: 파일 Presign URL 접근 방법 변경 -> id로 접근

- 제한 사항 : 본인의 학생증 인증 파일에 관해 URL 접근 권한자를 지정함
- File 엔티티에 isSecret 칼럼 추가해 추후 유연하게 조절할 예정

- MemberService:
- 기존에는 회원은 최초의 온보딩 과정에서만 학생증 인증사진을 올릴 수 있었으나 verfied된 회원도 사진을 올릴 수 있도록 수정

- Liquibase 칼럼 추가 (v1.0.1) 및 master -> include 명령으로 수정

* refactor/swagger-add-3: 누락된 update Null 방지 코드 추가

* refactor/swagger-add-4: 과도기 단계 - 구버전의 파일 name으로 PresignUrl 가져오기 남겨두기

* refactor/report-add-chatroom-1: 그룹 채팅방 신고 추가 (#219)

* refactor/report-add-chatroom-1: 그룹 채팅방 신고 추가

- Report에 외래키 chatroom 추가
- 로직은 기존 신고와 댓글/게시글과의 연관관계와 동일
- swagger, liquibase 작성완료

* refactor/report-add-chatroom-2: 그룹 채팅방 조회 시 참여 여부 표시 -> isEntered

- 그룹 채팅방 생성 시에도 조회와 같은 DTO 사용한다.
- 때문에 isEntered가 불러와지는데 생성 후에는 본인만 보일 응답 DTO이기 때문에 DTO를 적을 필요가 없다 판단 -> 조회 시에만 isEntered값이 들어감

* Perf/fix response dto : DTO에 민감한 정보 포함되지 않도록 (#220)

* perf/fix-response-dto-1: 그룹 채팅방 응답 DTO 수정

- Member -> MemberResponseDto 변경:
- 커스텀한 MemberModelMapper 사용
- 제외한 민감한 정보:
- 비밀번호, 전공, 실명

- Chatroom -> ChatroomResponseDto 변경
- 커스텀 Mapper ChatroomModelMapper 사용
- 제외한 민감한 정보:
- 그룹 채팅방의 비밀번호

* perf/fix-response-dto-2: 게시글/댓글 응답 DTO에 민감한 정보를 제외한 Member가 아닌 MemberResponseDto가 적히도록 수정

+신고 서비스 응답 로직 변경 -> ResponseDto보이지 않고 Created Status만 표시하도록

* perf/fix-response-dto-3: Chore

* perf/fix-response-dto-4: isBookmarked 값 Post GET요청 시 보이게 추가 및 나머지 DTO 보안화 진행

* perf/fix-response-dto-5: Build 파일 작성

* perf/fix-response-dto-6: 좋아요 응답 DTO 생성

- 기존에는 PostResponse를 재활용했으나 like Id를 가져올 수 있는 LikeResponseDto 로 수정

* perf/fix-response-dto-7: Comment 조회 시 부모 게시글의 좋아요/댓글 갯수 표시되도록

* fix(db): DB Migration 꼬인 부분을 정상화 (#224)

개요

- 현재 Migration 관련해서 히스토리가 꼬여서 이를 정상화하자.

수정 사항

- includeAll로 v1.0 하위 폴더의 모든 changeSet 감지하도록
- chatroom_id가 report에 컬럼이 없어서 FK를 못거는 상황이어서 추가해줌

* fix(chat): 채팅 이미지 사이즈 관련 조정 및 멤버 채팅 DTO에 포함 (#225)

* fix(db): DB Migration 꼬인 부분을 정상화

개요

- 현재 Migration 관련해서 히스토리가 꼬여서 이를 정상화하자.

수정 사항

- includeAll로 v1.0 하위 폴더의 모든 changeSet 감지하도록
- chatroom_id가 report에 컬럼이 없어서 FK를 못거는 상황이어서 추가해줌

* fix(chat): 채팅 이미지 사이즈 관련 조정 및 멤버 채팅 DTO에 포함

개요

- 채팅 이미지를 10MB 이상으로 받으려면 스프링 자체에도 설정이 필요해서
추가
- Member를 Response 타입에 포함시켜 프론트에 전달 (정보가 필요)

---------

Co-authored-by: Koo Su Yeon <[email protected]>
Co-authored-by: suyeon <[email protected]>

* Revert "release(v1.0.2): v1.0.2 merge (#229)" (#230)

This reverts commit 010f0f7b84a0a102b1c61e304e5276ed761c4b69.

* release(v1.0.2): v1.0.2 (#231)

* Refactor/file include url chat byte : 채팅 String으로 이미지 입력을 받자 (#203)

* refactor/file-includeUrl-chatByte-1: 파일 upload시 url에 presignURL 적히도록 수정

* refactor/file-includeUrl-chatByte-2:

- 1. 파일 List형태의 imgCode (여러개 이미지 파일)로 전송 시 MultipartFile로 바꿈

- 2. File업로드 진행
- 3. Redis로 파일 List형태의 presign URL 전송

- 실패 : 파일 저장도 안되고 전송도 안됨

* refactor/file-includeUrl-chatByte-3:

- imgCode에 따른 DTO의 수정사항

* refactor/file-includeUrl-chatByte-4:

- else

* fix(채팅): 채팅 파일 전송 수정 (#205)

* fix(채팅): 채팅 파일 전송 수정

개요

- 수연님이 구현해주신 PR #203에서 에러나는 부분을 수정하고 동작을
확인한다.

수정 사항

- CustomMulipartFile을 Base64MultipartFile로 이름 변경
  - 기존에 DiskFileItem으로 생성했다면, content, type, name을 직접
전달하여 명시적으로 생성하도록 변경
- 불필요한 DiskFileItem 등 삭제. 파일 생성 후 저장 방식을 수연님이 만든
Base64MultipartFile로 생성하여 fileService에 전달
- DisconnectHandler의 함수명 조금 더 명시적으로 변경
- 불필요한 모듈 삭제

* chore(ws): 웹소켓 디버깅 로깅 활성화

개요

- 앞으로 웹소켓 관련 디버깅을 조금 더 정확히 하기 위해 로컬에서 웹소켓
로깅을 활성화 한다.

* fix(sql): 채팅방 setting dummy data 수정

개요 및 수정사항

- 현재 dummyData에 count = 0이 들어가지 않아서, 채팅방 입장시
getCount에서 null으로 인식되어 에러가 뜸.

* Fix/members chatrooms display tmp (#210)

* fix/members-chatrooms-display-1:
내가 쓴 글 / 내가 쓴 댓글 조회 시 좋아요/댓글 , isLiked, isPublic 표시

* fix/members-chatrooms-display-2:
불필요해진 maxCount 삭제

* fix/members-chatrooms-display-3:
게시글 글자수 제한 해제 -> LONGTEXT로 변경

---------

Co-authored-by: suyeon <[email protected]>

* fix/notificationToken-byDeviceId-1: DeviceId마다 알림 리스트를 GET할 수 있도록 (#207)

* fix/notificationToken-byDeviceId-1:

- NotificationController, getNotifications:
- 알림 리스트를 받아올 때 pathVariable에 deviceId 추가해 deviceId별 알림 리스트를 받아올 수 있도록 함
- 이때 deviceId를 가진 회원만이 알림들을 가져올 수 있음

- sendNotificationTokens:
- deviceId 마다 하나의 토큰만이 생성되도록 로직 수정
- isTokenAlive 메서드를 추가해 이전에 해당 device 앞으로 된 토큰이 있는지 확인하고 없다면 새로 만들고
- 기존에 회원이 등록했던 deviceIdfh 된 토큰이라면 새로 만들지 않고 응답 DTO를 작성함

* fix/notificationToken-byDeviceId-2: 테스트 편의성을 위한 sql 수정

* refactor/enum-string-1: (#208)

- 국가코드, 여가, 언어코드 : NOT ENUM
- 게시글 타입, 북마크 타입, 채팅방 타입, 채팅 타입, 커넥트 상태, 파일 포맷, 채팅방 목적,  MBTI, 좋아요 타입, 알림 타입, 신고 타입 : ENUM
- 회원 생성, 채팅방 생성 테스트 완료

* chore(db): Liquibase 적용 및 수정 (#212)

* feat/liquibase-implementation-1: Liquibase 적용을 위한 yml 설정

- application.yml:
- Liquibase를 통한 DDL 생성으로 인한 ddl-auto 해제
- Liquibase와 import.sql 을 함께 사용하기 위해서 hibernate 초기화 이후 import.sql을 실행하는 옵션값인 defer-datasource-initialization값을 false 로 되돌림

- application-local.yml:
- Liquibase 사용 가능하도록 local에 추가
- master인 application.yml과 설정값 통일 시키기

* feat/liquibase-implementation-2: Liquibase XML

- migration 시키기 전 테이블 수 26개 작성
- 관계 연결 완료

* feat/liquibase-implementation-3:
test의 application.yml

- ./gradlew build 통과를 위한 liquibase 명시

* chore(db): Liquibase 적용 및 수정

개요

- 수연님이 작성해주신 Liquibase PR #204를 바탕으로 수정 진행

수정 사항

- Liquibase를 release 버전 별로 관리를 할 수 있도록 폴더 및 구조 추가
- changeset ID를 조금 더 랜덤화하고(중복 방지), type을 대문자로 하여 가독성을 높임
- FK constraint 이름은 자동 생성으로 하여 정하였음.
- liquibase가 prod, local에 둘 다 적용이 필요하므로,
application.yml에 추가
- ddl-auto 및 defer-datasourc-initialization등 기본값이 none, false이기
때문에 불필요한 코드 삭제

- 추가로, PR #208의 변경 사항으로 ENUM 관련 column들이 string으로 바뀌어서
column type도 함께 liquibase에서 변경해준다. (PR로 squash
- 초기 스크립트 에러도 고쳤음
- application-prod가 빈파일이어서 불필요하므로 삭제

---------

Co-authored-by: suyeon <[email protected]>

* feat/chatroom-random-1: 랜덤하게 10개 그룹 채팅방 뽑아오는 API 추가 및 탈퇴 시 댓글 삭제 처리 로직 수정 (#211)

* feat/chatroom-random-1: 랜덤하게 10개 그룹 채팅방 뽑아오는 API 추가

- 랜덤한 채팅방 10개의 후보군으로는 그룹 채팅방, 인원수가 꽉 차지 않은 채팅방이 보여짐

* feat/chatroom-random-2: 댓글 삭제 로직 변경

- 솔로 댓글일 경우 -> 탈퇴 시 자동 삭제
- 자식 댓글일 경우 -> 탈퇴 시 자동 삭제
- 부모 댓글일 경우 -> 탈퇴 시 NULL 처리

* feat/chatroom-random-3: 방장인 그룹 채팅방은 랜덤 호출 시 안 보이게 수정

* fix(db): 잘못 수정된 group purpose TYPE을 liquibase에 추가 (#213)

개요 및 수정사항

- group_purpose의 type 컬럼을 삭제했었는데, 필요한 컬림이므로 다시
추가해준다.

* refactor(file): File 모델의 URL 컬럼 삭제, Exception 리팩토링 (#214)

* chore(file): S3 File에 관한 Exception 정의

개요

- S3 upload 과정에서 문제가 생겼을 때 custom exception을 정의하자.

수정 사항

- S3 File 이름의 validation을 위한 S3FileNameInvalidException 정의
- 찾는 S3 파일이 DB에 없을 때를 위한 S3FileNotFoundException 정의

* refactor(file): File 모델의 URL 컬럼 삭제, Exception 리팩토링

개요

- 현재 DB에 pre-signed url을 저장하고 있는데, pre-signed url은
일시적으로만 사용하는 것이므로 DB에 저장을 하지않도록 한다.
  - 프론트엔드 코드에서는 다행히 File 모델의 url 값을 필요로 하는 부분은 없어서
리팩토링 진행 (presignedImgProfile로 이미지 렌더링을 하더라구요)

- 반복되는 코드 genereatePresignedUrl 함수로 리팩토링
- exception의 경우에 global exception handler가 있으므로, try catch 걸지
않아도, 괜찮아서 삭제

* refactor/board-getall-1: 게시글 모든 타입도 가져올 수 있게 수정 (#215)

- 파라미터 변경사항 -> type 존재

* fix/blockservice-mistake-1: 잘못 비교했던 id 비교 수정 & 메서드 재활용 UP (#216)

* refactor/board-getall-1: 게시글 모든 타입도 가져올 수 있게 수정
- 파라미터 변경사항 -> type 존재

* fix/blockservice-mistake-1: 잘못 비교했던 id 비교 수정 & 메서드 재활용 UP

* fix/blockservice-mistake-1: 본인이 방장인 채팅방 불러오기 추가

- 기존 채팅방을 불러오는 API인 GET: /chatrooms 에서 파라미터를 아무것도 넣지 않을 때 방장을 불러올 수 있음
- 파리미터 GROUP -> 속하거나 방장인 그룹 채팅방
- 파라미터 SINGLE -> 속한 싱글 채팅방

* refactor/swagger-add-1: 배제해두었던 ChatroomSwagger 되살리기 & 모든 Controller 스… (#218)

* refactor/swagger-add-1: 배제해두었던 ChatroomSwagger 되살리기 & 모든 Controller 스웨거 작성완료

- ENUM 타입 중에 DTO를 통해서만 전달되는 값들은 스웨거에 명시가 안되어서 멘트로 추가해두었음

* refactor/swagger-add-2: 파일 Presign URL 접근 방법 변경 -> id로 접근

- 제한 사항 : 본인의 학생증 인증 파일에 관해 URL 접근 권한자를 지정함
- File 엔티티에 isSecret 칼럼 추가해 추후 유연하게 조절할 예정

- MemberService:
- 기존에는 회원은 최초의 온보딩 과정에서만 학생증 인증사진을 올릴 수 있었으나 verfied된 회원도 사진을 올릴 수 있도록 수정

- Liquibase 칼럼 추가 (v1.0.1) 및 master -> include 명령으로 수정

* refactor/swagger-add-3: 누락된 update Null 방지 코드 추가

* refactor/swagger-add-4: 과도기 단계 - 구버전의 파일 name으로 PresignUrl 가져오기 남겨두기

* refactor/report-add-chatroom-1: 그룹 채팅방 신고 추가 (#219)

* refactor/report-add-chatroom-1: 그룹 채팅방 신고 추가

- Report에 외래키 chatroom 추가
- 로직은 기존 신고와 댓글/게시글과의 연관관계와 동일
- swagger, liquibase 작성완료

* refactor/report-add-chatroom-2: 그룹 채팅방 조회 시 참여 여부 표시 -> isEntered

- 그룹 채팅방 생성 시에도 조회와 같은 DTO 사용한다.
- 때문에 isEntered가 불러와지는데 생성 후에는 본인만 보일 응답 DTO이기 때문에 DTO를 적을 필요가 없다 판단 -> 조회 시에만 isEntered값이 들어감

* Perf/fix response dto : DTO에 민감한 정보 포함되지 않도록 (#220)

* perf/fix-response-dto-1: 그룹 채팅방 응답 DTO 수정

- Member -> MemberResponseDto 변경:
- 커스텀한 MemberModelMapper 사용
- 제외한 민감한 정보:
- 비밀번호, 전공, 실명

- Chatroom -> ChatroomResponseDto 변경
- 커스텀 Mapper ChatroomModelMapper 사용
- 제외한 민감한 정보:
- 그룹 채팅방의 비밀번호

* perf/fix-response-dto-2: 게시글/댓글 응답 DTO에 민감한 정보를 제외한 Member가 아닌 MemberResponseDto가 적히도록 수정

+신고 서비스 응답 로직 변경 -> ResponseDto보이지 않고 Created Status만 표시하도록

* perf/fix-response-dto-3: Chore

* perf/fix-response-dto-4: isBookmarked 값 Post GET요청 시 보이게 추가 및 나머지 DTO 보안화 진행

* perf/fix-response-dto-5: Build 파일 작성

* perf/fix-response-dto-6: 좋아요 응답 DTO 생성

- 기존에는 PostResponse를 재활용했으나 like Id를 가져올 수 있는 LikeResponseDto 로 수정

* perf/fix-response-dto-7: Comment 조회 시 부모 게시글의 좋아요/댓글 갯수 표시되도록

* fix(db): DB Migration 꼬인 부분을 정상화 (#224)

개요

- 현재 Migration 관련해서 히스토리가 꼬여서 이를 정상화하자.

수정 사항

- includeAll로 v1.0 하위 폴더의 모든 changeSet 감지하도록
- chatroom_id가 report에 컬럼이 없어서 FK를 못거는 상황이어서 추가해줌

* fix(chat): 채팅 이미지 사이즈 관련 조정 및 멤버 채팅 DTO에 포함 (#225)

* fix(db): DB Migration 꼬인 부분을 정상화

개요

- 현재 Migration 관련해서 히스토리가 꼬여서 이를 정상화하자.

수정 사항

- includeAll로 v1.0 하위 폴더의 모든 changeSet 감지하도록
- chatroom_id가 report에 컬럼이 없어서 FK를 못거는 상황이어서 추가해줌

* fix(chat): 채팅 이미지 사이즈 관련 조정 및 멤버 채팅 DTO에 포함

개요

- 채팅 이미지를 10MB 이상으로 받으려면 스프링 자체에도 설정이 필요해서
추가
- Member를 Response 타입에 포함시켜 프론트에 전달 (정보가 필요)

* Feat/translate community-1 : 사용자에게 기기 언어 추가 및 커뮤니티 서비스 번역 추가 (#223)

* feat/translate-community-1: 사용자에게 기기언어 추가
- PUT 요청에서 추가 가능
- EN, KO, ZH, JA, ES (ENUM 타입)
- null일 경우 자동 EN 처리

* feat/translate-community-2: 댓글 작성 시에 번역된 알림 추가 및 DOCS 작업 추가

* feat/translate-community-3: 커넥트 생성, 성공 / 게시글 좋아요 / 댓글 좋아요 / 채팅방 입장 시에 번역된 알림 전송

* feat/translate-community-4: 번역 언어는 String으로 받기 (DEEPL 번역 언어 String)

* feat/translate-community-5: 제한이 존재하는 번역진행

- 게시글, 채팅 번역 추가
- 게시글은 title, content가 그 범위임
- 회원당 번역 제한 15개

* feat/translate-community-6: DOCS & chore

* feat/translate-community-6-add:./spotlessapply

* feat/translate-community-6-chore:Liquibase 지정 및 ENUM LanguageType 삭제

* feat/translate-community-7-rebase-liquibase

* feat/translate-community-8:
댓글 번역 추가

* feat/translate-community-9:
ResourceBundle을 이용한 알림 번역본 properties화

* feat/translate-community-10:
피드백 반영 중복되는 Transalte 엔티티 인터페이스 & Override 이용

- 게시글의 경우 title과 content의 분리는 \n로 하였음

* Perf/member module : MemberService 모듈화 및 비밀번호 변경 후 로직 추가 (#226)

* perf/member-module-1: 불필요한 DTO 정보 제외 & 비밀번호 변경 후 로직 추가

- 비밀번호 변경 시:
- 1. 변경된 비밀번호 발급과 동시에 member.setIsPassword를 true로 업데이트
- 2. 변경된 비밀번호로 로그인 후 IsPassword가 true에 한해 비밀번호를 update 가능하게 해줌 PUT :/api/members
- 변경과 함께 다시 IsPasswordChanged False로 변환
- 즉, change-password API를 실행한 후에야 비밀번호 편집 자격 부여

* perf/member-module-2: memberService 모듈화 진행 및 chore

* perf/member-module-3: 비밀번호 재설정 로직 변경

- 1. 비밀번호 변경 시 -> 메일 발송 (인증번호 용도) GET :/members/change-password (NO AUTH)
- 2. 해당 인증번호로 비밀번호 재설정 API PATCH 요청 (NO AUTH)
- 파라미터로 인증번호와 새로 설정할 비밀번호와 계정 이메일을 넣고 요청을 보냄
- 인증번호 불일치 시 403에러 내뱉음

* perf/member-module-4: 비밀번호 인증번호 일치 여부를 새로운 비밀번호 설정 전에 확인할 수 있도록 함

* fix(chat): 그룹 채팅 전용 조회 API를 1:1 겸용으로 개조 (#227)

* fix(chat): 그룹 채팅 전용 조회 API를 1:1 겸용으로 개조

개요

- 현재 그룹채팅 전용으로 사용 중인 /chatrooms/getGroupChatrooms와 /chatrooms/getGroupChatroom을 1:1도 사용할 수 있도록 겸용으로 바꾼다.

수정 사항

- 함수명 변경
- 1:1 채팅의 경우에는 방장이 없으므로, null 값이 들어가서 에러가 남.
따라서, GROUP이 있는 경우에만 값처리를 해주자

* fix(chat): 1:1 채팅방에서 상대방이 멤버 목록에서 빠져있음

개요

- 상대방이 1:1 채팅방 정보 요청을 하면 거기에 정보가 빠져 있다. 원인은
member에 본인만 등록해주는 부분이 있었음.

* fix/translate-get-1: 게시글 가져올 때 \n 이 아닌 각각으로 가져오기 (#228)

---------

Co-authored-by: Koo Su Yeon <[email protected]>
Co-authored-by: suyeon <[email protected]>

* hotfix(db): Migration 관련 이전에 삭제를 안했던 파일을 삭제한다 (#232)

개요

- 잘못해서 삭제를 이전에 안하고 PR올림

* chore(init): init mode 기본을 never로 변경 (로컬) (#234)

개요

- Liquibase 작업을 거친 이후로 init mode가 매번 필요 없어서 never로 변경
제안

* test/isVerified-1: 베타테스트를 위한 인증 열어두기 (#233)

* fix(chat): 채팅방의 chatroom_type 정보가 없어서 추가

개요

- 채팅방의 chatroom_type 정보가 없어서 추가를 한다.

* fix(chat): 채팅방의 chatroom_type 정보가 없어서 추가 (#236)

개요

- 채팅방의 chatroom_type 정보가 없어서 추가를 한다.

* hotfix(db): Migration 관련 이전에 삭제를 안했던 파일을 삭제한다 (#232) (#235)

개요

- 잘못해서 삭제를 이전에 안하고 PR올림

* fix(db): DB Migration에서 파일을 삭제로 누락된 컬럼 부위 (#238)

* fix(db): DB Migration에서 파일을 삭제로 누락된 컬럼 부위

개요

- Migration 부분에서 파일 삭제로 인해 사라진 부분 복구

* fix(member): is_verified true위치 업데이트 함수로 변경

개요

- 현재 register에서 is_verified true로 설정을 하는데, 프로필
설정이라던지 과정이 모두 생략되므로, update 요청시 is_verified를 true로 바꿔줌
- 추가로, verification 파일이 없어도 진행이 되게끔 Comment

* fix(translate): Translatable 관련 property ignore 적용

현재, chat에서 getTextToTranslate로 인해, textToTranslate 필드값이 있는 것으로 나옴
따라서, 이 에러를 방지하고자 JsonIgnoreProperties 적용

* chore: spotlessApply

* Perf/single chatroom: 베타테스트를 위한 채팅 DTO 수정 (#240)

* perf/singleChatroom-1: 채팅 조회 총정리, 채팅방 조회 DTO 수정

- SINGLE, AUTH : 본인이 속한 일대일 채팅방 조회

- GROUP, AUTH : 본인이 속한 그룹 채팅방 조회

- AUTH : 본인이 방장인 그룹 채팅방 조회

- 채팅방 DTO 재활용을 위한 인터페이스 화 진행

- 싱글 채팅방 조회 메서드 새로 생성
- 채팅방 조회 DTO에서 채팅들 삭제

* perf/singleChatroom-2: JPA 간단화 및 채팅 RedisDTO에 민감한 정보 제외

* perf/singleChatroom-3: chore 및 누락 Liquibase 되살리기

* perf/singleChatroom-4: Spotlessapply 적용

* perf/singleChatroom-5: @JsonIgnoreProperty 적용해 Override해서 불러오지 말아야 할 값 안 가져옴

* perf/singleChatroom-7: 중복해서 들어간 @JsonIgnoreProperty 삭제

* perf/singleChatroom-8: 중복해서 들어간 Liquibase 코드 삭제

* perf/singleChatroom-9: 채팅 응답 DTO에서 누락된 채팅 ID 표시

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외) (#241)

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외)

* perf/exceptMemberDto-2: 1차 서비스 코드 정리

* hotfix/bookmarkAndtime-1: Created 기준 시간 -> 한국 시간으로 변경 & 북마크 공개/비공개 게시글 상관없이 가능하도록 수정 (#243)

* Dev (#242)

* Perf/single chatroom: 베타테스트를 위한 채팅 DTO 수정 (#240)

* perf/singleChatroom-1: 채팅 조회 총정리, 채팅방 조회 DTO 수정

- SINGLE, AUTH : 본인이 속한 일대일 채팅방 조회

- GROUP, AUTH : 본인이 속한 그룹 채팅방 조회

- AUTH : 본인이 방장인 그룹 채팅방 조회

- 채팅방 DTO 재활용을 위한 인터페이스 화 진행

- 싱글 채팅방 조회 메서드 새로 생성
- 채팅방 조회 DTO에서 채팅들 삭제

* perf/singleChatroom-2: JPA 간단화 및 채팅 RedisDTO에 민감한 정보 제외

* perf/singleChatroom-3: chore 및 누락 Liquibase 되살리기

* perf/singleChatroom-4: Spotlessapply 적용

* perf/singleChatroom-5: @JsonIgnoreProperty 적용해 Override해서 불러오지 말아야 할 값 안 가져옴

* perf/singleChatroom-7: 중복해서 들어간 @JsonIgnoreProperty 삭제

* perf/singleChatroom-8: 중복해서 들어간 Liquibase 코드 삭제

* perf/singleChatroom-9: 채팅 응답 DTO에서 누락된 채팅 ID 표시

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외) (#241)

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외)

* perf/exceptMemberDto-2: 1차 서비스 코드 정리

* hotfix/bookmarkAndtime-1: Created 기준 시간 -> 한국 시간으로 변경 & 북마크 공개/비공개 게시글 상관없이 가능하도록 수정 (#243)

* fix/comment-toMe-notification-1: 자신이 작성한 게시글에는 댓글 작성 알림 오지 않도록 (이전 회의 사항 미 반영본) (#244)

* hotfix/chatroom-getChatError-1: 채팅방 조회시 작성자와 다름 문제 해결 (#245)

* fix/comment-toMe-notification-1: 자신이 작성한 게시글에는 댓글 작성 알림 오지 않도록 (이전 회의 사항 미 반영본)

* hotfix/chatroom-getChatError-1: 채팅방 조회시 작성자와 다름 문제 해결

* Chore/merge spotlessapply (#247)

* Perf/single chatroom: 베타테스트를 위한 채팅 DTO 수정 (#240)

* perf/singleChatroom-1: 채팅 조회 총정리, 채팅방 조회 DTO 수정

- SINGLE, AUTH : 본인이 속한 일대일 채팅방 조회

- GROUP, AUTH : 본인이 속한 그룹 채팅방 조회

- AUTH : 본인이 방장인 그룹 채팅방 조회

- 채팅방 DTO 재활용을 위한 인터페이스 화 진행

- 싱글 채팅방 조회 메서드 새로 생성
- 채팅방 조회 DTO에서 채팅들 삭제

* perf/singleChatroom-2: JPA 간단화 및 채팅 RedisDTO에 민감한 정보 제외

* perf/singleChatroom-3: chore 및 누락 Liquibase 되살리기

* perf/singleChatroom-4: Spotlessapply 적용

* perf/singleChatroom-5: @JsonIgnoreProperty 적용해 Override해서 불러오지 말아야 할 값 안 가져옴

* perf/singleChatroom-7: 중복해서 들어간 @JsonIgnoreProperty 삭제

* perf/singleChatroom-8: 중복해서 들어간 Liquibase 코드 삭제

* perf/singleChatroom-9: 채팅 응답 DTO에서 누락된 채팅 ID 표시

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외) (#241)

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외)

* perf/exceptMemberDto-2: 1차 서비스 코드 정리

* hotfix/bookmarkAndtime-1: Created 기준 시간 -> 한국 시간으로 변경 & 북마크 공개/비공개 게시글 상관없이 가능하도록 수정 (#243)

* fix/comment-toMe-notification-1: 자신이 작성한 게시글에는 댓글 작성 알림 오지 않도록 (이전 회의 사항 미 반영본) (#244)

* hotfix/chatroom-getChatError-1: 채팅방 조회시 작성자와 다름 문제 해결 (#245)

* fix/comment-toMe-notification-1: 자신이 작성한 게시글에는 댓글 작성 알림 오지 않도록 (이전 회의 사항 미 반영본)

* hotfix/chatroom-getChatError-1: 채팅방 조회시 작성자와 다름 문제 해결

* fix/member-1: 회원정보 각각의 필드값에 따른 수정을 가능하게 하자

- Set형태였던 hobbies, languages들을 null 값이 아닐 때에만 수정이 들어가며 null일 때에는 기존 값들이 들어가도록 함
- 기존의 /id API로 들어갔던 수정 메서드를 토큰 인증을 이용한 API로 수정함

* hotfix/file-getById-1:
파일 id로 조회 오류 해결 & id로 파일 가져오기 대대적 적용

* hotfix/file-presignurl-1: 누락된 presignurl 수정 코드 추가 (#251)

* Dev (#252)

* Perf/single chatroom: 베타테스트를 위한 채팅 DTO 수정 (#240)

* perf/singleChatroom-1: 채팅 조회 총정리, 채팅방 조회 DTO 수정

- SINGLE, AUTH : 본인이 속한 일대일 채팅방 조회

- GROUP, AUTH : 본인이 속한 그룹 채팅방 조회

- AUTH : 본인이 방장인 그룹 채팅방 조회

- 채팅방 DTO 재활용을 위한 인터페이스 화 진행

- 싱글 채팅방 조회 메서드 새로 생성
- 채팅방 조회 DTO에서 채팅들 삭제

* perf/singleChatroom-2: JPA 간단화 및 채팅 RedisDTO에 민감한 정보 제외

* perf/singleChatroom-3: chore 및 누락 Liquibase 되살리기

* perf/singleChatroom-4: Spotlessapply 적용

* perf/singleChatroom-5: @JsonIgnoreProperty 적용해 Override해서 불러오지 말아야 할 값 안 가져옴

* perf/singleChatroom-7: 중복해서 들어간 @JsonIgnoreProperty 삭제

* perf/singleChatroom-8: 중복해서 들어간 Liquibase 코드 삭제

* perf/singleChatroom-9: 채팅 응답 DTO에서 누락된 채팅 ID 표시

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외) (#241)

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외)

* perf/exceptMemberDto-2: 1차 서비스 코드 정리

* hotfix/bookmarkAndtime-1: Created 기준 시간 -> 한국 시간으로 변경 & 북마크 공개/비공개 게시글 상관없이 가능하도록 수정 (#243)

* fix/comment-toMe-notification-1: 자신이 작성한 게시글에는 댓글 작성 알림 오지 않도록 (이전 회의 사항 미 반영본) (#244)

* hotfix/chatroom-getChatError-1: 채팅방 조회시 작성자와 다름 문제 해결 (#245)

* fix/comment-toMe-notification-1: 자신이 작성한 게시글에는 댓글 작성 알림 오지 않도록 (이전 회의 사항 미 반영본)

* hotfix/chatroom-getChatError-1: 채팅방 조회시 작성자와 다름 문제 해결

* hotfix/file-presignurl-1: 누락된 presignurl 수정 코드 추가 (#251)

* hotfix/file-profileImg-1: File presignURL ID로 가져오기 작업 - ProfileImg (#253)

* Feat/single chatroom exit : 싱글 채팅방 퇴장 및 혼자 남아있을 경우 (상대방 퇴장 시)알림 구현 (#255)

* feat/singleChatroom-1: 싱글 채팅방 퇴장 구현

- 기존 채팅방 퇴장은 그룹 채팅방 퇴장만 구현되어 있음 -> 싱글 채팅방 퇴장도 추가 구현

- 그룹 채팅방은 Redisson 처리한 사항이 있어 DB 저장 작업이 필수적임 -> 구별되게 그룹 채팅방 퇴장과 싱글 채팅방 퇴장을 구분
- 채팅 퇴장 시 퇴장 채팅 저장과 Redis 발행은 기존대로 유지 (채팅 보내기와 동일하게 동작함)

* feat/singleChatroom-2: 채팅방 퇴장 시 혼자 남은 채팅방 알림구현

- 그룹, 싱글 알림 모두 구현
- 기존 알림 서비스와 동일
- Set의 members에서 한 명의 유저만 남아있을 경우 stream.findFirst() 사용함
- 사용자 언어설정에 따른 번역 알림 추가

* feat/singleChatroom-isRead-1: 싱글 채팅방 읽음 대상자(상대방) 읽었는지 표시 구현 (#256)

* feat/singleChatroom-isRead-
1: 싱글 채팅방 읽음 대상자(상대방) 읽었는지 표시 구현

- Chat 엔티티에 해당 Boolean 값인 isOtherRead 생성
- 읽음 대상자 (상대방)이 GET :chats?chatroomId={채팅방 ID}를 하면 해당 isOtherRead를 true로 바꿔줌

* hotfix/chatroom-bookmark-individual-1: 채팅방 별 북마크 조회 가능하도록 수정

* feat/singleChatroom-isRead-
2: 싱글 채팅방 퇴장 시 알림 구현 사항 되돌리기
- 이유 : 불필요

* QA를 위한 dev -> prod (#257)

* hotfix/file-profileImg-1: File presignURL ID로 가져오기 작업 - ProfileImg (#253)

* Feat/single chatroom exit : 싱글 채팅방 퇴장 및 혼자 남아있을 경우 (상대방 퇴장 시)알림 구현 (#255)

* feat/singleChatroom-1: 싱글 채팅방 퇴장 구현

- 기존 채팅방 퇴장은 그룹 채팅방 퇴장만 구현되어 있음 -> 싱글 채팅방 퇴장도 추가 구현

- 그룹 채팅방은 Redisson 처리한 사항이 있어 DB 저장 작업이 필수적임 -> 구별되게 그룹 채팅방 퇴장과 싱글 채팅방 퇴장을 구분
- 채팅 퇴장 시 퇴장 채팅 저장과 Redis 발행은 기존대로 유지 (채팅 보내기와 동일하게 동작함)

* feat/singleChatroom-2: 채팅방 퇴장 시 혼자 남은 채팅방 알림구현

- 그룹, 싱글 알림 모두 구현
- 기존 알림 서비스와 동일
- Set의 members에서 한 명의 유저만 남아있을 경우 stream.findFirst() 사용함
- 사용자 언어설정에 따른 번역 알림 추가

* feat/singleChatroom-isRead-1: 싱글 채팅방 읽음 대상자(상대방) 읽었는지 표시 구현 (#256)

* feat/singleChatroom-isRead-
1: 싱글 채팅방 읽음 대상자(상대방) 읽었는지 표시 구현

- Chat 엔티티에 해당 Boolean 값인 isOtherRead 생성
- 읽음 대상자 (상대방)이 GET :chats?chatroomId={채팅방 ID}를 하면 해당 isOtherRead를 true로 바꿔줌

* hotfix/chatroom-bookmark-individual-1: 채팅방 별 북마크 조회 가능하도록 수정

* feat/singleChatroom-isRead-
2: 싱글 채팅방 퇴장 시 알림 구현 사항 되돌리기
- 이유 : 불필요

* Feat/chat authorization : 일대일 채팅 JWT Authorization 넣기  (#254)

* feat/chat-authorization-1: STOMP 시큐리티 작업

- SecurityWebSockConfig:
- SecurityConfig로 보호되지 않았던 /pub, /sub 보안 잠그기
- WebSockConfig:
- 채팅 발행하기에 앞서 Client에서 보내준 Authorization 값 STOMP Session에 포함시키기 위한 Interceptor 주입

* feat/chat-authorization-2: WebSocketInterceptor 작업

- WebSocketInterceptor:
- CONNCECT -> SEND 모두 authorization을 받아 JWTFilter의 doFilterChain 메서드가 하는 일을 수행함
- 자격증명이 마친다면 StompHeaderAccessor로 회원 이메일을 전달함

* hotfix/chatroom-exit-unsubscribe-1: 기존에 DISCONNECT 했던 채팅방을 UNSUBSCRIBE로 퇴장을 구현함 (#258)

* hotfix/chatroom-exit-unsubscribe-1: 기존에 DISCONNECT 했던 채팅방을 UNSUBSCIRBE로 퇴장을 수정함

* hotfix/chatroom-exit-unsubscribe-2: spotlessapply

* feat(채팅): 더 세밀한 채팅 관련 인증/인가 조절 구현 (#259)

개요

- 현재 SecurityWebSocketConfig에서 HttpSecurity를 사용하고 있는데, 이를
authorizationManager로 바꾸어 STOMP 명령어별로 인증/인가를 설정할 수
있도록 한다.

수정사항

- 누구나 접속해도 되는 CONNECT, UNSUB, DISCONNECT, HEARTBEAT는 풀어놓고
- MESSAGE, SUB은 인증이 될 경우에만 호출할 수 있도록 한다.
- 추가로, SEND /pub, SUBSCRIBE /sub으로의 destination은 무조건 인증된
경우만 접근할 수 있도록
- 이외의 호출은 모두 거절한다.

- csrfChannelInterceptor는 csrf 활성화를 제거하기 위한 작업. (브라우저는
어플에서 사용하지 않으므로 csrf 비활성화)

- Interceptor의 로직 같은 경우, 초기 CONNECT하는 경우에만 JWT로 해당
유저의 인증상태를 확인한다. (만료된 상황에서 확인하는 과정은 다음 PR에서
진행하도록 하겠습니다.)

- authenticated()를 AuthorizationManager에서 사용하려면, 현재 컨텍스트에
setAuthentication을 해주고, 이후의 활용을 위해 accessor.setUser까지
추가해줘야한다. 그래야만 인증이 되었을 때, 문제없이 인증을 할 수 있다.

- 참고로, Websocket 자체에서 인증 인가를, Header에서 simpUser로 진행하기
때문에, 기존에 header에 넣어줬던 userEmail을 제거하고
SocketController의 UserDetails 주입을 통해 해당 인증 정보를 가져올 수
있도록 한다. 기존의 userEmail을 이렇게 변경한 이유는, 웹소켓이 초기에
연결이 성립되고 이후에 메시지보내기 등을 사용하면 기존의 Auth 정보는
header에 저장이 되지만, 우리가 직접 넣어줬던 userEmail은 요청마다 새로
다시 넣어줘야하기 때문이다.

* fix(error): 웹소켓 에러 시에 이유 함께 보낼 수 있도록 처리 (#260)

개요

- 현재 웹소켓의 연결이 끊길 때 원인이 잘 나오지 않는 문제가 있다.
- 에러 발생 시, 원인을 전달하기 위해 StompSubProtocolHandler를 직접
작성한다.
- Interceptor에서 에러 체킹을 추가한다.

수정 사항

- 에러 발생 시, 원인을 전달하기 위해 StompSubProtocolHandler를 직접
  - 빠른 구현을 위해 링크 참고해서 일부만 수정함: https://velog.io/@jkijki12/%EC%B1%84%ED%8C%85-STOMP-JWT
- WebsocketInterceptor에서, JWT가 필요한 Command와 그렇지 않은
Command를 구분해서 알맞게 상황처리를 해준다.
  - CONNECT, SEND, MESSAGE, SUBSCRIBE는 JWT 필요
  - CONNECT의 경우에는 초기 auth 설정해줌
  - SUBSCRIBE의 경우에 destination 체킹 진행
  - SUBSCRIBE 때, 구독 권한이 있는지 확인한다.
- chatroom.getMembers().contains(member) 이 부분에서 Member 인스턴스가
달라도, id로 멤버가 포함되어있는지 체킹이 필요하기 때문에, equals와
hashcode 함께 override (Convention 따라, o 변수 사용)

* refactor/chat-exit-auth-1: 개선된 채팅 인증/인가 적용한 채팅방 퇴장 수정 (#261)

- 기존에 채팅방 퇴장하면 DISCONNECT 했던 것을 UNSUBSCRIBE로 수정
-  messagingTemplate 이용해 UNSUBSCRIBE 메시지 직접 서버에서 전송

chore
- 이전에 DISCONNECT 하지 않았어야 하는 enter 부분 코드 Exception 던지는 것으로 수정
- 불필요한 퇴장 시 빈 채팅방 확인 코드 삭제

* Revert "Feat/chatroom re enter (#264)" (#267)

This reverts commit c75de607533575343a5f69be2723d212fdb5a0a7.

* Merge/dev (#270)

* feat/chatroom-reEnter-1: 재입장 가능하도록
- 중간 테이블 chatroom_exited_member 생성

재입장 로직:
- EXIT을 하게 되면 chatroom_member에서 member이 삭제되는 것이 아닌 chatroom_exited_member에 member가 추가되는 것임

- 응답 DTO에 퇴장한 회원 정보 표시 (그룹 채팅방에 접속한 회원 수 표시 목적)

* feat/chatroom-reEnter-2: 채팅방 조회 코드 수정 및 chore

- ChatService:
- EXIT:
- 퇴장을 하게 되면 chatroom의 members에서 삭제되는 것이 아닌 exitedMembers에 추가되는 것임
- CHAT:
- 퇴장을 한 회원에게는 채팅 알림이 가지 않아야 하기 때문에 제외 코드를 추가함
- ENTER:
- 그 후 재 입장을 하게 되면 원래 있던 채팅방에 입장해야 하기 때문에 exitedMembers에서 삭제를 진행하며 입장 알림이 가도록 함

- ChatroomService:
- GET 채팅방 조회시에 퇴장한 채팅방은 포함되지 않아야 하기 때문에 filter 코드 추가함
- 퇴장한 채팅방 조회도 가능하도록 추가
- GET : /api/chatrooms?type=EXITED

chore
- 방장인 채팅방 조회:
- GET : /api/chatrooms?type=MANAGER
- Test 통과를 위한 JVM 크기 2GB로 늘림
- SWAGGER 반영 완료

* feat/chatroom-reEnter-3: 퇴장한 채팅방 접근 강화

* feat/chatroom-reEnter-4: build messaging 추가

* Merge/prod dev pr : 채팅방 재입장 적용한 prod merge PR (#268)

* Feat/chat authorization : 일대일 채팅 JWT Authorization 넣기  (#254)

* feat/chat-authorization-1: STOMP 시큐리티 작업

- SecurityWebSockConfig:
- SecurityConfig로 보호되지 않았던 /pub, /sub 보안 잠그기
- WebSockConfig:
- 채팅 발행하기에 앞서 Client에서 보내준 Authorization 값 STOMP Session에 포함시키기 위한 Interceptor 주입

* feat/chat-authorization-2: WebSocketInterceptor 작업

- WebSocketInterceptor:
- CONNCECT -> SEND 모두 authorization을 받아 JWTFilter의 doFilterChain 메서드가 하는 일을 수행함
- 자격증명이 마친다면 StompHeaderAccessor로 회원 이메일을 전달함

* hotfix/chatroom-exit-unsubscribe-1: 기존에 DISCONNECT 했던 채팅방을 UNSUBSCRIBE로 퇴장을 구현함 (#258)

* hotfix/chatroom-exit-unsubscribe-1: 기존에 DISCONNECT 했던 채팅방을 UNSUBSCIRBE로 퇴장을 수정함

* hotfix/chatroom-exit-unsubscribe-2: spotlessapply

* feat(채팅): 더 세밀한 채팅 관련 인증/인가 조절 구현 (#259)

개요

- 현재 SecurityWebSocketConfig에서 HttpSecurity를 사용하고 있는데, 이를
authorizationManager로 바꾸어 STOMP 명령어별로 인증/인가를 설정할 수
있도록 한다.

수정사항

- 누구나 접속해도 되는 CONNECT, UNSUB, DISCONNECT, HEARTBEAT는 풀어놓고
- MESSAGE, SUB은 인증이 될 경우에만 호출할 수 있도록 한다.
- 추가로, SEND /pub, SUBSCRIBE /sub으로의 destination은 무조건 인증된
경우만 접근할 수 있도록
- 이외의 호출은 모두 거절한다.

- csrfChannelInterceptor는 csrf 활성화를 제거하기 위한 작업. (브라우저는
어플에서 사용하지 않으므로 csrf 비활성화)

- Interceptor의 로직 같은 경우, 초기 CONNECT하는 경우에만 JWT로 해당
유저의 인증상태를 확인한다. (만료된 상황에서 확인하는 과정은 다음 PR에서
진행하도록 하겠습니다.)

- authenticated()를 AuthorizationManager에서 사용하려면, 현재 컨텍스트에
setAuthentication을 해주고, 이후의 활용을 위해 accessor.setUser까지
추가해줘야한다. 그래야만 인증이 되었을 때, 문제없이 인증을 할 수 있다.

- 참고로, Websocket 자체에서 인증 인가를, Header에서 simpUser로 진행하기
때문에, 기존에 header에 넣어줬던 userEmail을 제거하고
SocketController의 UserDetails 주입을 통해 해당 인증 정보를 가져올 수
있도록 한다. 기존의 userEmail을 이렇게 변경한 이유는, 웹소켓이 초기에
연결이 성립되고 이후에 메시지보내기 등을 사용하면 기존의 Auth 정보는
header에 저장이 되지만, 우리가 직접 넣어줬던 userEmail은 요청마다 새로
다시 넣어줘야하기 때문이다.

* fix(error): 웹소켓 에러 시에 이유 함께 보낼 수 있도록 처리 (#260)

개요

- 현재 웹소켓의 연결이 끊길 때 원인이 잘 나오지 않는 문제가 있다.
- 에러 발생 시, 원인을 전달하기 위해 StompSubProtocolHandler를 직접
작성한다.
- Interceptor에서 에러 체킹을 추가한다.

수정 사항

- 에러 발생 시, 원인을 전달하기 위해 StompSubProtocolHandler를 직접
  - 빠른 구현을 위해 링크 참고해서 일부만 수정함: https://velog.io/@jkijki12/%EC%B1%84%ED%8C%85-STOMP-JWT
- WebsocketInterceptor에서, JWT가 필요한 Command와 그렇지 않은
Command를 구분해서 알맞게 상황처리를 해준다.
  - CONNECT, SEND, MESSAGE, SUBSCRIBE는 JWT 필요
  - CONNECT의 경우에는 초기 auth 설정해줌
  - SUBSCRIBE의 경우에 destination 체킹 진행
  - SUBSCRIBE 때, 구독 권한이 있는지 확인한다.
- chatroom.getMembers().contains(member) 이 부분에서 Member 인스턴스가
달라도, id로 멤버가 포함되어있는지 체킹이 필요하기 때문에, equals와
hashcode 함께 override (Convention 따라, o 변수 사용)

* refactor/chat-exit-auth-1: 개선된 채팅 인증/인가 적용한 채팅방 퇴장 수정 (#261)

- 기존에 채팅방 퇴장하면 DISCONNECT 했던 것을 UNSUBSCRIBE로 수정
-  messagingTemplate 이용해 UNSUBSCRIBE 메시지 직접 서버에서 전송

chore
- 이전에 DISCONNECT 하지 않았어야 하는 enter 부분 코드 Exception 던지는 것으로 수정
- 불필요한 퇴장 시 빈 채팅방 확인 코드 삭제

* Revert "Feat/chatroom re enter (#264)" (#267)

This reverts commit c75de607533575343a5f69be2723d212fdb5a0a7.

* Refactor/chatroom re enter (#269)

* feat/chatroom-reEnter-1: 재입장 가능하도록
- 중간 테이블 chatroom_exited_member 생성

재입장 로직:
- EXIT을 하게 되면 chatroom_member에서 member이 삭제되는 것이 아닌 chatroom_exited_member에 member가 추가되는 것임

- 응답 DTO에 퇴장한 회원 정보 표시 (그룹 채팅방에 접속한 회원 수 표시 목적)

* feat/chatroom-reEnter-2: 채팅방 조회 코드 수정 및 chore

- ChatService:
- EXIT:
- 퇴장을 하게 되면 chatroom의 members에서 삭제되는 것이 아닌 exitedMembers에 추가되는 것임
- CHAT:
- 퇴장을 한 회원에게는 채팅 알림이 가지 않아야 하기 때문에 제외 코드를 추가함
- ENTER:
- 그 후 재 입장을 하게 되면 원래 있던 채팅방에 입장해야 하기 때문에 exitedMembers에서 삭제를 진행하며 입장 알림이 가도록 함

- ChatroomService:
- GET 채팅방 조회시에 퇴장한 채팅방은 포함되지 않아야 하기 때문에 filter 코드 추가함
- 퇴장한 채팅방 조회도 가능하도록 추가
- GET : /api/chatrooms?type=EXITED

chore
- 방장인 채팅방 조회:
- GET : /api/chatrooms?type=MANAGER
- Test 통과를 위한 JVM 크기 2GB로 늘림
- SWAGGER 반영 완료

* feat/chatroom-reEnter-3: 퇴장한 채팅방 접근 강화

* feat/chatroom-reEnter-4: build messaging 추가

---------

Co-authored-by: Seungho Lee <[email protected]>

* chore(posts): Posts 에러 관련하여 더 정확한 디버깅을 위해 로깅 추가 (#271)

개요 및 수정사항

- 게시글 에러 관련하여, 정확한 디버깅을 위해 로깅을 추가하자.
- 추가로, SQL 출력문을 없앤다.

* Merge/dev (#270) (#273)

* feat/chatroom-reEnter-1: 재입장 가능하도록
- 중간 테이블 chatroom_exited_member 생성

재입장 로직:
- EXIT을 하게 되면 chatroom_member에서 member이 삭제되는 것이 아닌 chatroom_exited_member에 member가 추가되는 것임

- 응답 DTO에 퇴장한 회원 정보 표시 (그룹 채팅방에 접속한 회원 수 표시 목적)

* feat/chatroom-reEnter-2: 채팅방 조회 코드 수정 및 chore

- ChatService:
- EXIT:
- 퇴장을 하게 되면 chatroom의 members에서 삭제되는 것이 아닌 exitedMembers에 추가되는 것임
- CHAT:
- 퇴장을 한 회원에게는 채팅 알림이 가지 않아야 하기 때문에 제외 코드를 추가함
- ENTER:
- 그 후 재 입장을 하게 되면 원래 있던 채팅방에 입장해야 하기 때문에 exitedMembers에서 삭제를 진행하며 입장 알림이 가도록 함

- ChatroomService:
- GET 채팅방 조회시에 퇴장한 채팅방은 포함되지 않아야 하기 때문에 filter 코드 추가함
- 퇴장한 채팅방 조회도 가능하도록 추가
- GET : /api/chatrooms?type=EXITED

chore
- 방장인 채팅방 조회:
- GET : /api/chatrooms?type=MANAGER
- Test 통과를 위한 JVM 크기 2GB로 늘림
- SWAGGER 반영 완료

* feat/chatroom-reEnter-3: 퇴장한 채팅방 접근 강화

* feat/chatroom-reEnter-4: build messaging 추가

* feat/chatroom-dto-add-lastChat-1: 채팅방 GET요청 시 최신 순 정렬된 마지막 채팅 DTO에 추가 (#272)

* chore(log): 버그 확인 용도로 사용한 로깅 삭제 (#275)

개요

- 꿀팁게시판 자유게시판이 섞이는 부분의 확인을 위해 로깅함수를
사용했는데 이를 삭제한다.

* fix(ws): 웹소켓 HEARTBEAT 안되는 문제 구현 (#276)

* hotfix/member-like-mapping-1: 회원정보 불러올 때 ResponseMapper 수정 (제대로 Hobbies와 Languages 불러오도록) (#278)

* Feat/chatroom exit and re enter : 퇴장 후 재 입장 코드 로직 수정 및 개선 (#277)

* feat/chatroom-exit-and-reEnter-1: 퇴장 채팅방과 회원 엔티티 간의 중간 테이블 생성

- 생성한 원인으로는 기존에 만들었던 테이블 (채팅방과 회원)으로는 reEnterTime 컬럼을 생성할 수 없었기 때문

- 퇴장 로직 설명:
- 퇴장을 하면 중간테이블인 ChatroomExitedMember가 생김
- 해당 테이블에 채팅방, 회원 reEnterTime이 생김
- 재입장 하지 않는 한 해당 테이블의 reEnterTime은 null임 (퇴장, 재입장, 퇴장 시에도 null)
- 채팅방, 회원 간에 unique해야 하는 테이블이므로 uniqueConstraints 값 설정

* feat/chatroom-exit-and-reEnter-2: 퇴장 후 재입장 및 채팅 불러오기 로직 정리

- 재입장 로직:
- 재입장 시에는 CheckPoint에 시각이 찍힘
- 이는 채팅 불러오기, 채팅방 구독 전 EXITED 채팅방 불러오기 시에 사용
- GET :/chats?chatroomId={} 시에 getChats를 할 때에 reEnterTime 이후에 유효한 채팅이 자동으로 적용되어 들어감

- docs : Liquibase 문 기존에 만들어 둔 단순 중간 테이블 삭제 후 새 테이블 생성 (이중 테이불이 생기는 경우이므로 기존 DDL update 문 삭제 후 생성을 진행함)

* feat/chatroom-exit-and-reEnter-3: Migration은 삭제가 아닌 수정을 하자

- 기존 외래키 관계 및 고유 키 drop 후 새로 중간 테이블 새로 생성
- 이전에 선언했던 단순 중간 테이블 v1.0.5.xml 되살리기

* feat/chatroom-exit-and-reEnter-4: 중간 테이블 ChatroomMember 재 선언

- ExitMember과 ActiveMember를 함께 관리

* feat/chatroom-exit-and-reEnter-5: 주요 수정 Service

- 기존 퇴장, 재입장 로직과 동일
- 채팅방의 ACTIVE 한 채팅방 회원들만 가져오는 함수 모듈화
- getSingleChatroom에 앞선 모듈화 함수를 사용하지 않은 이유로는 재입장 시에 사용하는 엔드포인트에서도 (EXITED) 사용하기 때문
- 재입장 시에만 EXITED 조건을 허용해 주기 때문에 다른 메서드에서는 ACTIVE한 상태인지 확인하는 조건이 추가됨
- 웹소켓 preSend 조건에서 사용하는 isMemberInChatroom에서는 Sub 시에 사용하기 때문에 재 입장 시에도 Sub 먼저 해야 하기 때문에 채팅방과 회원간에 관계가 없을 경우에만 Exception을 내뱉도록 수정함

* feat/chatroom-exit-and-reEnter-6: getMembers -> validMembers 메서드 이용후 contains() 메서드 이용

* feat/chatroom-exit-and-reEnter-7: chore/docs

* feat/chatroom-exit-and-reEnter-8: SUB 보안 되살리기

- 앞선 코드에서 SUB를 퇴장한 회원에 한해서는 허용해왔지만
- 퇴장한 회원 가운데에 재입장한 회원에 한해 허용하도록 엔드포인트를 하나 더 생성함 (서버에서 채팅방 회원의 status를 Active로 바꿔주는 엔드포인트)

* feat/chatroom-count-1: 채팅방 list 조회 시에 count가 보이도록 구현 (#279)

- lastHoldAt : ChatroomMember에 채팅방을 떠날 때에 TimeStamp를 기록
- 해당 값은 채팅방 뒤로가기를 누를 시에, 채팅 목록 조회 시에 업데이트 됨

- Put :/chatrooms/{chatroomId}/hold 엔드포인트 생성 :
- 해당 엔드포인트는 채팅방 안읽은 채팅 갯수를 업데이트 하기 위한 용도로 사용됨

* fix/ddl-content-toLongText-1: (#281)

* fix/ddl-content-toLongText-1:

- POST, COMMENT : DDL 긴 게시글 내용 작성 가능하도록 수정
- MEMBER : 한줄소개 이모지 생성 가능한 타입 LONGTEXT로 수정 (프론트쪽에서 글자 수 제한 유)

* fix/ddl-content-toLongText-2:
spotlessapply

* fix/ddl-content-toLongText-3:
불필요한 Chat의 otherRead 삭제 (DDL)

* fix/ddl-content-toLongText-4:
otherRead 삭제 반영

* fix(profile): MBTI 선택 안함 옵션을 위해 null로 저장 (#283)

* Rebase/from prod to dev (#285)

* Dev (#274)

* Perf/single chatroom: 베타테스트를 위한 채팅 DTO 수정 (#240)

* perf/singleChatroom-1: 채팅 조회 총정리, 채팅방 조회 DTO 수정

- SINGLE, AUTH : 본인이 속한 일대일 채팅방 조회

- GROUP, AUTH : 본인이 속한 그룹 채팅방 조회

- AUTH : 본인이 방장인 그룹 채팅방 조회

- 채팅방 DTO 재활용을 위한 인터페이스 화 진행

- 싱글 채팅방 조회 메서드 새로 생성
- 채팅방 조회 DTO에서 채팅들 삭제

* perf/singleChatroom-2: JPA 간단화 및 채팅 RedisDTO에 민감한 정보 제외

* perf/singleChatroom-3: chore 및 누락 Liquibase 되살리기

* perf/singleChatroom-4: Spotlessapply 적용

* perf/singleChatroom-5: @JsonIgnoreProperty 적용해 Override해서 불러오지 말아야 할 값 안 가져옴

* perf/singleChatroom-7: 중복해서 들어간 @JsonIgnoreProperty 삭제

* perf/singleChatroom-8: 중복해서 들어간 Liquibase 코드 삭제

* perf/singleChatroom-9: 채팅 응답 DTO에서 누락된 채팅 ID 표시

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외) (#241)

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외)

* perf/exceptMemberDto-2: 1차 서비스 코드 정리

* hotfix/bookmarkAndtime-1: Created 기준 시간 -> 한국 시간으로 변경 & 북마크 공개/비공개 게시글 상관없이 가능하도록 수정 (#243)

* fix/comment-toMe-notification-1: 자신이 작성한 게시글에는 댓글 작성 알림 오지 않도록 (이전 회의 사항 미 반영본) (#244)

* hotfix/chatroom-getChatError-1: 채팅방 조회시 작성자와 다름 문제 해결 (#245)

* fix/comment-toMe-notification-1: 자신이 작성한 게시글에는 댓글 작성 알림 오지 않도록 (이전 회의 사항 미 반영본)

* hotfix/chatroom-getChatError-1: 채팅방 조회시 작성자와 다름 문제 해결

* hotfix/file-presignurl-1: 누락된 presignurl 수정 코드 추가 (#251)

* hotfix/file-profileImg-1: File presignURL ID로 가져오기 작업 - ProfileImg (#253)

* Feat/single chatroom exit : 싱글 채팅방 퇴장 및 혼자 남아있을 경우 (상대방 퇴장 시)알림 구현 (#255)

* feat/singleChatroom-1: 싱글 채팅방 퇴장 구현

- 기존 채팅방 퇴장은 그룹 채팅방 퇴장만 구현되어 있음 -> 싱글 채팅방 퇴장도 추가 구현

- 그룹 채팅방은 Redisson 처리한 사항이 있어 DB 저장 작업이 필수적임 -> 구별되게 그룹 채팅방 퇴장과 싱글 채팅방 퇴장을 구분
- 채팅 퇴장 시 퇴장 채팅 저장과 Redis 발행은 기존대로 유지 (채팅 보내기와 동일하게 동작함)

* feat/singleChatroom-2: 채팅방 퇴장 시 혼자 남은 채팅방 알림구현

- 그룹, 싱글 알림 모두 구현
- 기존 알림 서비스와 동일
- Set의 members에서 한 명의 유저만 남아있을 경우 stream.findFirst() 사용함
- 사용자 언어설정에 따른 번역 알림 추가

* feat/singleChatroom-isRead-1: 싱글 채팅방 읽음 대상자(상대방) 읽었는지 표시 구현 (#256)

* feat/singleChatroom-isRead-
1: 싱글 채팅방 읽음 대상자(상대방) 읽었는지 표시 구현

- Chat 엔티티에 해당 Boolean 값인 isOtherRead 생성
- 읽음 대상자 (상대방)이 GET :chats?chatroomId={채팅방 ID}를 하면 해당 isOtherRead를 true로 바꿔줌

* hotfix/chatroom-bookmark-individual-1: 채팅방 별 북마크 조회 가능하도록 수정

* feat/singleChatroom-isRead-
2: 싱글 채팅방 퇴장 시 알림 구현 사항 되돌리기
- 이유 : 불필요

* Feat/chat authorization : 일대일 채팅 JWT Authorization 넣기  (#254)

* feat/chat-authorization-1: STOMP 시큐리티 작업

- SecurityWebSockConfig:
- SecurityConfig로 보호되지 않았던 /pub, /sub 보안 잠그기
- WebSockConfig:
- 채팅 발행하기에 앞서 Client에서 보내준 Authorization 값 STOMP Session에 포함시키기 위한 Interceptor 주입

* feat/chat-authorization-2: WebSocketInterceptor 작업

- WebSocketInterceptor:
- CONNCECT -> SEND 모두 authorization을 받아 JWTFilter의 doFilterChain 메서드가 하는 일을 수행함
- 자격증명이 마친다면 StompHeaderAccessor로 회원 이메일을 전달함

* hotfix/chatroom-exit-unsubscribe-1: 기존에 DISCONNECT 했던 채팅방을 UNSUBSCRIBE로 퇴장을 구현함 (#258)

* hotfix/chatroom-exit-unsubscribe-1: 기존에 DISCONNECT 했던 채팅방을 UNSUBSCIRBE로 퇴장을 수정함

* hotfix/chatroom-exit-unsubscribe-2: spotlessapply

* feat(채팅): 더 세밀한 채팅 관련 인증/인가 조절 구현 (#259)

개요

- 현재 SecurityWebSocketConfig에서 HttpSecurity를 사용하고 있는데, 이를
authorizationManager로 바꾸어 STOMP 명령어별로 인증/인가를 설정할 수
있도록 한다.

수정사항

- 누구나 접속해도 되는 CONNECT, UNSUB, DISCONNECT, HEARTBEAT는 풀어놓고
- MESSAGE, SUB은 인증이 될 경우에만 호출할 수 있도록 한다.
- 추가로, SEND /pub, SUBSCRIBE /sub으로의 destination은 무조건 인증된
경우만 접근할 수 있도록
- 이외의 호출은 모두 거절한다.

- csrfChannelInterceptor는 csrf 활성화를 제거하기 위한 작업. (브라우저는
어플에서 사용하지 않으므로 csrf 비활성화)

- Interceptor의 로직 같은 경우, 초기 CONNECT하는 경우에만 JWT로 해당
유저의 인증상태를 확인한다. (만료된 상황에서 확인하는 과정은 다음 PR에서
진행하도록 하겠습니다.)

- authenticated()를 AuthorizationManager에서 사용하려면, 현재 컨텍스트에
setAuthentication을 해주고, 이후의 활용을 위해 accessor.setUser까지
추가해줘야한다. 그래야만 인증이 되었을 때, 문제없이 인증을 할 수 있다.

- 참고로, Websocket 자체에서 인증 인가를, Header에서 simpUser로 진행하기
때문에, 기존에 header에 넣어줬던 userEmail을 제거하고
SocketController의 UserDetails 주입을 통해 해당 인증 정보를 가져올 수
있도록 한다. 기존의 userEmail을 이렇게 변경한 이유는, 웹소켓이 초기에
연결이 성립되고 이후에 메시지보내기 등을 사용하면 기존의 Auth 정보는
header에 저장이 되지만, 우리가 직접 넣어줬던 userEmail은 요청마다 새로
다시 넣어줘야하기 때문이다.

* fix(error): 웹소켓 에러 시에 이유 함께 보낼 수 있도록 처리 (#260)

개요

- 현재 웹소켓의 연결이 끊길 때 원인이 잘 나오지 않는 문제가 있다.
- 에러 발생 시, 원인을 전달하기 위해 StompSubProtocolHandler를 직접
작성한다.
- Interceptor에서 에러 체킹을 추가한다.

수정 사항

- 에러 발생 시, 원인을 전달하기 위해 StompSubProtocolHandler를 직접
  - 빠른 구현을 위해 링크 참고해서 일부만 수정함: https://velog.io/@jkijki12/%EC%B1%84%ED%8C%85-STOMP-JWT
- WebsocketInterceptor에서, JWT가 필요한 Command와 그렇지 않은
Command를 구분해서 알맞게 상황처리를 해준다.
  - CONNECT, SEND, MESSAGE, SUBSCRIBE는 JWT 필요
  - CONNECT의 경우에는 초기 auth 설정해줌
  - SUBSCRIBE의 경우에 destination 체킹 진행
  - SUBSCRIBE 때, 구독 권한이 있는지 확인한다.
- chatroom.getMembers().contains(member) 이 부분에서 Member 인스턴스가
달라도, id로 멤버가 포함되어있는지 체킹이 필요하기 때문에, equals와
hashcode 함께 override (Convention 따라, o 변수 사용)

* refactor/chat-exit-auth-1: 개선된 채팅 인증/인가 적용한 채팅방 퇴장 수정 (#261)

- 기존에 채팅방 퇴장하면 DISCONNECT 했던 것을 UNSUBSCRIBE로 수정
-  messagingTemplate 이용해 UNSUBSCRIBE 메시지 직접 서버에서 전송

chore
- 이전에 DISCONNECT 하지 않았어야 하는 enter 부분 코드 Exception 던지는 것으로 수정
- 불필요한 퇴장 시 빈 채팅방 확인 코드 삭제

* Revert "Feat/chatroom re enter (#264)" (#267)

This reverts commit c75de607533575343a5f69be2723d212fdb5a0a7.

* Merge/dev (#270)

* feat/chatroom-reEnter-1: 재입장 가능하도록
- 중간 테이블 chatroom_exited_member 생성

재입장 로직:
- EXIT을 하게 되면 chatroom_member에서 member이 삭제되는 것이 아닌 chatroom_exited_member에 member가 추가되는 것임

- 응답 DTO에 퇴장한 회원 정보 표시 (그룹 채팅방에 접속한 회원 수 표시 목적)

* feat/chatroom-reEnter-2: 채팅방 조회 코드 수정 및 chore

- ChatService:
- EXIT:
- 퇴장을 하게 되면 chatroom의 members에서 삭제되는 것이 아닌 exitedMembers에 추가되는 것임
- CHAT:
- 퇴장을 한 회원에게는 채팅 알림이 가지 않아야 하기 때문에 제외 코드를 추가함
- ENTER:
- 그 후 재 입장을 하게 되면 원래 있던 채팅방에 입장해야 하기 때문에 exitedMembers에서 삭제를 진행하며 입장 알림이 가도록 함

- ChatroomService:
- GET 채팅방 조회시에 퇴장한 채팅방은 포함되지 않아야 하기 때문에 filter 코드 추가함
- 퇴장한 채팅방 조회도 가능하도록 추가
- GET : /api/chatrooms?type=EXITED

chore
- 방장인 채팅방 조회:
- GET : /api/chatrooms?type=MANAGER
- Test 통과를 위한 JVM 크기 2GB로 늘림
- SWAGGER 반영 완료

* feat/chatroom-reEnter-3: 퇴장한 채팅방 접근 강화

* feat/chatroom-reEnter-4: build messaging 추가

* Merge/dev (#270) (#273)

* feat/chatroom-reEnter-1: 재입장 가능하도록
- 중간 테이블 chatroom_exited_member 생성

재입장 로직:
- EXIT을 하게 되면 chatroom_member에서 member이 삭제되는 것이 아닌 chatroom_exited_member에 member가 추가되는 것임

- 응답 DTO에 퇴장한 회원 정보 표시 (그룹 채팅방에 접속한 회원 수 표시 목적)

* feat/chatroom-reEnter-2: 채팅방 조회 코드 수정 및 chore

- ChatService:
- EXIT:
- 퇴장을 하게 되면 chatroom의 members에서 삭제되는 것이 아닌 exitedMembers에 추가되는 것임
- CHAT:
- 퇴장을 한 회원에게는 채팅 알림이 가지 않아야 하기 때문에 제외 코드를 추가함
- ENTER:
- 그 후 재 입장을 하게 되면 원래 있던 채팅방에 입장해야 하기 때문에 exitedMembers에서 삭제를 진행하며 입장 알림이 가도록 함

- ChatroomService:
- GET 채팅방 조회시에 퇴장한 채팅방은 포함되지 않아야 하기 때문에 filter 코드 추가함
- 퇴장한 채팅방 조회도 가능하도록 추가
- GET : /api/chatrooms?type=EXITED

chore
- 방장인 채팅방 조회:
- GET : /api/chatrooms?type=MANAGER
- Test 통과를 위한 JVM 크기 2GB로 늘림
- SWAGGER 반영 완료

* feat/chatroom-reEnter-3: 퇴장한 채팅방 접근 강화

* feat/chatroom-reEnter-4: build messaging 추가

---------

Co-authored-by: Seungho Lee <[email protected]>

* Dev (#280)

* Perf/single chatroom: 베타테스트를 위한 채팅 DTO 수정 (#240)

* perf/singleChatroom-1: 채팅 조회 총정리, 채팅방 조회 DTO 수정

- SINGLE, AUTH : 본인이 속한 일대일 채팅방 조회

- GROUP, AUTH : 본인이 속한 그룹 채팅방 조회

- AUTH : 본인이 방장인 그룹 채팅방 조회

- 채팅방 DTO 재활용을 위한 인터페이스 화 진행

- 싱글 채팅방 조회 메서드 새로 생성
- 채팅방 조회 DTO에서 채팅들 삭제

* perf/singleChatroom-2: JPA 간단화 및 채팅 RedisDTO에 민감한 정보 제외

* perf/singleChatroom-3: chore 및 누락 Liquibase 되살리기

* perf/singleChatroom-4: Spotlessapply 적용

* perf/singleChatroom-5: @JsonIgnoreProperty 적용해 Override해서 불러오지 말아야 할 값 안 가져옴

* perf/singleChatroom-7: 중복해서 들어간 @JsonIgnoreProperty 삭제

* perf/singleChatroom-8: 중복해서 들어간 Liquibase 코드 삭제

* perf/singleChatroom-9: 채팅 응답 DTO에서 누락된 채팅 ID 표시

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외) (#241)

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외)

* perf/exceptMemberDto-2: 1차 서비스 코드 정리

* hotfix/bookmarkAndtime-1: Created 기준 시간 -> 한국 시간으로 변경 & 북마크 공개/비공개 게시글 상관없이 가능하도록 수정 (#243)

* fix/comment-toMe-notification-1: 자신이 작성한 게시글에는 댓글 작성 알림 오지 않도록 (이전 회의 사항 미 반영본) (#244)

* hotfix/chatroom-getChatError-1: 채팅방 조회시 작성자와 다름 문제 해결 (#245)

* fix/comment-toMe-notification-1: 자신이 작성한 게시글에는 댓글 작성 알림 오지 않도록 (이전 회의 사항 미 반영본)

* hotfix/chatroom-getChatError-1: 채팅방 조회시 작성자와 다름 문제 해결

* hotfix/file-presignurl-1: 누락된 presignurl 수정 코드 추가 (#251)

* hotfix/file-profileImg-1: File presignURL ID로 가져오기 작업 - ProfileImg (#253)

* Feat/single chatroom exit : 싱글 채팅방 퇴장 및 혼자 남아있을 경우 (상대방 퇴장 시)알림 구현 (#255)

* feat/singleChatroom-1: 싱글 채팅방 퇴장 구현

- 기존 채팅방 퇴장은 그룹 채팅방 퇴장만 구현되어 있음 -> 싱글 채팅방 퇴장도 추가 구현

- 그룹 채팅방은 Redisson 처리한 사항이 있어 DB 저장 작업이 필수적임 -> 구별되게 그룹 채팅방 퇴장과 싱글 채팅방 퇴장을 구분
- 채팅 퇴장 시 퇴장 채팅 저장과 Redis 발행은 기존대로 유지 (채팅 보내기와 동일하게 동작함)

* feat/singleChatroom-2: 채팅방 퇴장 시 혼자 남은 채팅방 알림구현

- 그룹, 싱글 알림 모두 구현
- 기존 알림 서비스와 동일
- Set의 members에서 한 명의 유저만 남아있을 경우 stream.findFirst() 사용함
- 사용자 언어설정에 따른 번역 알림 추가

* feat/singleChatroom-isRead-1: 싱글 채팅방 읽음 대상자(상대방) 읽었는지 표시 구현 (#256)

* feat/singleChatroom-isRead-
1: 싱글 채팅방 읽음 대상자(상대방) 읽었는지 표시 구현

- Chat 엔티티에 해당 Boolean 값인 isOtherRead 생성
- 읽음 대상자 (상대방)이 GET :chats?chatroomId={채팅방 ID}를 하면 해당 isOtherRead를 true로 바꿔줌

* hotfix/chatroom-bookmark-individual-1: 채팅방 별 북마크 조회 가능하도록 수정

* feat/singleChatroom-isRead-
2: 싱글 채팅방 퇴장 시 알림 구현 사항 되돌리기
- 이유 : 불필요

* Feat/chat authorization : 일대일 채팅 JWT Authorization 넣기  (#254)

* feat/chat-authorization-1: STOMP 시큐리티 작업

- SecurityWebSockConfig:
- SecurityConfig로 보호되지 않았던 /pub, /sub 보안 잠그기
- WebSockConfig:
- 채팅 발행하기에 앞서 Client에서 보내준 Authorization 값 STOMP Session에 포함시키기 위한 Interceptor 주입

* feat/chat-authorization-2: WebSocketInterceptor 작업

- WebSocketInterceptor:
- CONNCECT -> SEND 모두 authorization을 받아 JWTFilter의 doFilterChain 메서드가 하는 일을 수행함
- 자격증명이 마친다면 StompHeaderAccessor로 회원 이메일을 전달함

* hotfix/chatroom-exit-unsubscribe-1: 기존에 DISCONNECT 했던 채팅방을 UNSUBSCRIBE로 퇴장을 구현함 (#258)

* hotfix/chatroom-exit-unsubscribe-1: 기존에 DISCONNECT 했던 채팅방을 UNSUBSCIRBE로 퇴장을 수정함

* hotfix/chatroom-exit-unsubscribe-2: spotlessapply

* feat(채팅): 더 세밀한 채팅 관련 인증/인가 조절 구현 (#259)

개요

- 현재 SecurityWebSocketConfig에서 HttpSecurity를 사용하고 있는데, 이를
authorizationManager로 바꾸어 STOMP 명령어별로 인증/인가를 설정할 수
있도록 한다.

수정사항

- 누구나 접속해도 되는 CONNECT, UNSUB, DISCONNECT, HEARTBEAT는 풀어놓고
- MESSAGE, SUB은 인증이 될 경우에만 호출할 수 있도록 한다.
- 추가로, SEND /pub, SUBSCRIBE /sub으로의 destination은 무조건 인증된
경우만 접근할 수 있도록
- 이외의 호출은 모두 거절한다.

- csrfChannelInterceptor는 csrf 활성화를 제거하기 위한 작업. (브라우저는
어플에서 사용하지 않으므로 csrf 비활성화)

- Interceptor의 로직 같은 경우, 초기 CONNECT하는 경우에만 JWT로 해당
유저의 인증상태를 확인한다. (만료된 상황에서 확인하는 과정은 다음 PR에서
진행하도록 하겠습니다.)

- authenticated()를 AuthorizationManager에서 사용하려면, 현재 컨텍스트에
setAuthentication을 해주고, 이후의 활용을 위해 accessor.setUser까지
추가해줘야한다. 그래야만 인증이 되었을 때, 문제없이 인증을 할 수 있다.

- 참고로, Websocket 자체에서 인증 인가를, Header에서 simpUser로 진행하기
때문에, 기존에 header에 넣어줬던 userEmail을 제거하고
SocketController의 UserDetails 주입을 통해 해당 인증 정보를 가져올 수
있도록 한다. 기존의 userEmail을 이렇게 변경한 이유는, 웹소켓이 초기에
연결이 성립되고 이후에 메시지보내기 등을 사용하면 기존의 Auth 정보는
header에 저장이 되지만, 우리가 직접 넣어줬던 userEmail은 요청마다 새로
다시 넣어줘야하기 때문이다.

* fix(error): 웹소켓 에러 시에 이유 함께 보낼 수 있도록 처리 (#260)

개요

- 현재 웹소켓의 연결이 끊길 때 원인이 잘 나오지 않는 문제가 있다.
- 에러 발생 시, 원인을 전달하기 위해 StompSubProtocolHandler를 직접
작성한다.
- Interceptor에서 에러 체킹을 추가한다.

수정 사항

- 에러 발생 시, 원인을 전달하기 위해 StompSubProtocolHandler를 직접
  - 빠른 구현을 위해 링크 참고해서 일부만 수정함: https://velog.io/@jkijki12/%EC%B1%84%ED%8C%85-STOMP-JWT
- WebsocketInterceptor에서, JWT가 필요한 Command와 그렇지 않은
Command를 구분해서 알맞게 상황처리를 해준다.
  - CONNECT, SEND, MESSAGE, SUBSCRIBE는 JWT 필요
  - CONNECT의 경우에는 초기 auth 설정해줌
  - SUBSCRIBE의 경우에 destination 체킹 진행
  - SUBSCRIBE 때, 구독 권한이 있는지 확인한다.
- chatroom.getMembers().contains(member) 이 부분에서 Member 인스턴스가
달라도, id로 멤버가 포함되어있는지 체킹이 필요하기 때문에, equals와
hashcode 함께 override (Convention 따라, o 변수 사용)

* refactor/chat-exit-auth-1: 개선된 채팅 인증/인가 적용한 채팅방 퇴장 수정 (#261)

- 기존에 채팅방 퇴장하면 DISCONNECT 했던 것을 UNSUBSCRIBE로 수정
-  messagingTemplate 이용해 UNSUBSCRIBE 메시지 직접 서버에서 전송

chore
- 이전에 DISCONNECT 하지 않았어야 하는 enter 부분 코드 Exception 던지는 것으로 수정
- 불필요한 퇴장 시 빈 채팅방 확인 코드 삭제

* Revert "Feat/chatroom re enter (#264)" (#267)

This reverts commit c75de607533575343a5f69be2723d212fdb5a0a7.

* Merge/dev (#270)

* feat/chatroom-reEnter-1: 재입장 가능하도록
- 중간 테이블 chatroom_exited_member 생성

재입장 로직:
- EXIT을 하게 되면 chatroom_member에서 member이 삭제되는 것이 아닌 chatroom_exited_member에 member가 추가되는 것임

- 응답 DTO에 퇴장한 회원 정보 표시 …
  • Loading branch information
3 people authored Nov 21, 2024
1 parent 569b2fd commit 86c0b0b
Show file tree
Hide file tree
Showing 127 changed files with 3,413 additions and 1,076 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ dependencies {
testImplementation 'org.testcontainers:localstack'
testImplementation 'org.testcontainers:junit-jupiter'
implementation group: 'org.redisson', name: 'redisson-spring-boot-starter', version: '3.19.0'
implementation 'org.springframework.security:spring-security-messaging'

implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.3'
Expand All @@ -70,9 +71,11 @@ dependencies {
implementation("software.amazon.awssdk:s3")

implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'
implementation 'org.liquibase:liquibase-core'
}

tasks.named('test') {
useJUnitPlatform()
jvmArgs '-Xmx2048m'
exclude '**/MemberControllerTest.*'
}
22 changes: 22 additions & 0 deletions src/main/java/com/dife/api/GlobalExceptionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import static org.springframework.http.HttpStatus.*;

import com.dife.api.exception.*;
import com.dife.api.exception.file.S3FileNameInvalidException;
import com.dife.api.exception.file.S3FileNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
Expand Down Expand Up @@ -66,6 +68,12 @@ public ResponseEntity<ExceptionResonse> handleConnectException(
.body(new ExceptionResonse(false, exception.getMessage()));
}

@ExceptionHandler(BlockNotFoundException.class)
public ResponseEntity<ExceptionResonse> handleBlockException(BlockNotFoundException exception) {
return ResponseEntity.status(NOT_FOUND.value())
.body(new ExceptionResonse(false, exception.getMessage()));
}

@ExceptionHandler(PostNotFoundException.class)
public ResponseEntity<ExceptionResonse> handlePostNotFoundException(
PostNotFoundException exception) {
Expand Down Expand Up @@ -126,4 +134,18 @@ public ResponseEntity<ExceptionResonse> handleRuntimeException(RuntimeException
return ResponseEntity.status(FORBIDDEN.value())
.body(new ExceptionResonse(false, exception.getMessage()));
}

@ExceptionHandler(S3FileNotFoundException.class)
public ResponseEntity<ExceptionResonse> handleS3FileNotFoundException(
S3FileNotFoundException exception) {
return ResponseEntity.status(NOT_FOUND.value())
.body(new ExceptionResonse(false, exception.getMessage()));
}

@ExceptionHandler(S3FileNameInvalidException.class)
public ResponseEntity<ExceptionResonse> handleS3FileNameInvalidException(
S3FileNameInvalidException exception) {
return ResponseEntity.status(BAD_REQUEST.value())
.body(new ExceptionResonse(false, exception.getMessage()));
}
}
25 changes: 25 additions & 0 deletions src/main/java/com/dife/api/config/JpaConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.dife.api.config;

import jakarta.annotation.PostConstruct;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Optional;
import java.util.TimeZone;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.auditing.DateTimeProvider;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@Configuration
@EnableJpaAuditing(dateTimeProviderRef = "auditingDateTimeProvider")
public class JpaConfig {
@Bean
public DateTimeProvider auditingDateTimeProvider() {
return () -> Optional.of(ZonedDateTime.now(ZoneId.of("Asia/Seoul")));
}

@PostConstruct
public void init() {
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul"));
}
}
53 changes: 42 additions & 11 deletions src/main/java/com/dife/api/config/MapperConfig.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.dife.api.config;

import com.dife.api.model.*;
import com.dife.api.model.dto.ChatroomResponseDto;
import com.dife.api.model.dto.GroupChatroomResponseDto;
import com.dife.api.model.dto.MemberResponseDto;
import com.dife.api.model.dto.SingleChatroomResponseDto;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;
Expand All @@ -31,10 +33,9 @@ public ModelMapper chatroomModelMapper() {
.setConverter(context -> context.getSource().getName());
modelMapper
.typeMap(GroupPurpose.class, String.class)
.setConverter(context -> context.getSource().getName());

.setConverter(context -> context.getSource().getType().name());
modelMapper
.typeMap(Chatroom.class, ChatroomResponseDto.class)
.typeMap(Chatroom.class, GroupChatroomResponseDto.class)
.addMappings(
mapper -> {
mapper.map(
Expand All @@ -44,7 +45,7 @@ public ModelMapper chatroomModelMapper() {
.stream()
.map(Hobby::getName)
.collect(Collectors.toSet()),
ChatroomResponseDto::setHobbies);
GroupChatroomResponseDto::setHobbies);

mapper.map(
src ->
Expand All @@ -53,20 +54,48 @@ public ModelMapper chatroomModelMapper() {
.stream()
.map(Language::getName)
.collect(Collectors.toSet()),
ChatroomResponseDto::setLanguages);

GroupChatroomResponseDto::setLanguages);
mapper.map(
src ->
Optional.ofNullable(src.getChatroomSetting().getPurposes())
.orElse(Collections.emptySet())
.stream()
.map(GroupPurpose::getName)
.map(GroupPurpose::getType)
.collect(Collectors.toSet()),
ChatroomResponseDto::setPurposes);
GroupChatroomResponseDto::setPurposes);

mapper.map(
src -> src.getChatroomSetting().getPassword(), ChatroomResponseDto::setPassword);
src -> {
Set<ChatroomMember> members = src.getMembers();
if (members == null) {
return Collections.emptySet();
}
return members.stream()
.filter(
chatroomMember -> chatroomMember.getStatus() == ChatroomStatus.ACTIVE)
.map(ChatroomMember::getMember)
.collect(Collectors.toSet());
},
GroupChatroomResponseDto::setMembers);
});
modelMapper
.typeMap(Chatroom.class, SingleChatroomResponseDto.class)
.addMappings(
mapper -> {
mapper.map(
src -> {
Set<ChatroomMember> members = src.getMembers();
if (members == null) {
return Collections.emptySet();
}
return members.stream()
.filter(
chatroomMember -> chatroomMember.getStatus() == ChatroomStatus.ACTIVE)
.map(ChatroomMember::getMember)
.collect(Collectors.toSet());
},
SingleChatroomResponseDto::setMembers);
});

return modelMapper;
}

Expand All @@ -84,6 +113,8 @@ public ModelMapper memberModelMapper() {
.typeMap(Member.class, MemberResponseDto.class)
.addMappings(
mapper -> {
mapper.map(Member::getCreated, MemberResponseDto::setCreated);
mapper.map(Member::getModified, MemberResponseDto::setModified);
mapper.map(Member::getUsername, MemberResponseDto::setUsername);
mapper.map(Member::getCountry, MemberResponseDto::setCountry);
mapper.map(Member::getBio, MemberResponseDto::setBio);
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/com/dife/api/config/SecurityWebSocketConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.dife.api.config;

import static org.springframework.messaging.simp.SimpMessageType.*;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.config.annotation.web.socket.EnableWebSocketSecurity;
import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager;

@Configuration
@EnableWebSocketSecurity
public class SecurityWebSocketConfig {
@Bean
AuthorizationManager<Message<?>> authorizationManager(
MessageMatcherDelegatingAuthorizationManager.Builder messages) {
return messages
.simpTypeMatchers(CONNECT, UNSUBSCRIBE, DISCONNECT, HEARTBEAT)
.permitAll()
.simpMessageDestMatchers("/pub/**")
.authenticated()
.simpSubscribeDestMatchers("/sub/**")
.authenticated()
.simpTypeMatchers(MESSAGE, SUBSCRIBE)
.authenticated()
.anyMessage()
.denyAll()
.build();
}

@Bean("csrfChannelInterceptor")
ChannelInterceptor csrfChannelInterceptor() {
return new ChannelInterceptor() {};
}
}
22 changes: 20 additions & 2 deletions src/main/java/com/dife/api/config/WebSockConfig.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,41 @@
package com.dife.api.config;

import com.dife.api.exception.StompExceptionHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.config.annotation.*;

@RequiredArgsConstructor
@Configuration
@EnableWebSocketMessageBroker
public class WebSockConfig implements WebSocketMessageBrokerConfigurer {

private final StompExceptionHandler stompExceptionHandler;
private final WebSocketInterceptor webSocketInterceptor;

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins("*");
registry.setErrorHandler(stompExceptionHandler).addEndpoint("/ws").setAllowedOrigins("*");
}

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/sub");
config.enableSimpleBroker("/sub").setTaskScheduler(taskScheduler());
config.setApplicationDestinationPrefixes("/pub");
}

public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.initialize();
return taskScheduler;
}

@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(webSocketInterceptor);
}
}
115 changes: 115 additions & 0 deletions src/main/java/com/dife/api/config/WebSocketInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.dife.api.config;

import static org.springframework.messaging.simp.stomp.StompCommand.*;

import com.dife.api.jwt.JWTUtil;
import com.dife.api.model.Chatroom;
import com.dife.api.model.Member;
import com.dife.api.model.dto.CustomUserDetails;
import com.dife.api.repository.MemberRepository;
import com.dife.api.service.ChatroomService;
import com.dife.api.service.MemberService;
import jakarta.security.auth.message.AuthException;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

@Order(Ordered.HIGHEST_PRECEDENCE + 99)
@RequiredArgsConstructor
@Component
public class WebSocketInterceptor implements ChannelInterceptor {

private final JWTUtil jwtUtil;
private final MemberRepository memberRepository;
private final MemberService memberService;
private final ChatroomService chatroomService;

@SneakyThrows
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor =
MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);

Set<StompCommand> jwtExpiredCheckCommands = Set.of(CONNECT, SEND, MESSAGE, SUBSCRIBE);
StompCommand currentCommand = accessor.getCommand();

if (currentCommand == null && accessor.getMessageType() == SimpMessageType.HEARTBEAT) {
return message;
}

if (jwtExpiredCheckCommands.contains(currentCommand)) {
String authToken = accessor.getFirstNativeHeader("authorization");
String jwtToken = extractJwtToken(authToken);

if (!isValidJwtToken(jwtToken)) {
throw new AuthException("손상된 토큰입니다! 다시 로그인 하세요!");
}

Long memberId = jwtUtil.getId(jwtToken);
Member member = memberService.getMemberEntityById(memberId);
if (!memberService.isValidMember(member)) {
throw new AuthException("인증이 필요한 회원입니다!");
}
if (currentCommand.equals(CONNECT)) {
setAuthentication(member, accessor);
}

String destination = accessor.getDestination();

if (currentCommand.equals(SUBSCRIBE)) {
if (!isValidSubscriptionDestination(destination)) {
throw new AuthException(
"Unauthorized subscription to " + destination + ". Only chatrooms are allowed.");
}
Long chatroomId = parseChatroomIdFromDestination(destination);
Chatroom chatroom = chatroomService.getChatroomById(chatroomId);
if (!isMemberAllowedToSubscribe(member, chatroom)) {
throw new AuthException("채팅방 메시지 Subscribe 권한이 없습니다.!");
}
}
}
return message;
}

private boolean isValidSubscriptionDestination(String destination) {
return destination != null && destination.startsWith("/sub/chatroom/");
}

private boolean isMemberAllowedToSubscribe(Member member, Chatroom chatroom) {
return chatroomService.isMemberInChatroom(member, chatroom);
}

private Long parseChatroomIdFromDestination(String destination) {
return Long.parseLong(destination.split("/")[3]);
}

private String extractJwtToken(String authToken) {
return authToken.split(" ")[1];
}

private boolean isValidJwtToken(String jwtToken) {
return jwtToken != null && !jwtUtil.isExpired(jwtToken);
}

private void setAuthentication(Member member, StompHeaderAccessor accessor) {
CustomUserDetails customUserDetails = new CustomUserDetails(member);
Authentication authentication =
new UsernamePasswordAuthenticationToken(
customUserDetails, null, customUserDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
accessor.setUser(authentication);
}
}
6 changes: 3 additions & 3 deletions src/main/java/com/dife/api/controller/BookmarkController.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ public ResponseEntity<BookmarkResponseDto> createBookmark(
return ResponseEntity.status(CREATED).body(responseDto);
}

@GetMapping("/{chatroomId}")
@GetMapping("/")
public ResponseEntity<List<BookmarkResponseDto>> getBookmarkChats(
@PathVariable(name = "chatroomId") Long chatroomId, Authentication authentication) {
@RequestParam(name = "chatroomId") Long chatroomId, Authentication authentication) {
List<BookmarkResponseDto> bookmarks =
bookmarkService.getBookmarks(chatroomId, authentication.getName());
bookmarkService.getChatroomBookmarks(chatroomId, authentication.getName());
return ResponseEntity.ok(bookmarks);
}

Expand Down
Loading

0 comments on commit 86c0b0b

Please sign in to comment.