Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

테스트 서버 배포 #968

Merged
merged 25 commits into from
Nov 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
84187eb
🔥 BE 브랜치에 남아있는 FE 레거시 코드 제거
greetings1012 Oct 25, 2024
b04c61c
Merge pull request #927 from woowacourse-teams/BE/feature/#926
greetings1012 Oct 25, 2024
08b3dac
chore: vscode 패키지 삭제
JiHyeonL Oct 29, 2024
df4abbe
refactor: 줄바꿈 컨벤션 적용
JiHyeonL Oct 30, 2024
73d2959
refactor: 커스텀 exception 이름 및 예외 메세지 구체적으로 변경
JiHyeonL Oct 30, 2024
8de5a2c
refactor: 예외 핸들러 메서드명 수정
JiHyeonL Oct 30, 2024
dcc9270
Merge pull request #938 from woowacourse-teams/BE/feature/#909-multip…
JiHyeonL Oct 30, 2024
072e6a4
feat: 페어룸이 종료되거나 삭제된 상태일 때 발생하는 커스텀 예외 추가 및 핸들링
JiHyeonL Nov 4, 2024
e22965c
feat: 페어룸 종료 api 추가 및 종료 & 삭제 되었을 경우 페어룸 수정 시 검증 로직 추가
JiHyeonL Nov 4, 2024
96cc130
feat: 투두 생성 & 수정 & 삭제 시 페어룸이 활성화 상태인지 확인하는 방어 로직 추가
JiHyeonL Nov 4, 2024
154b6d7
feat: 카테고리 및 링 생성 & 수정 & 삭제 시 페어룸이 활성화 상태인지 확인하는 방어 로직 추가
JiHyeonL Nov 4, 2024
4d636cf
fix: 테스트 응답 status 값 수정
JiHyeonL Nov 4, 2024
5c6a19d
docs: 페어룸 종료 문서화 추가
JiHyeonL Nov 4, 2024
4a6bcd9
Merge pull request #949 from woowacourse-teams/BE/feature/#948-comple…
JiHyeonL Nov 11, 2024
40fa718
chore: #961 build.gradle Web Socket 의존성 추가
kelly6bf Nov 18, 2024
bd30648
chore: #961 SchedulerService WS 삽입 구간 마킹
kelly6bf Nov 18, 2024
6afcc39
feat: #961 Web Socket 모듈 구현
kelly6bf Nov 19, 2024
17a898f
refactor: 쿼리에서 액세스코드 파싱하는 역할 분리
yechop Nov 19, 2024
2957562
refactor: 쿼리에서 액세스코드 파싱하는 역할 분리
yechop Nov 19, 2024
cce6861
refactor: #961 기존 SSE 기반 코드를 Web Socket 기반으로 변경
kelly6bf Nov 20, 2024
ada435c
Merge remote-tracking branch 'origin/BE/feature/#961' into BE/feature…
yechop Nov 20, 2024
32f472f
chore: final 추가
yechop Nov 21, 2024
676da02
chore: 테스트 임시 @Disabled
yechop Nov 21, 2024
c5ad88b
Merge pull request #966 from woowacourse-teams/BE/feature/#961
kelly6bf Nov 23, 2024
0063874
Merge branch 'BE/test' into BE/dev
kelly6bf Nov 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
15 changes: 0 additions & 15 deletions .vscode/settings.json

This file was deleted.

3 changes: 3 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt:0.12.6'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.6'

// Web Socket
implementation 'org.springframework.boot:spring-boot-starter-websocket'

// Test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand Down Expand Up @@ -95,10 +94,18 @@ public ResponseEntity<PairRoomExistResponse> pairRoomExists(@RequestParam("acces
return ResponseEntity.ok(response);
}

@DeleteMapping("/pair-room/{accessCode}")
@PatchMapping("/pair-room/{accessCode}/complete")
public ResponseEntity<Void> completePairRoom(@PathVariable("accessCode") final String accessCode) {
pairRoomService.completePairRoom(accessCode);
return ResponseEntity.noContent()
.build();
}

@PatchMapping("/pair-room/{accessCode}/delete")
public ResponseEntity<Void> deletePairRoom(@PathVariable("accessCode") final String accessCode) {
pairRoomService.deletePairRoom(accessCode);
return ResponseEntity.noContent().build();
return ResponseEntity.noContent()
.build();
}

@GetMapping("/member/{accessCode}/exists")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
import site.coduo.common.controller.response.ApiErrorResponse;
import site.coduo.pairroom.controller.error.PairRoomApiError;
import site.coduo.pairroom.exception.DuplicatePairNameException;
import site.coduo.pairroom.exception.InactivePairRoomException;
import site.coduo.pairroom.exception.InvalidAccessCodeException;
import site.coduo.pairroom.exception.InvalidNameFormatException;
import site.coduo.pairroom.exception.InvalidPairRoomStatusException;
import site.coduo.pairroom.exception.PairRoomException;
import site.coduo.pairroom.exception.PairRoomMemberNotFoundException;
import site.coduo.pairroom.exception.PairRoomNotFoundException;
import site.coduo.pairroom.exception.InvalidPairRoomStatusException;

@Slf4j
@RestControllerAdvice
Expand All @@ -31,6 +33,14 @@ public ResponseEntity<ApiErrorResponse> handleDuplicatePairNameException(final D
.body(new ApiErrorResponse(PairRoomApiError.INVALID_PAIR_NAME.getMessage()));
}

@ExceptionHandler(InactivePairRoomException.class)
public ResponseEntity<ApiErrorResponse> handleInactivePairRoomException(final InactivePairRoomException e) {
log.warn(e.getMessage());

return ResponseEntity.status(PairRoomApiError.INACTIVE_PAIR_ROOM.getHttpStatus())
.body(new ApiErrorResponse(PairRoomApiError.INACTIVE_PAIR_ROOM.getMessage()));
}

@ExceptionHandler(InvalidAccessCodeException.class)
public ResponseEntity<ApiErrorResponse> handleInvalidAccessCodeException(final InvalidAccessCodeException e) {
log.warn(e.getMessage());
Expand All @@ -49,7 +59,8 @@ public ResponseEntity<ApiErrorResponse> handleInvalidPropertiesFormatException(
}

@ExceptionHandler(InvalidPairRoomStatusException.class)
public ResponseEntity<ApiErrorResponse> handlePairRoomStatusNotFoundException(final InvalidPairRoomStatusException e) {
public ResponseEntity<ApiErrorResponse> handlePairRoomStatusNotFoundException(
final InvalidPairRoomStatusException e) {
log.warn(e.getMessage());

return ResponseEntity.status(PairRoomApiError.INVALID_PROPERTIES_FORMAT.getHttpStatus())
Expand All @@ -64,6 +75,15 @@ public ResponseEntity<ApiErrorResponse> handlePairRoomNotFoundException(final Pa
.body(new ApiErrorResponse(PairRoomApiError.PAIR_ROOM_NOT_FOUND.getMessage()));
}

@ExceptionHandler(PairRoomMemberNotFoundException.class)
public ResponseEntity<ApiErrorResponse> handlePairRoomMemberNotFoundException(
final PairRoomMemberNotFoundException e) {
log.warn(e.getMessage());

return ResponseEntity.status(PairRoomApiError.PAIR_ROOM_MEMBER_NOT_FOUND.getHttpStatus())
.body(new ApiErrorResponse(PairRoomApiError.PAIR_ROOM_MEMBER_NOT_FOUND.getMessage()));
}

@ExceptionHandler(PairRoomException.class)
public ResponseEntity<ApiErrorResponse> handlePairRoomException(final PairRoomException e) {
log.warn(e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ ResponseEntity<Void> deletePairRoom(
String accessCode
);

@Operation(summary = "페어룸을 종료한다.")
@ApiResponse(responseCode = "204", description = "페어룸 종료 성공")
ResponseEntity<Void> completePairRoom(
@Parameter(description = "페어룸 접근 코드", required = true)
String accessCode
);

@Operation(summary = "특정 회원이 특정 페어룸에 존재하는지 여부를 조회한다.")
@ApiResponse(responseCode = "200", description = "회원 페어룸 참여 여부 조회 성공", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ExistMemberInPairRoomResponse.class)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ public enum PairRoomApiError {
INVALID_PAIR_NAME(HttpStatus.BAD_REQUEST, "올바르지 않은 페어 이름입니다."),
INVALID_ACCESS_CODE(HttpStatus.BAD_REQUEST, "올바르지 않은 접근 코드입니다."),
PAIR_ROOM_NOT_FOUND(HttpStatus.NOT_FOUND, "페어룸이 존재하지 않습니다."),
INVALID_PROPERTIES_FORMAT(HttpStatus.BAD_REQUEST, "올바르지 않은 데이터 형식입니다.");
PAIR_ROOM_MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "페어룸-멤버가 존재하지 않습니다."),
INVALID_PROPERTIES_FORMAT(HttpStatus.BAD_REQUEST, "올바르지 않은 데이터 형식입니다."),
INACTIVE_PAIR_ROOM(HttpStatus.BAD_REQUEST, "이미 종료되거나 삭제된 페어룸입니다.");

private final HttpStatus httpStatus;
private final String message;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package site.coduo.pairroom.exception;

public class InactivePairRoomException extends PairRoomException {

public InactivePairRoomException(final String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package site.coduo.pairroom.exception;

public class NotFoundPairRoomSessionException extends PairRoomException {

public NotFoundPairRoomSessionException(final String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@ public void swapNavigatorWithDriver() {
this.driver = temp;
}

public boolean isDelete() {
public boolean isActive() {
return status != PairRoomStatus.COMPLETED && status != PairRoomStatus.DELETED;
}

public boolean isDeleted() {
return status == PairRoomStatus.DELETED;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import site.coduo.pairroom.domain.accesscode.generator.AccessCodeGenerator;
import site.coduo.pairroom.domain.accesscode.generator.EasyAccessCodeGenerator;
import site.coduo.pairroom.domain.accesscode.generator.UUIDAccessCodeGenerator;
import site.coduo.pairroom.exception.DeletePairRoomException;
import site.coduo.pairroom.exception.InactivePairRoomException;
import site.coduo.pairroom.repository.PairRoomEntity;
import site.coduo.pairroom.repository.PairRoomMemberEntity;
import site.coduo.pairroom.repository.PairRoomMemberRepository;
Expand Down Expand Up @@ -101,38 +101,38 @@ private boolean isAlreadyExistAccessCode(final AccessCodeGenerator accessCodeGen
@Transactional
public void updateNavigatorWithDriver(final String accessCode) {
final PairRoomEntity pairRoomEntity = pairRoomRepository.fetchByAccessCode(accessCode);
checkDeletePairRoom(pairRoomEntity);
checkPairRoomIsActive(pairRoomEntity);
pairRoomEntity.swapNavigatorWithDriver();
}

private void checkDeletePairRoom(final PairRoomEntity pairRoomEntity) {
if (pairRoomEntity.isDelete()) {
throw new DeletePairRoomException("삭제된 페어룸입니다.");
}
}

@Transactional
public void updatePairRoomStatus(final String accessCode, final String statusName) {
final PairRoomEntity pairRoomEntity = pairRoomRepository.fetchByAccessCode(accessCode);
checkDeletePairRoom(pairRoomEntity);
checkPairRoomIsActive(pairRoomEntity);
final PairRoomStatus status = PairRoomStatus.findByName(statusName);
pairRoomEntity.updateStatus(status);
}

public PairRoomReadResponse findPairRoomAndTimer(final String accessCode) {
final PairRoomEntity pairRoomEntity = pairRoomRepository.fetchByAccessCode(accessCode);
checkDeletePairRoom(pairRoomEntity);
checkPairRoomIsDeleted(pairRoomEntity);
final TimerEntity timerEntity = timerRepository.fetchTimerByPairRoomEntity(pairRoomEntity);
return PairRoomReadResponse.of(pairRoomEntity.toDomain(), timerEntity.toDomain());
}

private void checkPairRoomIsActive(final PairRoomEntity pairRoomEntity) {
if (!pairRoomEntity.isActive()) {
throw new InactivePairRoomException("종료되거나 삭제된 페어룸을 조작할 수 없습니다.");
}
}

public List<PairRoomMemberResponse> findPairRooms(final String token) {
final Member member = memberService.findMemberByCredential(token);

final List<PairRoomMemberEntity> pairRooms = pairRoomMemberRepository.findByMember(member);
final List<PairRoomEntity> pairRoomEntities = pairRooms.stream()
.map(PairRoomMemberEntity::getPairRoom)
.filter(pairRoomEntity -> !pairRoomEntity.isDelete())
.filter(pairRoomEntity -> !pairRoomEntity.isDeleted())
.toList();

return pairRoomEntities.stream()
Expand All @@ -143,10 +143,23 @@ public List<PairRoomMemberResponse> findPairRooms(final String token) {
@Transactional
public void deletePairRoom(final String accessCode) {
final PairRoomEntity pairRoomEntity = pairRoomRepository.fetchByAccessCode(accessCode);
checkDeletePairRoom(pairRoomEntity);
checkPairRoomIsDeleted(pairRoomEntity);
pairRoomEntity.updateStatus(PairRoomStatus.DELETED);
}

@Transactional
public void completePairRoom(final String accessCode) {
final PairRoomEntity pairRoomEntity = pairRoomRepository.fetchByAccessCode(accessCode);
checkPairRoomIsActive(pairRoomEntity);
pairRoomEntity.updateStatus(PairRoomStatus.COMPLETED);
}

private void checkPairRoomIsDeleted(final PairRoomEntity pairRoomEntity) {
if (pairRoomEntity.isDeleted()) {
throw new InactivePairRoomException("삭제된 페어룸을 삭제할 수 없습니다.");
}
}

public boolean existMemberInPairRoom(final String credentialToken, final String pairRoomAccessCode) {
final PairRoomEntity pairRoom = pairRoomRepository.fetchByAccessCode(pairRoomAccessCode);
final Member member = memberService.findMemberByCredential(credentialToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import lombok.RequiredArgsConstructor;
import site.coduo.pairroom.domain.accesscode.AccessCode;
import site.coduo.pairroom.exception.InactivePairRoomException;
import site.coduo.pairroom.repository.PairRoomEntity;
import site.coduo.pairroom.repository.PairRoomRepository;
import site.coduo.referencelink.domain.Category;
Expand Down Expand Up @@ -41,6 +42,7 @@ public List<CategoryReadResponse> findAllByPairRoomAccessCode(final String acces

public CategoryCreateResponse createCategory(final String accessCode, final CategoryCreateRequest request) {
final PairRoomEntity pairRoomEntity = pairRoomRepository.fetchByAccessCode(new AccessCode(accessCode));
checkPairRoomIsActive(pairRoomEntity);
validateDuplicated(request.value(), pairRoomEntity);
final CategoryEntity categoryEntity = categoryRepository.save(
new CategoryEntity(pairRoomEntity, new Category(request.value())));
Expand All @@ -56,6 +58,7 @@ private void validateDuplicated(final String categoryName, final PairRoomEntity

public CategoryUpdateResponse updateCategoryName(final String accessCode, final CategoryUpdateRequest request) {
final PairRoomEntity pairRoomEntity = pairRoomRepository.fetchByAccessCode(new AccessCode(accessCode));
checkPairRoomIsActive(pairRoomEntity);
validateDuplicated(request.updatedCategoryName(), pairRoomEntity);
final CategoryEntity category = categoryRepository.fetchByPairRoomAndCategoryId(pairRoomEntity,
request.categoryId());
Expand All @@ -65,11 +68,18 @@ public CategoryUpdateResponse updateCategoryName(final String accessCode, final

public void deleteCategory(final String accessCode, final Long categoryId) {
final PairRoomEntity pairRoomEntity = pairRoomRepository.fetchByAccessCode(new AccessCode(accessCode));
checkPairRoomIsActive(pairRoomEntity);
if (categoryRepository.existsByIdAndPairRoomEntity(categoryId, pairRoomEntity)) {
final List<ReferenceLinkEntity> referenceLinks = referenceLinkService.findReferenceLinksEntityByCategory(
accessCode, categoryId);
referenceLinks.forEach(ReferenceLinkEntity::updateCategoryToNull);
categoryRepository.deleteCategoryByPairRoomEntityAndId(pairRoomEntity, categoryId);
}
}

private void checkPairRoomIsActive(final PairRoomEntity pairRoomEntity) {
if (!pairRoomEntity.isActive()) {
throw new InactivePairRoomException("이미 종료되었거나 삭제된 페어룸의 카테고리를 조작할 수 없습니다.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import site.coduo.pairroom.domain.accesscode.AccessCode;
import site.coduo.pairroom.exception.InactivePairRoomException;
import site.coduo.pairroom.repository.PairRoomEntity;
import site.coduo.pairroom.repository.PairRoomRepository;
import site.coduo.referencelink.domain.Category;
Expand All @@ -34,10 +35,13 @@ public class ReferenceLinkService {
private final CategoryRepository categoryRepository;
private final OpenGraphService openGraphService;

public ReferenceLinkResponse createReferenceLink(final String accessCodeText,
final ReferenceLinkCreateRequest request) {
public ReferenceLinkResponse createReferenceLink(
final String accessCodeText,
final ReferenceLinkCreateRequest request
) {
final AccessCode accessCode = new AccessCode(accessCodeText);
final PairRoomEntity pairRoomEntity = pairRoomRepository.fetchByAccessCode(accessCode);
checkPairRoomIsActive(pairRoomEntity);
final URL url = makeUrl(request.url());
final ReferenceLink referenceLink = new ReferenceLink(url, accessCode);

Expand All @@ -54,9 +58,10 @@ private URL makeUrl(final String requestUrl) {
}
}

private ReferenceLinkEntity saveReferenceLink(final ReferenceLinkCreateRequest request,
final PairRoomEntity pairRoomEntity,
final ReferenceLink referenceLink
private ReferenceLinkEntity saveReferenceLink(
final ReferenceLinkCreateRequest request,
final PairRoomEntity pairRoomEntity,
final ReferenceLink referenceLink
) {
if (request.categoryId() == null) {
return referenceLinkRepository.save(new ReferenceLinkEntity(referenceLink, pairRoomEntity));
Expand Down Expand Up @@ -118,10 +123,18 @@ private ReferenceLinkResponse makeReferenceLinkResponse(final ReferenceLinkEntit
}

public void deleteReferenceLink(final String accessCodeText, final long id) {
final PairRoomEntity pairRoomEntity = pairRoomRepository.fetchByAccessCode(accessCodeText);
checkPairRoomIsActive(pairRoomEntity);
final ReferenceLinkEntity referenceLinkEntity = referenceLinkRepository.fetchById(id);
if (referenceLinkEntity.isSameAccessCode(new AccessCode(accessCodeText))) {
openGraphService.deleteByReferenceLink(referenceLinkEntity);
referenceLinkRepository.delete(referenceLinkEntity);
}
}

private void checkPairRoomIsActive(final PairRoomEntity pairRoomEntity) {
if (!pairRoomEntity.isActive()) {
throw new InactivePairRoomException("이미 종료되었거나 삭제된 페어룸의 링크를 조작할 수 없습니다.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,17 @@ public ResponseEntity<Void> createRetrospect(

@GetMapping("/retrospects")
public ResponseEntity<FindRetrospectsResponse> findRetrospects(
@CookieValue(SIGN_IN_COOKIE_NAME) final String credentialToken) {
@CookieValue(SIGN_IN_COOKIE_NAME) final String credentialToken
) {
final FindRetrospectsResponse response = retrospectService.findAllRetrospectsByMember(credentialToken);
return ResponseEntity.ok(response);
}

@GetMapping("/retrospects/{accessCode}")
public ResponseEntity<FindRetrospectByIdResponse> getRetrospect(
@CookieValue(SIGN_IN_COOKIE_NAME) final String credentialToken,
@PathVariable("accessCode") final String accessCode) {
@PathVariable("accessCode") final String accessCode
) {
final Retrospect retrospect = retrospectService.findRetrospectByAccessCode(credentialToken, accessCode);
final FindRetrospectByIdResponse response = FindRetrospectByIdResponse.from(retrospect);
return ResponseEntity.ok(response);
Expand Down
Loading