Skip to content

Commit f7ded66

Browse files
Merge branch 'dev' into feat/23
2 parents 9ed7545 + cf25ffa commit f7ded66

File tree

60 files changed

+1171
-29
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1171
-29
lines changed

.github/workflows/bump-version.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: release
2+
on:
3+
pull_request:
4+
types:
5+
- labeled
6+
7+
jobs:
8+
release:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
- uses: haya14busa/action-bumpr@v1

.github/workflows/release.yml

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,52 @@ on:
33
push:
44
branches:
55
- main
6-
pull_request:
7-
types:
8-
- labeled
6+
7+
env:
8+
REGISTRY: ghcr.io
9+
IMAGE_NAME: ${{ github.repository }}
910

1011
jobs:
1112
release:
1213
runs-on: ubuntu-latest
14+
outputs:
15+
next_version: ${{ steps.bump.outputs.next_version }}
1316
steps:
1417
- uses: actions/checkout@v4
1518
- uses: haya14busa/action-bumpr@v1
19+
id: bump
20+
21+
package:
22+
runs-on: ubuntu-latest
23+
needs: release
24+
25+
permissions:
26+
contents: read
27+
packages: write
28+
attestations: write
29+
id-token: write
30+
31+
steps:
32+
- uses: actions/checkout@v4
33+
34+
- uses: docker/login-action@v3
35+
with:
36+
registry: ${{ env.REGISTRY }}
37+
username: ${{ github.actor }}
38+
password: ${{ secrets.GITHUB_TOKEN }}
39+
40+
41+
- uses: docker/metadata-action@v5
42+
id: meta
43+
with:
44+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
45+
tags: |
46+
type=raw,value=latest
47+
type=raw,value=${{ needs.release.outputs.next_version }}
48+
49+
- uses: docker/build-push-action@v6
50+
with:
51+
context: ./backend
52+
push: true
53+
tags: ${{ steps.meta.outputs.tags }}
54+
labels: ${{ steps.meta.outputs.labels }}

.github/workflows/test.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ jobs:
99
contents: read
1010
env:
1111
PROJECT_DIR: backend
12+
KAKAO_CLIENT: ${{ secrets.KAKAO_CLIENT }}
13+
KAKAO_SECRET: ${{ secrets.KAKAO_SECRET }}
1214
steps:
1315
- uses: actions/checkout@v4
1416

backend/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,11 @@ out/
4242
### .idea ###
4343
.idea
4444

45+
### websocket test ###
46+
src/main/resources/static/ws-test.html
47+
src/main/resources/static/ws-test.js
48+
49+
50+
4551
### images/thumbnail ###
4652
images/thumbnail/**

backend/Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM gradle:jdk21 AS builder
2+
WORKDIR /app
3+
COPY . .
4+
RUN ./gradlew clean build -x test
5+
6+
FROM openjdk:21-slim
7+
WORKDIR /app
8+
COPY --from=builder /app/build/libs/*.jar app.jar
9+
ENTRYPOINT ["java", "-jar", "app.jar"]

backend/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ dependencies {
2929
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
3030
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
3131
implementation 'org.springframework.boot:spring-boot-starter-websocket'
32+
implementation 'org.springframework.boot:spring-boot-starter-security'
33+
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
3234

3335
/* DATABASE */
3436
runtimeOnly 'com.mysql:mysql-connector-j'
@@ -39,6 +41,7 @@ dependencies {
3941
testImplementation 'org.projectlombok:lombok'
4042
testAnnotationProcessor 'org.projectlombok:lombok'
4143
testRuntimeOnly 'com.h2database:h2'
44+
testImplementation 'org.springframework.security:spring-security-test'
4245

4346
/* ETC */
4447
annotationProcessor 'org.projectlombok:lombok'

backend/src/main/java/io/f1/backend/domain/game/api/RoomController.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.f1.backend.domain.game.app.RoomService;
44
import io.f1.backend.domain.game.dto.request.RoomCreateRequest;
5+
import io.f1.backend.domain.game.dto.request.RoomValidationRequest;
56
import io.f1.backend.domain.game.dto.response.RoomCreateResponse;
67
import io.f1.backend.domain.game.dto.response.RoomListResponse;
78

@@ -38,6 +39,12 @@ public RoomCreateResponse saveRoom(@RequestBody @Valid RoomCreateRequest request
3839
return roomService.saveRoom(request, loginUser);
3940
}
4041

42+
@PostMapping("/validation")
43+
@ResponseStatus(HttpStatus.NO_CONTENT)
44+
public void validateRoom(@RequestBody @Valid RoomValidationRequest request) {
45+
roomService.validateRoom(request);
46+
}
47+
4148
@GetMapping
4249
public RoomListResponse getAllRooms() {
4350
return roomService.getAllRooms();

backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,29 @@
22

33
import static io.f1.backend.domain.game.mapper.RoomMapper.*;
44

5+
import io.f1.backend.domain.game.dto.RoomInitialData;
56
import io.f1.backend.domain.game.dto.request.RoomCreateRequest;
7+
import io.f1.backend.domain.game.dto.request.RoomValidationRequest;
8+
import io.f1.backend.domain.game.dto.response.GameSettingResponse;
9+
import io.f1.backend.domain.game.dto.response.PlayerListResponse;
10+
import io.f1.backend.domain.game.dto.response.QuizResponse;
611
import io.f1.backend.domain.game.dto.response.RoomCreateResponse;
712
import io.f1.backend.domain.game.dto.response.RoomListResponse;
813
import io.f1.backend.domain.game.dto.response.RoomResponse;
14+
import io.f1.backend.domain.game.dto.response.RoomSettingResponse;
15+
import io.f1.backend.domain.game.event.RoomCreatedEvent;
916
import io.f1.backend.domain.game.model.GameSetting;
1017
import io.f1.backend.domain.game.model.Player;
1118
import io.f1.backend.domain.game.model.Room;
1219
import io.f1.backend.domain.game.model.RoomSetting;
20+
import io.f1.backend.domain.game.model.RoomState;
1321
import io.f1.backend.domain.game.store.RoomRepository;
22+
import io.f1.backend.domain.quiz.app.QuizService;
1423
import io.f1.backend.domain.quiz.entity.Quiz;
15-
import io.f1.backend.domain.user.entity.User;
1624

1725
import lombok.RequiredArgsConstructor;
1826

27+
import org.springframework.context.ApplicationEventPublisher;
1928
import org.springframework.stereotype.Service;
2029

2130
import java.util.List;
@@ -26,8 +35,10 @@
2635
@RequiredArgsConstructor
2736
public class RoomService {
2837

38+
private final QuizService quizService;
2939
private final RoomRepository roomRepository;
3040
private final AtomicLong roomIdGenerator = new AtomicLong(0);
41+
private final ApplicationEventPublisher eventPublisher;
3142

3243
public RoomCreateResponse saveRoom(RoomCreateRequest request, Map<String, Object> loginUser) {
3344

@@ -39,27 +50,78 @@ public RoomCreateResponse saveRoom(RoomCreateRequest request, Map<String, Object
3950

4051
Long newId = roomIdGenerator.incrementAndGet();
4152

42-
roomRepository.saveRoom(new Room(newId, roomSetting, gameSetting, host));
53+
Room room = new Room(newId, roomSetting, gameSetting, host);
54+
55+
roomRepository.saveRoom(room);
56+
57+
Long quizId = room.getGameSetting().getQuizId();
58+
Quiz quiz = quizService.getQuizById(quizId);
59+
60+
eventPublisher.publishEvent(new RoomCreatedEvent(room, quiz));
4361

4462
return new RoomCreateResponse(newId);
4563
}
4664

47-
// todo quizService에서 퀴즈 조회 메서드로 변경
65+
public void validateRoom(RoomValidationRequest request) {
66+
67+
Room room =
68+
roomRepository
69+
.findRoom(request.roomId())
70+
.orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다."));
71+
72+
if (room.getState().equals(RoomState.PLAYING)) {
73+
throw new IllegalArgumentException("403 게임이 진행중입니다.");
74+
}
75+
76+
int maxUserCnt = room.getRoomSetting().maxUserCount();
77+
int currentCnt = room.getPlayerSessionMap().size();
78+
if (maxUserCnt == currentCnt) {
79+
throw new IllegalArgumentException("403 정원이 모두 찼습니다.");
80+
}
81+
82+
if (room.getRoomSetting().locked()
83+
&& !room.getRoomSetting().password().equals(request.password())) {
84+
throw new IllegalArgumentException("401 비밀번호가 일치하지 않습니다.");
85+
}
86+
}
87+
88+
public RoomInitialData enterRoom(Long roomId, String sessionId) {
89+
90+
Room room =
91+
roomRepository
92+
.findRoom(roomId)
93+
.orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다."));
94+
95+
// todo security
96+
Player player = new Player(1L, "빵야빵야");
97+
98+
Map<String, Player> playerSessionMap = room.getPlayerSessionMap();
99+
100+
playerSessionMap.put(sessionId, player);
101+
102+
String destination = "/sub/room/" + roomId;
103+
104+
RoomSettingResponse roomSettingResponse = toRoomSettingResponse(room);
105+
// todo quiz 생성 api 완성 후 수정
106+
QuizResponse quiz =
107+
new QuizResponse(room.getGameSetting().getQuizId(), "title", "설명", "url", 10);
108+
GameSettingResponse gameSettingResponse =
109+
toGameSettingResponse(room.getGameSetting(), quiz);
110+
111+
PlayerListResponse playerListResponse = toPlayerListResponse(room);
112+
113+
return new RoomInitialData(
114+
destination, roomSettingResponse, gameSettingResponse, playerListResponse);
115+
}
116+
48117
public RoomListResponse getAllRooms() {
49118
List<Room> rooms = roomRepository.findAll();
50119
List<RoomResponse> roomResponses =
51120
rooms.stream()
52121
.map(
53122
room -> {
54-
User user = new User(); // 임시 유저 객체
55-
user.setNickname("임시 유저 닉네임");
56-
57-
Quiz quiz = new Quiz(); // 임시 퀴즈 객체
58-
quiz.setTitle("임시 퀴즈 제목");
59-
quiz.setDescription("임시 퀴즈 설명");
60-
quiz.setThumbnailUrl("임시 이미지");
61-
quiz.setQuestions(List.of());
62-
quiz.setCreator(user);
123+
Long quizId = room.getGameSetting().getQuizId();
124+
Quiz quiz = quizService.getQuizById(quizId);
63125

64126
return toRoomResponse(room, quiz);
65127
})
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package io.f1.backend.domain.game.dto;
2+
3+
public enum MessageType {
4+
ROOM_SETTING,
5+
GAME_SETTING,
6+
PLAYER_LIST,
7+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package io.f1.backend.domain.game.dto;
2+
3+
import io.f1.backend.domain.game.dto.response.GameSettingResponse;
4+
import io.f1.backend.domain.game.dto.response.PlayerListResponse;
5+
import io.f1.backend.domain.game.dto.response.RoomSettingResponse;
6+
7+
public record RoomInitialData(
8+
String destination,
9+
RoomSettingResponse roomSettingResponse,
10+
GameSettingResponse gameSettingResponse,
11+
PlayerListResponse playerListResponse) {}

0 commit comments

Comments
 (0)