Skip to content

Commit 636ecc6

Browse files
authored
✨ feat: 이미지 퀴즈 추가 (#186)
1 parent fd03e9a commit 636ecc6

Some content is hidden

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

42 files changed

+797
-316
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ public void gameStart(Long roomId, UserPrincipal principal) {
9090
timerService.startTimer(room, START_DELAY);
9191

9292
messageSender.sendBroadcast(
93-
destination, MessageType.GAME_START, toGameStartResponse(questions));
93+
destination,
94+
MessageType.GAME_START,
95+
toGameStartResponse(quiz.getQuizType(), questions));
9496
messageSender.sendBroadcast(
9597
destination, MessageType.RANK_UPDATE, toRankUpdateResponse(room));
9698
messageSender.sendBroadcast(

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ public void reconnectSendResponse(Long roomId, UserPrincipal principal) {
310310
String destination = getDestination(roomId);
311311
String userDestination = getUserDestination();
312312

313+
Long quizId = room.getQuizId();
314+
Quiz quiz = quizService.findQuizById(quizId);
315+
313316
messageSender.sendBroadcast(
314317
destination,
315318
MessageType.SYSTEM_NOTICE,
@@ -330,14 +333,11 @@ public void reconnectSendResponse(Long roomId, UserPrincipal principal) {
330333
messageSender.sendPersonal(
331334
userDestination,
332335
MessageType.GAME_START,
333-
toGameStartResponse(room.getQuestions()),
336+
toGameStartResponse(quiz.getQuizType(), room.getQuestions()),
334337
principal.getName());
335338
} else {
336339
RoomSettingResponse roomSettingResponse = toRoomSettingResponse(room);
337340

338-
Long quizId = room.getGameSetting().getQuizId();
339-
340-
Quiz quiz = quizService.findQuizById(quizId);
341341
Long questionsCount = quizService.getQuestionsCount(quizId);
342342

343343
GameSettingResponse gameSettingResponse =
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package io.f1.backend.domain.game.dto.response;
22

33
import io.f1.backend.domain.quiz.dto.GameQuestionResponse;
4+
import io.f1.backend.domain.quiz.entity.QuizType;
45

56
import java.util.List;
67

7-
public record GameStartResponse(List<GameQuestionResponse> questions) {}
8+
public record GameStartResponse(QuizType quizType, List<GameQuestionResponse> questions) {}
Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,11 @@
11
package io.f1.backend.domain.question.api;
22

3-
import io.f1.backend.domain.question.app.QuestionService;
4-
53
import lombok.RequiredArgsConstructor;
64

7-
import org.springframework.http.ResponseEntity;
8-
import org.springframework.web.bind.annotation.DeleteMapping;
9-
import org.springframework.web.bind.annotation.PathVariable;
105
import org.springframework.web.bind.annotation.RequestMapping;
116
import org.springframework.web.bind.annotation.RestController;
127

138
@RestController
149
@RequestMapping("/questions")
1510
@RequiredArgsConstructor
16-
public class QuestionController {
17-
18-
private final QuestionService questionService;
19-
20-
@DeleteMapping("/{questionId}")
21-
public ResponseEntity<Void> deleteQuestion(@PathVariable Long questionId) {
22-
questionService.deleteQuestion(questionId);
23-
24-
return ResponseEntity.noContent().build();
25-
}
26-
}
11+
public class QuestionController {}
Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,79 @@
11
package io.f1.backend.domain.question.app;
22

3-
import static io.f1.backend.domain.question.mapper.QuestionMapper.questionRequestToQuestion;
4-
import static io.f1.backend.domain.question.mapper.TextQuestionMapper.questionRequestToTextQuestion;
5-
import static io.f1.backend.domain.quiz.app.QuizService.verifyUserAuthority;
6-
3+
import io.f1.backend.domain.question.dao.ContentQuestionRepository;
74
import io.f1.backend.domain.question.dao.QuestionRepository;
8-
import io.f1.backend.domain.question.dao.TextQuestionRepository;
9-
import io.f1.backend.domain.question.dto.QuestionRequest;
10-
import io.f1.backend.domain.question.dto.QuestionUpdateRequest;
5+
import io.f1.backend.domain.question.dto.ContentQuestionRequest;
6+
import io.f1.backend.domain.question.dto.ContentQuestionUpdateRequest;
7+
import io.f1.backend.domain.question.entity.ContentQuestion;
118
import io.f1.backend.domain.question.entity.Question;
12-
import io.f1.backend.domain.question.entity.TextQuestion;
139
import io.f1.backend.domain.quiz.entity.Quiz;
10+
import io.f1.backend.domain.quiz.entity.QuizType;
1411
import io.f1.backend.global.exception.CustomException;
1512
import io.f1.backend.global.exception.errorcode.QuestionErrorCode;
13+
import io.f1.backend.global.util.FileManager;
1614

1715
import lombok.RequiredArgsConstructor;
1816

1917
import org.springframework.stereotype.Service;
20-
import org.springframework.transaction.annotation.Transactional;
2118

2219
@Service
2320
@RequiredArgsConstructor
2421
public class QuestionService {
2522

2623
private final QuestionRepository questionRepository;
27-
private final TextQuestionRepository textQuestionRepository;
28-
29-
@Transactional
30-
public void saveQuestion(Quiz quiz, QuestionRequest request) {
24+
private final ContentQuestionRepository contentQuestionRepository;
3125

32-
Question question = questionRequestToQuestion(quiz, request);
26+
public void saveContentQuestion(Quiz quiz, ContentQuestionRequest request) {
27+
Question question = new Question(quiz, request.getAnswer());
3328
quiz.addQuestion(question);
3429
questionRepository.save(question);
3530

36-
TextQuestion textQuestion = questionRequestToTextQuestion(question, request.getContent());
37-
textQuestionRepository.save(textQuestion);
38-
question.addTextQuestion(textQuestion);
31+
ContentQuestion contentQuestion = request.toContentQuestion(question);
32+
contentQuestionRepository.save(contentQuestion);
33+
question.addContentQuestion(contentQuestion);
3934
}
4035

41-
public void updateQuestions(Quiz quiz, QuestionUpdateRequest request) {
42-
36+
public void updateContentQuestions(Quiz quiz, ContentQuestionUpdateRequest request) {
4337
if (request.getId() == null) {
44-
saveQuestion(quiz, QuestionRequest.of(request));
38+
saveContentQuestion(
39+
quiz, ContentQuestionRequest.of(request.getContent(), request.getAnswer()));
40+
4541
return;
4642
}
4743

48-
Question question =
49-
questionRepository
50-
.findById(request.getId())
51-
.orElseThrow(
52-
() -> new CustomException(QuestionErrorCode.QUESTION_NOT_FOUND));
44+
Question question = getQuestionWithContent(request.getId());
45+
46+
if (request.getContent() != null) {
47+
ContentQuestion contentQuestion = question.getContentQuestion();
48+
contentQuestion.changeContent(request.getContent());
49+
}
5350

54-
TextQuestion textQuestion = question.getTextQuestion();
55-
textQuestion.changeContent(request.getContent());
5651
question.changeAnswer(request.getAnswer());
5752
}
5853

59-
@Transactional
60-
public void deleteQuestion(Long questionId) {
54+
public void deleteQuestion(Long questionId, QuizType quizType) {
55+
Question question;
6156

62-
Question question =
63-
questionRepository
64-
.findById(questionId)
65-
.orElseThrow(
66-
() -> new CustomException(QuestionErrorCode.QUESTION_NOT_FOUND));
67-
68-
verifyUserAuthority(question.getQuiz());
57+
if (quizType.name().equals("IMAGE")) {
58+
question = getQuestionWithContent(questionId);
59+
String filePath = question.getContentQuestion().getContent();
60+
FileManager.deleteFile(filePath);
61+
} else {
62+
question = getQuestion(questionId);
63+
}
6964

7065
questionRepository.delete(question);
7166
}
67+
68+
private Question getQuestion(Long questionId) {
69+
return questionRepository
70+
.findById(questionId)
71+
.orElseThrow(() -> new CustomException(QuestionErrorCode.QUESTION_NOT_FOUND));
72+
}
73+
74+
private Question getQuestionWithContent(Long questionId) {
75+
return questionRepository
76+
.findByIdWithContent(questionId)
77+
.orElseThrow(() -> new CustomException(QuestionErrorCode.QUESTION_NOT_FOUND));
78+
}
7279
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package io.f1.backend.domain.question.dao;
2+
3+
import io.f1.backend.domain.question.entity.ContentQuestion;
4+
5+
import org.springframework.data.jpa.repository.JpaRepository;
6+
7+
public interface ContentQuestionRepository extends JpaRepository<ContentQuestion, Long> {}

backend/src/main/java/io/f1/backend/domain/question/dao/QuestionRepository.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,12 @@
33
import io.f1.backend.domain.question.entity.Question;
44

55
import org.springframework.data.jpa.repository.JpaRepository;
6+
import org.springframework.data.jpa.repository.Query;
67

7-
public interface QuestionRepository extends JpaRepository<Question, Long> {}
8+
import java.util.Optional;
9+
10+
public interface QuestionRepository extends JpaRepository<Question, Long> {
11+
12+
@Query("SELECT q FROM Question q JOIN FETCH q.contentQuestion WHERE q.id = :id")
13+
Optional<Question> findByIdWithContent(Long id);
14+
}

backend/src/main/java/io/f1/backend/domain/question/dao/TextQuestionRepository.java

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.f1.backend.domain.question.dto;
2+
3+
import io.f1.backend.domain.question.entity.ContentQuestion;
4+
import io.f1.backend.domain.question.entity.Question;
5+
import io.f1.backend.domain.quiz.entity.Quiz;
6+
7+
import lombok.AccessLevel;
8+
import lombok.AllArgsConstructor;
9+
import lombok.Getter;
10+
11+
@Getter
12+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
13+
public class ContentQuestionRequest {
14+
private String content;
15+
private String answer;
16+
17+
public static ContentQuestionRequest of(String content, String answer) {
18+
return new ContentQuestionRequest(content, answer);
19+
}
20+
21+
public ContentQuestion toContentQuestion(Question question) {
22+
return new ContentQuestion(question, content);
23+
}
24+
25+
public Question toQuestion(Quiz quiz) {
26+
return new Question(quiz, answer);
27+
}
28+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.f1.backend.domain.question.dto;
2+
3+
import lombok.AccessLevel;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Getter;
6+
7+
@Getter
8+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
9+
public class ContentQuestionUpdateRequest {
10+
private Long id;
11+
private String content;
12+
private String answer;
13+
14+
public static ContentQuestionUpdateRequest of(Long id, String content, String answer) {
15+
return new ContentQuestionUpdateRequest(id, content, answer);
16+
}
17+
}

0 commit comments

Comments
 (0)