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

모임 상태 및 찜, 참여 기능 추가 #171

Merged
merged 30 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d5b3ab4
refactor: JoinColumn 제거
pricelees Jul 31, 2024
5bb735d
feat: 현재 회원의 참여 여부 및 전체 참여자 조회 기능 구현
pricelees Jul 31, 2024
647b0bc
feat: 회원이 모임에 찜 했는지 여부를 확인하는 기능 구현
pricelees Jul 31, 2024
d588f7d
feat: 테스트에서 사용하는 DatabaseCleaner에 새로 추가된 테이블 반영
pricelees Jul 31, 2024
96c862c
Merge branch 'develop-backend' into feat/#150
pricelees Jul 31, 2024
320d2fe
style: 컨벤션 수정
pricelees Jul 31, 2024
d66de5e
refactor: 로그인 기능 사용을 위한 어노테이션 추가
pricelees Jul 31, 2024
5261fb7
refactor: Builder 생성자 추가
pricelees Jul 31, 2024
10706c3
style: 모든 참여자 조회 메서드 수정
pricelees Jul 31, 2024
308502d
refactor: FK 관련 오류 해결을 위한 쿼리 순서 수정
pricelees Jul 31, 2024
2111e00
test: 전체 참여자 및 참여 여부 조회 테스트 추가
pricelees Jul 31, 2024
6c7807c
test: 찜 여부 조회 테스트 추가
pricelees Jul 31, 2024
5b9aab9
Merge branch 'develop-backend' into feat/#150
pricelees Jul 31, 2024
c00be06
refactor: 테스트에서 새로 추가된 fixture를 사용하도록 수정
pricelees Jul 31, 2024
f77c825
feat: 모임 참여 기능 구현
pricelees Aug 1, 2024
4aaa5a2
feat: 모임 찜하기 / 찜 해제 기능 구현
pricelees Aug 1, 2024
3087ebb
refactor: 참여 / 찜 / 모임 상태 추가에 의한 기존 모임 생성, 삭제 기능 수정
pricelees Aug 1, 2024
dcc33be
feat: 모임 참여 기능에 대한 테스트 추가
pricelees Aug 1, 2024
473acba
feat: 모임 찜 기능에 대한 테스트 추가
pricelees Aug 1, 2024
32a8411
Merge branch 'develop-backend' into feat/#150
pricelees Aug 1, 2024
82b190d
Merge branch 'develop-backend' into feat/#150
pricelees Aug 1, 2024
43fac8d
refactor: 조회 로직에 readOnly 추가
pricelees Aug 1, 2024
d3d1794
Merge branch 'develop-backend' into feat/#150
pricelees Aug 1, 2024
339621e
Merge remote-tracking branch 'origin/feat/#150' into feat/#150
pricelees Aug 1, 2024
c21540b
Merge remote-tracking branch 'origin/feat/#150' into feat/#150
pricelees Aug 1, 2024
d6f7aab
Merge remote-tracking branch 'origin/feat/#150' into feat/#150
pricelees Aug 1, 2024
723427d
style: 테스트 메서드명 수정
pricelees Aug 1, 2024
76218b2
refactor: 도메인 nullable 추가
pricelees Aug 1, 2024
baf0b21
refactor: 분리된 메서드 제거
pricelees Aug 1, 2024
e0a6d69
chore: dto 패키지 세분화(request / response)
pricelees Aug 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package mouda.backend.auth.controller;

import lombok.RequiredArgsConstructor;
import mouda.backend.auth.dto.LoginRequest;
import mouda.backend.auth.dto.LoginResponse;
import mouda.backend.auth.dto.request.LoginRequest;
import mouda.backend.auth.dto.response.LoginResponse;
import mouda.backend.auth.service.AuthService;
import mouda.backend.common.RestResponse;
import org.springframework.http.ResponseEntity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import mouda.backend.auth.dto.LoginRequest;
import mouda.backend.auth.dto.LoginResponse;
import mouda.backend.auth.dto.request.LoginRequest;
import mouda.backend.auth.dto.response.LoginResponse;
import mouda.backend.common.RestResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package mouda.backend.auth.dto;
package mouda.backend.auth.dto.request;

public record LoginRequest(String nickname) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package mouda.backend.auth.dto;
package mouda.backend.auth.dto.response;

public record LoginResponse(String accessToken) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package mouda.backend.auth.service;

import mouda.backend.auth.dto.LoginRequest;
import mouda.backend.auth.dto.LoginResponse;
import mouda.backend.auth.dto.request.LoginRequest;
import mouda.backend.auth.dto.response.LoginResponse;
import mouda.backend.auth.exception.AuthErrorMessage;
import mouda.backend.auth.exception.AuthException;
import mouda.backend.member.domain.Member;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package mouda.backend.chamyo.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import mouda.backend.chamyo.dto.response.ChamyoFindAllResponses;
import mouda.backend.chamyo.dto.request.MoimChamyoRequest;
import mouda.backend.chamyo.dto.response.MoimRoleFindResponse;
import mouda.backend.chamyo.service.ChamyoService;
import mouda.backend.common.RestResponse;
import mouda.backend.config.argumentresolver.LoginMember;
import mouda.backend.member.domain.Member;

@RestController
@RequestMapping("/v1/chamyo")
@RequiredArgsConstructor
public class ChamyoController implements ChamyoSwagger {

private final ChamyoService chamyoService;

@Override
@GetMapping("/me")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 로그인한 사용자의 권한을 불러오는 거군요 .. ! /chamyo/me 보다는 chamyo/role 는 어떨까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 로그인한 사용자의 권한을 불러오는 거군요 .. ! /chamyo/me 보다는 chamyo/role 는 어떨까요?

프론트 처리를 위해 role을 반환하도록 했지만 사실상 참여 여부 조회에 사용되고 있습니다 ㅎㅎ 어찌됐든 Role에 미참여자도 포함된 만큼 상의 후 처리해볼게용!

public ResponseEntity<RestResponse<MoimRoleFindResponse>> findMoimRoleByMember(
@RequestParam Long moimId, @LoginMember Member member
) {
MoimRoleFindResponse moimRoleFindResponse = chamyoService.findMoimRole(moimId, member);

return ResponseEntity.ok().body(new RestResponse<>(moimRoleFindResponse));
}

@Override
@GetMapping("/all")
public ResponseEntity<RestResponse<ChamyoFindAllResponses>> findAllChamyoByMoim(@RequestParam Long moimId) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moimId가 없으면 안되니 NULL 체크가 필요하겠네요
@RequestParam은 NULL이 입력되었을 때 어떻게 처리되나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moimId가 없으면 안되니 NULL 체크가 필요하겠네요 @RequestParam은 NULL이 입력되었을 때 어떻게 처리되나요?

기본값이 required=true라서 없으면 MissingServletRequestParameterException 에러가 터지긴 합니다 ㅎㅎ

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호 😀 그럼 핸들링해서 400 에러를 보내는 과정도 필요하겠네요.

ChamyoFindAllResponses chamyoFindAllResponses = chamyoService.findAllChamyo(moimId);

return ResponseEntity.ok().body(new RestResponse<>(chamyoFindAllResponses));
}

@Override
@PostMapping
public ResponseEntity<Void> chamyoMoim(@Valid @RequestBody MoimChamyoRequest request, @LoginMember Member member) {
chamyoService.chamyoMoim(request, member);

return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package mouda.backend.chamyo.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
import mouda.backend.chamyo.dto.response.ChamyoFindAllResponses;
import mouda.backend.chamyo.dto.request.MoimChamyoRequest;
import mouda.backend.chamyo.dto.response.MoimRoleFindResponse;
import mouda.backend.common.RestResponse;
import mouda.backend.config.argumentresolver.LoginMember;
import mouda.backend.member.domain.Member;

public interface ChamyoSwagger {

@Operation(summary = "모임 참여 여부 조회", description = "현재 로그인된 회원의 모임 참여 여부를 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "모임 참여 여부 조회 성공")
})
ResponseEntity<RestResponse<MoimRoleFindResponse>> findMoimRoleByMember(@RequestParam Long moimId,
@LoginMember Member member);

@Operation(summary = "모든 모임 참여자 조회", description = "모임에 참여한 모든 회원을 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "모든 모임 참여자 조회 성공")
})
ResponseEntity<RestResponse<ChamyoFindAllResponses>> findAllChamyoByMoim(@RequestParam Long moimId);

@Operation(summary = "모임 참여", description = "모임에 참여합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "모임 참여 성공")
})
ResponseEntity<Void> chamyoMoim(@Valid @RequestBody MoimChamyoRequest request, @LoginMember Member member);
}
14 changes: 12 additions & 2 deletions backend/src/main/java/mouda/backend/chamyo/domain/Chamyo.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package mouda.backend.chamyo.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
Expand All @@ -8,6 +9,7 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import mouda.backend.member.domain.Member;
Expand All @@ -23,13 +25,21 @@ public class Chamyo {
private Long id;

@ManyToOne
@JoinColumn(name = "moim_id")
@JoinColumn(nullable = false)
private Moim moim;

@ManyToOne
@JoinColumn(name = "member_id")
@JoinColumn(nullable = false)
private Member member;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private MoimRole moimRole;

@Builder
public Chamyo(Moim moim, Member member, MoimRole moimRole) {
this.moim = moim;
this.member = member;
this.moimRole = moimRole;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

@Getter
public enum MoimRole {
DEFAULT
MOIMER, MOIMEE, NON_MOIMEE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package mouda.backend.chamyo.dto.request;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;

public record MoimChamyoRequest(
@NotNull @Positive
Long moimId
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package mouda.backend.chamyo.dto.response;

import lombok.Builder;
import mouda.backend.chamyo.domain.Chamyo;

@Builder
public record ChamyoFindAllResponse(
String nickname,
String profile,
String role
) {

public static ChamyoFindAllResponse toResponse(Chamyo chamyo) {
return ChamyoFindAllResponse.builder()
.nickname(chamyo.getMember().getNickname())
.profile("")
.role(chamyo.getMoimRole().name())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package mouda.backend.chamyo.dto.response;

import java.util.List;

public record ChamyoFindAllResponses(
List<ChamyoFindAllResponse> chamyos
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package mouda.backend.chamyo.dto.response;

public record MoimRoleFindResponse(
String role
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package mouda.backend.chamyo.exception;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum ChamyoErrorMessage {

MOIM_NOT_FOUND("참여하려는 모임이 존재하지 않습니다."),
MOIM_ALREADY_JOINED("이미 참여한 모임입니다."),
MOIM_FULL("최대 인원 수를 초과했습니다."),
MOIMING_CANCLED("취소된 모임입니다."),
MOIMING_COMPLETE("모집이 완료된 모임입니다.");
Comment on lines +10 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MOIM이라는 접두사랑 MOIMING이라는 접두사는 무슨 차이가 있는 지 궁금합니다 😀

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MOIM이라는 접두사랑 MOIMING이라는 접두사는 무슨 차이가 있는 지 궁금합니다 😀

MOIM은 모임 그 자체를, MOIMING은 모집 중이라는 행위를 표현하려는 의도였어요 ㅎㅎ
MOIM_COMPLETE라고 하면 이게 모임 자체가 끝난건지, 사람을 더 안받는건지 애매하니깐요!


private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package mouda.backend.chamyo.exception;

import org.springframework.http.HttpStatus;

import mouda.backend.exception.MoudaException;

public class ChamyoException extends MoudaException {

public ChamyoException(HttpStatus httpStatus, ChamyoErrorMessage chamyoErrorMessage) {
super(httpStatus, chamyoErrorMessage.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package mouda.backend.chamyo.repository;

import java.util.List;
import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;

import mouda.backend.chamyo.domain.Chamyo;
import mouda.backend.member.domain.Member;
import mouda.backend.moim.domain.Moim;

public interface ChamyoRepository extends JpaRepository<Chamyo, Long> {

Optional<Chamyo> findByMoimIdAndMemberId(Long moimId, Long id);

List<Chamyo> findAllByMoimId(Long moimId);

int countByMoim(Moim moim);

boolean existsByMoimAndMember(Moim moim, Member member);

void deleteAllByMoimId(Long moimId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package mouda.backend.chamyo.service;

import java.util.List;
import java.util.Optional;

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import lombok.RequiredArgsConstructor;
import mouda.backend.chamyo.domain.Chamyo;
import mouda.backend.chamyo.domain.MoimRole;
import mouda.backend.chamyo.dto.response.ChamyoFindAllResponse;
import mouda.backend.chamyo.dto.response.ChamyoFindAllResponses;
import mouda.backend.chamyo.dto.request.MoimChamyoRequest;
import mouda.backend.chamyo.dto.response.MoimRoleFindResponse;
import mouda.backend.chamyo.exception.ChamyoErrorMessage;
import mouda.backend.chamyo.exception.ChamyoException;
import mouda.backend.chamyo.repository.ChamyoRepository;
import mouda.backend.member.domain.Member;
import mouda.backend.moim.domain.Moim;
import mouda.backend.moim.domain.MoimStatus;
import mouda.backend.moim.repository.MoimRepository;

@Service
@RequiredArgsConstructor
@Transactional
public class ChamyoService {

private final ChamyoRepository chamyoRepository;
private final MoimRepository moimRepository;

@Transactional(readOnly = true)
public MoimRoleFindResponse findMoimRole(Long moimId, Member member) {
Optional<Chamyo> chamyoOptional = chamyoRepository.findByMoimIdAndMemberId(moimId, member.getId());

MoimRole moimRole = chamyoOptional.map(Chamyo::getMoimRole).orElse(MoimRole.NON_MOIMEE);

return new MoimRoleFindResponse(moimRole.name());
}

@Transactional(readOnly = true)
public ChamyoFindAllResponses findAllChamyo(Long moimId) {
List<ChamyoFindAllResponse> responses = chamyoRepository.findAllByMoimId(moimId).stream()
.map(ChamyoFindAllResponse::toResponse)
.toList();

return new ChamyoFindAllResponses(responses);
}

public void chamyoMoim(MoimChamyoRequest request, Member member) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주석은 혹시 일부러 하신 건가요 ? 아니면 실수로 남겨놓은 건가요? 😃

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주석은 혹시 일부러 하신 건가요 ? 아니면 실수로 남겨놓은 건가요? 😃

ㅋㅋㅋㅋ 수정할게요..ㅋㅋㅋㅋㅋㅋ 어제 마지막 부분만 못하고 갔거든요

Moim moim = moimRepository.findById(request.moimId())
.orElseThrow(() -> new ChamyoException(HttpStatus.NOT_FOUND, ChamyoErrorMessage.MOIM_NOT_FOUND));
validateCanChamyoMoim(moim, member);

Chamyo chamyo = Chamyo.builder()
.moim(moim)
.member(member)
.moimRole(MoimRole.MOIMEE)
.build();
chamyoRepository.save(chamyo);

int currentPeople = chamyoRepository.countByMoim(moim);
if (currentPeople >= moim.getMaxPeople()) {
moimRepository.updateMoimStatusById(moim.getId(), MoimStatus.COMPLETED);
}
}

private void validateCanChamyoMoim(Moim moim, Member member) {
int currentPeople = chamyoRepository.countByMoim(moim);
if (currentPeople >= moim.getMaxPeople()) {
throw new ChamyoException(HttpStatus.BAD_REQUEST, ChamyoErrorMessage.MOIM_FULL);
}
if (moim.getMoimStatus() == MoimStatus.CANCELED) {
throw new ChamyoException(HttpStatus.BAD_REQUEST, ChamyoErrorMessage.MOIMING_CANCLED);
}
if (moim.getMoimStatus() == MoimStatus.COMPLETED) {
throw new ChamyoException(HttpStatus.BAD_REQUEST, ChamyoErrorMessage.MOIMING_COMPLETE);
}
if (chamyoRepository.existsByMoimAndMember(moim, member)) {
throw new ChamyoException(HttpStatus.BAD_REQUEST, ChamyoErrorMessage.MOIM_ALREADY_JOINED);
}
}
}
Loading