Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Expand Up @@ -96,6 +96,7 @@ public void gameStart(Long roomId, UserPrincipal principal) {
public void onCorrectAnswer(GameCorrectAnswerEvent event) {

Room room = event.room();
log.debug(room.getId() + "번 방 채팅으로 정답! 현재 라운드 : " + room.getCurrentRound());
String sessionId = event.sessionId();
ChatMessage chatMessage = event.chatMessage();
String answer = event.answer();
Expand Down Expand Up @@ -135,6 +136,8 @@ public void onCorrectAnswer(GameCorrectAnswerEvent event) {
@EventListener
public void onTimeout(GameTimeoutEvent event) {
Room room = event.room();
log.debug(room.getId() + "번 방 타임아웃! 현재 라운드 : " + room.getCurrentRound());

String destination = getDestination(room.getId());

messageSender.sendBroadcast(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,23 @@
import io.f1.backend.domain.game.model.Room;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class TimerService {

private final ApplicationEventPublisher eventPublisher;

public void startTimer(Room room, int delaySec) {
log.debug(room.getId() + "번 방 타이머 시작 ! 현재 라운드 : " + room.getCurrentRound());
cancelTimer(room);

ScheduledFuture<?> timer =
Expand All @@ -43,6 +46,7 @@ public boolean validateCurrentRound(Room room) {

public boolean cancelTimer(Room room) {
// 정답 맞혔어요 ~ 타이머 캔슬 부탁
log.debug(room.getId() + "번 방 타이머 취소 ! 현재 라운드 : " + room.getCurrentRound());
ScheduledFuture<?> timer = room.getTimer();
if (timer != null && !timer.isDone()) {
return timer.cancel(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package io.f1.backend.domain.question.api;

import io.f1.backend.domain.question.app.QuestionService;
import io.f1.backend.domain.question.dto.QuestionUpdateRequest;

import lombok.RequiredArgsConstructor;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

Expand All @@ -20,21 +17,6 @@ public class QuestionController {

private final QuestionService questionService;

@PutMapping("/{questionId}")
public ResponseEntity<Void> updateQuestion(
@PathVariable Long questionId, @RequestBody QuestionUpdateRequest request) {

if (request.content() != null) {
questionService.updateQuestionContent(questionId, request.content());
}

if (request.content() != null) {
questionService.updateQuestionAnswer(questionId, request.answer());
}

return ResponseEntity.noContent().build();
}

@DeleteMapping("/{questionId}")
public ResponseEntity<Void> deleteQuestion(@PathVariable Long questionId) {
questionService.deleteQuestion(questionId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,23 @@

import static io.f1.backend.domain.question.mapper.QuestionMapper.questionRequestToQuestion;
import static io.f1.backend.domain.question.mapper.TextQuestionMapper.questionRequestToTextQuestion;
import static io.f1.backend.domain.quiz.app.QuizService.verifyUserAuthority;

import io.f1.backend.domain.question.dao.QuestionRepository;
import io.f1.backend.domain.question.dao.TextQuestionRepository;
import io.f1.backend.domain.question.dto.QuestionRequest;
import io.f1.backend.domain.question.dto.QuestionUpdateRequest;
import io.f1.backend.domain.question.entity.Question;
import io.f1.backend.domain.question.entity.TextQuestion;
import io.f1.backend.domain.quiz.entity.Quiz;
import io.f1.backend.global.exception.CustomException;
import io.f1.backend.global.exception.errorcode.AuthErrorCode;
import io.f1.backend.global.exception.errorcode.QuestionErrorCode;
import io.f1.backend.global.security.enums.Role;
import io.f1.backend.global.util.SecurityUtils;

import lombok.RequiredArgsConstructor;

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

import java.util.Objects;

@Service
@RequiredArgsConstructor
public class QuestionService {
Expand All @@ -41,46 +38,22 @@ public void saveQuestion(Quiz quiz, QuestionRequest request) {
question.addTextQuestion(textQuestion);
}

@Transactional
public void updateQuestionContent(Long questionId, String content) {

validateContent(content);
public void updateQuestions(Quiz quiz, QuestionUpdateRequest request) {

Question question =
questionRepository
.findById(questionId)
.orElseThrow(
() -> new CustomException(QuestionErrorCode.QUESTION_NOT_FOUND));

verifyUserAuthority(question.getQuiz());

TextQuestion textQuestion = question.getTextQuestion();
textQuestion.changeContent(content);
}

private static void verifyUserAuthority(Quiz quiz) {
if (SecurityUtils.getCurrentUserRole() == Role.ADMIN) {
if (request.getId() == null) {
saveQuestion(quiz, QuestionRequest.of(request));
return;
}
if (!Objects.equals(SecurityUtils.getCurrentUserId(), quiz.getCreator().getId())) {
throw new CustomException(AuthErrorCode.FORBIDDEN);
}
}

@Transactional
public void updateQuestionAnswer(Long questionId, String answer) {

validateAnswer(answer);

Question question =
questionRepository
.findById(questionId)
.findById(request.getId())
.orElseThrow(
() -> new CustomException(QuestionErrorCode.QUESTION_NOT_FOUND));

verifyUserAuthority(question.getQuiz());

question.changeAnswer(answer);
TextQuestion textQuestion = question.getTextQuestion();
textQuestion.changeContent(request.getContent());
question.changeAnswer(request.getAnswer());
}

@Transactional
Expand All @@ -96,16 +69,4 @@ public void deleteQuestion(Long questionId) {

questionRepository.delete(question);
}

private void validateAnswer(String answer) {
if (answer.trim().length() < 5 || answer.trim().length() > 30) {
throw new CustomException(QuestionErrorCode.INVALID_ANSWER_LENGTH);
}
}

private void validateContent(String content) {
if (content.trim().length() < 5 || content.trim().length() > 30) {
throw new CustomException(QuestionErrorCode.INVALID_CONTENT_LENGTH);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,12 @@ public class QuestionRequest {
@TrimmedSize(min = 1, max = 30)
@NotBlank(message = "정답을 입력해주세요.")
private String answer;

public static QuestionRequest of(QuestionUpdateRequest request) {
QuestionRequest questionRequest = new QuestionRequest();
questionRequest.content = request.getContent();
questionRequest.answer = request.getAnswer();

return questionRequest;
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
package io.f1.backend.domain.question.dto;

public record QuestionUpdateRequest(String content, String answer) {}
import io.f1.backend.global.validation.TrimmedSize;

import jakarta.validation.constraints.NotBlank;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class QuestionUpdateRequest {

private Long id;

@TrimmedSize(min = 5, max = 30)
@NotBlank(message = "문제를 입력해주세요.")
private String content;

@TrimmedSize(min = 1, max = 30)
@NotBlank(message = "정답을 입력해주세요.")
private String answer;
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,9 @@ public ResponseEntity<Void> deleteQuiz(@PathVariable Long quizId) {
public ResponseEntity<Void> updateQuiz(
@PathVariable Long quizId,
@RequestPart(required = false) MultipartFile thumbnailFile,
@RequestPart QuizUpdateRequest request) {
@Valid @RequestPart QuizUpdateRequest request) {

if (request.title() != null) {
quizService.updateQuizTitle(quizId, request.title());
}

if (request.description() != null) {
quizService.updateQuizDesc(quizId, request.description());
}
quizService.updateQuizAndQuestions(quizId, request);

if (thumbnailFile != null && !thumbnailFile.isEmpty()) {
quizService.updateThumbnail(quizId, thumbnailFile);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import io.f1.backend.domain.question.app.QuestionService;
import io.f1.backend.domain.question.dto.QuestionRequest;
import io.f1.backend.domain.question.dto.QuestionUpdateRequest;
import io.f1.backend.domain.question.entity.Question;
import io.f1.backend.domain.quiz.dao.QuizRepository;
import io.f1.backend.domain.quiz.dto.QuizCreateRequest;
Expand All @@ -14,6 +15,7 @@
import io.f1.backend.domain.quiz.dto.QuizListResponse;
import io.f1.backend.domain.quiz.dto.QuizMinData;
import io.f1.backend.domain.quiz.dto.QuizQuestionListResponse;
import io.f1.backend.domain.quiz.dto.QuizUpdateRequest;
import io.f1.backend.domain.quiz.entity.Quiz;
import io.f1.backend.domain.user.dao.UserRepository;
import io.f1.backend.domain.user.entity.User;
Expand Down Expand Up @@ -138,7 +140,7 @@ public void deleteQuiz(Long quizId) {
quizRepository.deleteById(quizId);
}

private static void verifyUserAuthority(Quiz quiz) {
public static void verifyUserAuthority(Quiz quiz) {
if (SecurityUtils.getCurrentUserRole() == Role.ADMIN) {
return;
}
Expand All @@ -148,30 +150,22 @@ private static void verifyUserAuthority(Quiz quiz) {
}

@Transactional
public void updateQuizTitle(Long quizId, String title) {
public void updateQuizAndQuestions(Long quizId, QuizUpdateRequest request) {
Quiz quiz =
quizRepository
.findById(quizId)
.orElseThrow(() -> new CustomException(QuizErrorCode.QUIZ_NOT_FOUND));

verifyUserAuthority(quiz);

validateTitle(title);
quiz.changeTitle(title);
}

@Transactional
public void updateQuizDesc(Long quizId, String description) {

Quiz quiz =
quizRepository
.findById(quizId)
.orElseThrow(() -> new CustomException(QuizErrorCode.QUIZ_NOT_FOUND));
quiz.changeTitle(request.getTitle());
quiz.changeDescription(request.getDescription());

verifyUserAuthority(quiz);
List<QuestionUpdateRequest> questionReqList = request.getQuestions();

validateDesc(description);
quiz.changeDescription(description);
for (QuestionUpdateRequest questionReq : questionReqList) {
questionService.updateQuestions(quiz, questionReq);
}
}

@Transactional
Expand All @@ -191,18 +185,6 @@ public void updateThumbnail(Long quizId, MultipartFile thumbnailFile) {
quiz.changeThumbnailUrl(newThumbnailPath);
}

private void validateDesc(String desc) {
if (desc.trim().length() < 10 || desc.trim().length() > 50) {
throw new CustomException(QuizErrorCode.INVALID_DESC_LENGTH);
}
}

private void validateTitle(String title) {
if (title.trim().length() < 2 || title.trim().length() > 30) {
throw new CustomException(QuizErrorCode.INVALID_TITLE_LENGTH);
}
}

private void deleteThumbnailFile(String oldFilename) {
if (oldFilename.contains(DEFAULT)) {
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
package io.f1.backend.domain.quiz.dto;

public record QuizUpdateRequest(String title, String description) {}
import io.f1.backend.domain.question.dto.QuestionUpdateRequest;
import io.f1.backend.global.validation.TrimmedSize;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class QuizUpdateRequest {

@TrimmedSize(min = 2, max = 30)
@NotBlank(message = "퀴즈 제목을 설정해주세요.")
private String title;

@TrimmedSize(min = 10, max = 50)
@NotBlank(message = "퀴즈 설명을 적어주세요.")
private String description;

@Size(min = 10, max = 80, message = "문제는 최소 10개, 최대 80개로 정해주세요.")
private List<QuestionUpdateRequest> questions;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
import io.f1.backend.global.exception.errorcode.RoomErrorCode;
import io.f1.backend.global.exception.errorcode.UserErrorCode;

import jakarta.annotation.PostConstruct;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

Expand All @@ -30,7 +28,6 @@ public class StatRepositoryAdapter implements StatRepository {
private final StatJpaRepository jpaRepository;
private final StatRedisRepository redisRepository;

@PostConstruct
public void setup() {
redisRepository.setup();
warmingRedis();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.f1.backend.global.config;

import io.f1.backend.domain.stat.dao.StatRepositoryAdapter;
import io.f1.backend.global.util.RedisUserSubscriber;

import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
Expand Down Expand Up @@ -38,4 +40,9 @@ public RedisMessageListenerContainer redisMessageListenerContainer(
container.addMessageListener(redisUserSubscriber, new PatternTopic("user-*"));
return container;
}

@Bean
ApplicationRunner redisWarmingRunner(StatRepositoryAdapter statRepositoryAdapter) {
return args -> statRepositoryAdapter.setup();
}
}
Loading