Skip to content

Commit

Permalink
[BE] feat: 모집 중인 방 리스트 API 구현(#30) (#68)
Browse files Browse the repository at this point in the history
* feat: Room Entity가 필요한 정보 추가

* feat: 초기 데이터 구현

* feat: 사이트에 접속한 유저를 파악하기 위한 ArgumentResolver 구현

* feat: 모집중인 방 리스트를 조회하는 기능 구현

* refactor: 페이지 사이즈 수정

* test: 테스트 필드에 private 접근 제어자 추가
  • Loading branch information
gyungchan-jo authored Jul 19, 2024
1 parent ebfd426 commit 4040333
Show file tree
Hide file tree
Showing 18 changed files with 470 additions and 63 deletions.
125 changes: 125 additions & 0 deletions backend/src/main/java/corea/DataInitializer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package corea;

import corea.matching.domain.Participation;
import corea.matching.repository.ParticipationRepository;
import corea.member.domain.Member;
import corea.member.repository.MemberRepository;
import corea.room.domain.Classification;
import corea.room.domain.Room;
import corea.room.domain.RoomStatus;
import corea.room.repository.RoomRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@Profile("test")
@Component
@Transactional
@RequiredArgsConstructor
public class DataInitializer implements ApplicationRunner {

private final MemberRepository memberRepository;
private final RoomRepository roomRepository;
private final ParticipationRepository participationRepository;

@Override
public void run(ApplicationArguments args) {
Member member1 = memberRepository.save(
new Member("jcoding-play", null, "조경찬",
"[email protected]", true, 5f));
Member member2 = memberRepository.save(
new Member("ashsty", null, "박민아",
null, false, 1.5f));
Member member3 = memberRepository.save(
new Member("youngsu5582", null, "이영수",
null, false, 4f));
Member member4 = memberRepository.save(
new Member("hjk0761", null, "김현중",
null, true, 3f));
Member member5 = memberRepository.save(
new Member("chlwlstlf", null, "최진실",
null, true, 2f));
Member member6 = memberRepository.save(
new Member("00kang", null, "강다빈",
null, true, 1f));
Member member7 = memberRepository.save(
new Member("pp449", null, "이상엽",
"[email protected]", true, 4.8f));

Room room1 = roomRepository.save(
new Room("방 제목 1", "방 설명 1", 3,
null, null, "TDD",
1, 20, member1,
LocalDateTime.of(2024, 12, 25, 12, 0),
LocalDateTime.of(2024, 12, 30, 12, 0),
Classification.BACKEND, RoomStatus.OPENED));
Room room2 = roomRepository.save(
new Room("방 제목 2", "방 설명 2", 3,
null, null, "TDD",
1, 20, member2,
LocalDateTime.of(2024, 12, 25, 12, 0),
LocalDateTime.of(2024, 12, 30, 12, 0),
Classification.BACKEND, RoomStatus.OPENED));
Room room3 = roomRepository.save(
new Room("방 제목 3", "방 설명 3", 3,
null, null, "TDD",
1, 20, member3,
LocalDateTime.of(2024, 12, 25, 12, 0),
LocalDateTime.of(2024, 12, 30, 12, 0),
Classification.ANDROID, RoomStatus.OPENED));
Room room4 = roomRepository.save(
new Room("방 제목 4", "방 설명 4", 3,
null, null, "TDD",
1, 20, member4,
LocalDateTime.of(2024, 12, 25, 12, 0),
LocalDateTime.of(2024, 12, 30, 12, 0),
Classification.ANDROID, RoomStatus.OPENED));
Room room5 = roomRepository.save(
new Room("방 제목 5", "방 설명 5", 3,
null, null, "TDD",
1, 20, member5,
LocalDateTime.of(2024, 12, 25, 12, 0),
LocalDateTime.of(2024, 12, 30, 12, 0),
Classification.FRONTEND, RoomStatus.OPENED));
Room room6 = roomRepository.save(
new Room("방 제목 6", "방 설명 6", 3,
null, null, "TDD",
1, 20, member6,
LocalDateTime.of(2024, 12, 25, 12, 0),
LocalDateTime.of(2024, 12, 30, 12, 0),
Classification.FRONTEND, RoomStatus.OPENED));
Room room7 = roomRepository.save(
new Room("방 제목 7", "방 설명 7", 3,
null, null, "TDD",
1, 20, member7,
LocalDateTime.of(2024, 12, 25, 12, 0),
LocalDateTime.of(2024, 12, 30, 12, 0),
Classification.FRONTEND, RoomStatus.OPENED));

participationRepository.save(new Participation(room1.getId(), member2.getId()));
participationRepository.save(new Participation(room1.getId(), member3.getId()));

participationRepository.save(new Participation(room2.getId(), member3.getId()));
participationRepository.save(new Participation(room2.getId(), member4.getId()));

participationRepository.save(new Participation(room3.getId(), member4.getId()));
participationRepository.save(new Participation(room3.getId(), member5.getId()));

participationRepository.save(new Participation(room4.getId(), member5.getId()));
participationRepository.save(new Participation(room4.getId(), member6.getId()));

participationRepository.save(new Participation(room5.getId(), member6.getId()));
participationRepository.save(new Participation(room5.getId(), member7.getId()));

participationRepository.save(new Participation(room6.getId(), member1.getId()));
participationRepository.save(new Participation(room6.getId(), member7.getId()));

participationRepository.save(new Participation(room7.getId(), member1.getId()));
participationRepository.save(new Participation(room7.getId(), member2.getId()));
}
}
3 changes: 3 additions & 0 deletions backend/src/main/java/corea/WebConfig.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package corea;

import corea.auth.resolver.AccessedMemberArgumentResolver;
import corea.auth.resolver.LoginMemberArgumentResolver;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
Expand All @@ -14,6 +15,7 @@
public class WebConfig implements WebMvcConfigurer {

private final LoginMemberArgumentResolver loginMemberArgumentResolver;
private final AccessedMemberArgumentResolver accessedMemberArgumentResolver;

@Override
public void addCorsMappings(CorsRegistry registry) {
Expand All @@ -27,5 +29,6 @@ public void addCorsMappings(CorsRegistry registry) {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(loginMemberArgumentResolver);
resolvers.add(accessedMemberArgumentResolver);
}
}
14 changes: 14 additions & 0 deletions backend/src/main/java/corea/auth/annotation/AccessedMember.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package corea.auth.annotation;

import io.swagger.v3.oas.annotations.Hidden;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Hidden()
public @interface AccessedMember {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package corea.auth.resolver;

import corea.auth.RequestHandler;
import corea.auth.annotation.AccessedMember;
import corea.member.domain.Member;
import corea.member.repository.MemberRepository;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

@Component
@RequiredArgsConstructor
public class AccessedMemberArgumentResolver implements HandlerMethodArgumentResolver {

private final RequestHandler requestHandler;
private final MemberRepository memberRepository;

@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(AccessedMember.class);
}

@Override
public Member resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();

return memberRepository.findByEmail(requestHandler.extract(request))
.orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@ public boolean supportsParameter(MethodParameter parameter) {
}

@Override
public AuthInfo resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {
public AuthInfo resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
Member member = memberRepository.findByEmail(requestHandler.extract(request))
.orElseThrow(()-> new CoreaException(ExceptionType.AUTHORIZATION_ERROR));

return AuthInfo.from(member);
}
}
19 changes: 15 additions & 4 deletions backend/src/main/java/corea/room/controller/RoomController.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package corea.room.controller;

import corea.auth.annotation.AccessedMember;
import corea.auth.annotation.LoginMember;
import corea.auth.domain.AuthInfo;
import corea.member.domain.Member;
import corea.room.dto.RoomResponse;
import corea.room.dto.RoomResponses;
import corea.room.service.RoomService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/rooms")
Expand All @@ -36,4 +35,16 @@ public ResponseEntity<RoomResponses> participatedRooms(@LoginMember AuthInfo aut
RoomResponses response = roomService.findParticipatedRooms(authInfo.getId());
return ResponseEntity.ok(response);
}

@GetMapping("/opened")
public ResponseEntity<RoomResponses> openedRooms(@AccessedMember Member member,
@RequestParam(value = "classification", defaultValue = "all") String expression,
@RequestParam(defaultValue = "0") int page) {
if (member == null) {
RoomResponses response = roomService.findOpenedRoomsWithoutMember(expression, page);
return ResponseEntity.ok(response);
}
RoomResponses response = roomService.findOpenedRoomsWithMember(member.getId(), expression, page);
return ResponseEntity.ok(response);
}
}
38 changes: 38 additions & 0 deletions backend/src/main/java/corea/room/domain/Classification.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package corea.room.domain;

import corea.exception.CoreaException;
import corea.exception.ExceptionType;

import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;

import static java.util.stream.Collectors.toMap;

public enum Classification {

ALL("all"),
ANDROID("an"),
BACKEND("be"),
FRONTEND("fe");

private static final Map<String, Classification> CACHED_CLASSIFICATIONS = Arrays.stream(values())
.collect(toMap(classification -> classification.expression, Function.identity()));

private final String expression;

Classification(String expression) {
this.expression = expression;
}

public static Classification from(String expression) {
if (CACHED_CLASSIFICATIONS.containsKey(expression)) {
return CACHED_CLASSIFICATIONS.get(expression);
}
throw new CoreaException(ExceptionType.NOT_FOUND_ERROR);
}

public boolean isAll() {
return this == ALL;
}
}
20 changes: 17 additions & 3 deletions backend/src/main/java/corea/room/domain/Room.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,29 @@ public class Room {
private int limitedParticipantsSize;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "manager_id",foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
@JoinColumn(name = "manager_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private Member manager;

private LocalDateTime recruitmentDeadline;

private LocalDateTime reviewDeadline;

public Room(String title, String content, int matchingSize, String repositoryLink, String thumbnailLink, String keyword, int currentParticipantsSize, int limitedParticipantsSize, Member manager, LocalDateTime recruitmentDeadline, LocalDateTime reviewDeadline) {
this(null, title, content, matchingSize, repositoryLink, thumbnailLink, keyword, currentParticipantsSize, limitedParticipantsSize, manager, recruitmentDeadline, reviewDeadline);
@Enumerated(value = EnumType.STRING)
private Classification classification;

/**
* RoomStatus가 변경될 수 있는 경우 (OPENED -> CLOSED)
* 1. 방장이 모집 마감을 한 경우
* 2. 제한 인원이 다 찼을 경우 (방에 참여할 때 같이 검증)
* 3. 모집 기간이 끝난 경우
*
* 1, 2의 경우 때문에 방 상태를 가지는 필드를 가져야 될듯.
* **/
@Enumerated(value = EnumType.STRING)
private RoomStatus status;

public Room(String title, String content, int matchingSize, String repositoryLink, String thumbnailLink, String keyword, int currentParticipantsSize, int limitedParticipantsSize, Member manager, LocalDateTime recruitmentDeadline, LocalDateTime reviewDeadline, Classification classification, RoomStatus status) {
this(null, title, content, matchingSize, repositoryLink, thumbnailLink, keyword, currentParticipantsSize, limitedParticipantsSize, manager, recruitmentDeadline, reviewDeadline, classification, status);
}
}

6 changes: 6 additions & 0 deletions backend/src/main/java/corea/room/domain/RoomStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package corea.room.domain;

public enum RoomStatus {

OPENED, CLOSED
}
9 changes: 7 additions & 2 deletions backend/src/main/java/corea/room/dto/RoomCreateRequest.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package corea.room.dto;

import corea.member.domain.Member;
import corea.room.domain.Classification;
import corea.room.domain.Room;
import corea.room.domain.RoomStatus;

import java.time.LocalDateTime;

Expand All @@ -16,13 +18,16 @@ public record RoomCreateRequest(
int currentParticipantsSize,
int limitedParticipantsSize,
LocalDateTime recruitmentDeadline,
LocalDateTime reviewDeadline
LocalDateTime reviewDeadline,
Classification classification,
RoomStatus status
) {

public Room toEntity() {
return new Room(title, content, matchingSize,
repositoryLink, thumbnailLink, keyword,
currentParticipantsSize, limitedParticipantsSize, manager,
recruitmentDeadline, reviewDeadline);
recruitmentDeadline, reviewDeadline, classification,
status);
}
}
5 changes: 5 additions & 0 deletions backend/src/main/java/corea/room/dto/RoomResponses.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package corea.room.dto;

import corea.room.domain.Room;
import org.springframework.data.domain.Page;

import java.util.List;

Expand All @@ -14,4 +15,8 @@ public static RoomResponses from(List<Room> rooms) {
.map(RoomResponse::from)
.collect(collectingAndThen(toList(), RoomResponses::new));
}

public static RoomResponses from(Page<Room> roomsWithPage) {
return from(roomsWithPage.getContent());
}
}
Loading

0 comments on commit 4040333

Please sign in to comment.