Skip to content

Commit

Permalink
Merge pull request #37 from DigiLabChallengeHackathon/develop
Browse files Browse the repository at this point in the history
�rel: refactor clearStage
  • Loading branch information
andrewkimswe authored Jan 3, 2025
2 parents f6e81e9 + 9a7a197 commit de34a0a
Show file tree
Hide file tree
Showing 10 changed files with 51 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,6 @@ public ResponseEntity<ApiResponse<UserResponse>> signup(@RequestBody @Valid Sign
));
}

/**
* 스테이지 클리어 처리
* @param request 스테이지 클리어 요청 데이터
* @return 처리 상태 메시지
*/
@PostMapping("/clear-stage")
public ResponseEntity<ApiResponse<Void>> clearStage(@RequestBody @Valid StageClearRequest request) {
authService.clearStage(request.getDeviceId(), request.getRegion(), request.getStage());
return ResponseEntity.ok(new ApiResponse<>(
"success",
"Stage cleared successfully",
null
));
}

/**
* 사용자 진행 상황 조회
* @param deviceId 사용자 기기 ID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.mosabulgyeo.bewavoca.dto.ApiResponse;
import com.mosabulgyeo.bewavoca.dto.CompleteQuizRequest;
import com.mosabulgyeo.bewavoca.dto.QuizResponse;
import com.mosabulgyeo.bewavoca.service.AuthService;
import com.mosabulgyeo.bewavoca.service.QuizService;

import org.springframework.http.ResponseEntity;
Expand All @@ -15,9 +16,11 @@
public class QuizController {

private final QuizService quizService;
private final AuthService authService;

public QuizController(QuizService quizService) {
public QuizController(QuizService quizService, AuthService authService) {
this.quizService = quizService;
this.authService = authService;
}

/**
Expand Down Expand Up @@ -48,11 +51,19 @@ public ResponseEntity<ApiResponse<QuizResponse>> getQuiz(@RequestParam int level
*/
@PostMapping("/complete")
public ResponseEntity<ApiResponse<String>> completeQuiz(@RequestBody @Valid CompleteQuizRequest request) {
String message = quizService.completeQuiz(request);
return ResponseEntity.ok(new ApiResponse<>(
"success",
message,
null
));
if (request.isSuccess()) {
authService.clearStage(request.getDeviceId(), request.getRegion(), request.getStage());
return ResponseEntity.ok(new ApiResponse<>(
"success",
"Quiz completed successfully and stage cleared.",
null
));
} else {
return ResponseEntity.ok(new ApiResponse<>(
"success",
"Quiz failed. Better luck next time!",
null
));
}
}
}
45 changes: 8 additions & 37 deletions src/main/java/com/mosabulgyeo/bewavoca/dto/CharacterResponse.java
Original file line number Diff line number Diff line change
@@ -1,52 +1,23 @@
package com.mosabulgyeo.bewavoca.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

import java.util.Map;

/**
* CharacterResponse 클래스
* 캐릭터 정보를 반환하기 위한 DTO 클래스.
*/
@Getter
@Setter
@AllArgsConstructor
public class CharacterResponse {

/**
* 캐릭터 고유 ID.
*/
private Long id;

/**
* 캐릭터 이름.
* 예: "제주도민 캐릭터"
*/
private String name;

/**
* 캐릭터 설명.
* 캐릭터의 간단한 소개를 포함.
*/
private String description;

/**
* 캐릭터 대사.
* 예: "안녕하세요! 제주도에 오신 것을 환영합니다."
*/
private String dialogue;

/**
* 캐릭터 표정에 따른 이미지 경로.
* Key: 표정 (e.g., "happy", "sad"), Value: 이미지 경로.
*/
private Map<String, String> appearances;

/**
* 캐릭터가 속한 지역 이름.
* 예: "제주시", "서귀포시".
*/
private String regionName;

public CharacterResponse(Long id, String name, String description, String dialogue, String regionName) {
this.id = id;
this.name = name;
this.description = description;
this.dialogue = dialogue;
this.regionName = regionName;
}
}
35 changes: 12 additions & 23 deletions src/main/java/com/mosabulgyeo/bewavoca/dto/CompleteQuizRequest.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,24 @@
package com.mosabulgyeo.bewavoca.dto;

import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;

/**
* 퀴즈 완료 요청 데이터 전송 객체
*/

@Data
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class CompleteQuizRequest {
@NotBlank(message = "Device ID is required.")
private String deviceId;

@NotNull(message = "User ID is required.")
@Min(value = 1, message = "User ID must be a positive number.")
private Long userId;

@NotNull(message = "Region ID is required.")
@Min(value = 1, message = "Region ID must be a positive number.")
private Long regionId;

@NotNull(message = "Stage type is required.")
private StageType stageType;
@Min(value = 1, message = "Region must be greater than 0.")
private int region;

@NotNull(message = "Pass/fail result is required.")
private Boolean isPassed;
@Min(value = 1, message = "Stage must be greater than 0.")
private int stage;

public enum StageType {
OX, MATCH, CHOICE
}
private boolean isSuccess;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
@Getter
@Setter
public class StageClearRequest {
private String deviceId; // 사용자 ID
private int region; // 지역 번호
private int stage; // 스테이지 번호
private String deviceId;
private int region;
private int stage;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
@Getter
@Setter
public class UserProgressResponse {
private Set<String> clearedStages; // 클리어한 스테이지 목록
private Set<Integer> clearedRegions; // 클리어한 지역 목록
private Set<String> clearedStages;
private Set<Integer> clearedRegions;

public UserProgressResponse(Set<String> clearedStages, Set<Integer> clearedRegions) {
this.clearedStages = clearedStages;
Expand Down
29 changes: 2 additions & 27 deletions src/main/java/com/mosabulgyeo/bewavoca/entity/Character.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package com.mosabulgyeo.bewavoca.entity;

import java.util.Map;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;

/**
* Character 엔티티 클래스
* 게임에서 제공되는 캐릭터 정보를 저장하고 관리하는 도메인 모델.
* 캐릭터의 이름, 설명, 대화 내용, 소속된 지역(region), 표정에 따른 appearance를 포함.
* 캐릭터의 이름, 설명, 대화 내용, 소속된 지역(region) 포함.
*/
@Entity
@Getter
Expand Down Expand Up @@ -54,40 +52,17 @@ public class Character {
@JoinColumn(name = "region_id", nullable = false)
private Region region;

/**
* 캐릭터의 표정(Expression)과 해당 appearance(이미지 경로) 매핑 정보.
* e.g., "happy" -> "happy.png".
* 표정-appearance를 다루는 맵 구조로 저장.
*/
@ElementCollection
@CollectionTable(name = "character_appearances", joinColumns = @JoinColumn(name = "character_id"))
@MapKeyColumn(name = "expression")
@Column(name = "appearance")
private Map<String, String> appearances;

/**
* 캐릭터 엔티티 생성자.
* @param name 캐릭터 이름
* @param description 캐릭터 설명
* @param dialogue 캐릭터 대화 내용
* @param region 캐릭터가 속한 지역
* @param appearances 캐릭터의 표정과 appearance 매핑 정보
*/
public Character(String name, String description, String dialogue, Region region, Map<String, String> appearances) {
public Character(String name, String description, String dialogue, Region region) {
this.name = name;
this.description = description;
this.dialogue = dialogue;
this.region = region;
this.appearances = appearances;
}

/**
* 특정 표정에 해당하는 appearance 반환
*
* @param expression 표정 (e.g., "happy", "sad")
* @return 해당 표정에 대한 appearance 경로
*/
public String getAppearanceByExpression(String expression) {
return appearances.getOrDefault(expression, "default.png");
}
}
4 changes: 4 additions & 0 deletions src/main/java/com/mosabulgyeo/bewavoca/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ public boolean hasClearedAllStages(int region) {
&& clearedStages.contains(region + "-3");
}

public boolean hasClearedRegion(int region) {
return clearedRegions.contains(region);
}

/**
* 선택된 캐릭터 ID 업데이트
* @param characterId 선택할 캐릭터 ID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,44 +38,31 @@ public CharacterService(CharacterRepository characterRepository, UserRepository
* @throws IllegalArgumentException 사용자가 존재하지 않을 경우
*/
public List<CharacterResponse> getAvailableCharacters(String deviceId) {
// 사용자 확인
User user = userRepository.findByDeviceId(deviceId)
.orElseThrow(() -> new IllegalArgumentException("User not found for this device."));

// 기본 캐릭터(ID 1번) 조회
Character defaultCharacter = characterRepository.findById(1L)
.orElseThrow(() -> new IllegalStateException("Default character (ID 1) not found"));

// 사용자가 클리어한 지역에 따라 잠금 해제된 캐릭터 필터링
List<Character> unlockedCharacters = characterRepository.findAll().stream()
.filter(character -> user.hasClearedRegion(character.getRegion().getId()))
.filter(character -> user.hasClearedRegion(character.getRegion().getId().intValue()))
.collect(Collectors.toList());

// 기본 캐릭터(ID 1번)를 추가
if (unlockedCharacters.stream().noneMatch(character -> character.getId().equals(defaultCharacter.getId()))) {
unlockedCharacters.add(defaultCharacter);
}

// 캐릭터 리스트를 DTO로 변환하여 반환
return unlockedCharacters.stream()
.map(character -> new CharacterResponse(
character.getId(),
character.getName(),
character.getDescription(),
character.getDialogue(),
character.getAppearances(),
character.getRegion().getName()
))
.collect(Collectors.toList());
}

/**
* 캐릭터 선택 기능
* 사용자가 특정 캐릭터를 선택하면 해당 캐릭터를 설정.
*
* @param request 선택 요청 데이터 (기기 ID, 캐릭터 ID 포함)
* @throws IllegalArgumentException 사용자 또는 캐릭터가 존재하지 않거나 캐릭터 잠금 해제가 되지 않았을 경우
*/
/**
* 캐릭터 선택 기능
* 사용자가 특정 캐릭터를 선택하면 해당 캐릭터를 설정.
Expand Down Expand Up @@ -118,7 +105,6 @@ public CharacterResponse getSelectedCharacter(String deviceId) {
character.getName(),
character.getDescription(),
character.getDialogue(),
character.getAppearances(),
character.getRegion().getName()
);
}
Expand Down
33 changes: 1 addition & 32 deletions src/main/java/com/mosabulgyeo/bewavoca/service/QuizService.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
package com.mosabulgyeo.bewavoca.service;

import com.mosabulgyeo.bewavoca.dto.CompleteQuizRequest;
import com.mosabulgyeo.bewavoca.dto.QuizResponse;
import com.mosabulgyeo.bewavoca.entity.Quiz;
import com.mosabulgyeo.bewavoca.entity.Region;
import com.mosabulgyeo.bewavoca.entity.User;
import com.mosabulgyeo.bewavoca.mapper.QuizResponseMapper;
import com.mosabulgyeo.bewavoca.repository.RegionRepository;
import com.mosabulgyeo.bewavoca.repository.QuizRepository;
import com.mosabulgyeo.bewavoca.repository.UserRepository;

import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

import jakarta.transaction.Transactional;

@Service
public class QuizService {

private final UserRepository userRepository;
private final RegionRepository regionRepository;
private final QuizRepository quizRepository;

private final QuizResponseMapper quizResponseMapper;

public QuizService(UserRepository userRepository, RegionRepository regionRepository, QuizRepository quizRepository, QuizResponseMapper quizResponseMapper) {
this.userRepository = userRepository;
public QuizService(RegionRepository regionRepository, QuizRepository quizRepository, QuizResponseMapper quizResponseMapper) {
this.regionRepository = regionRepository;
this.quizRepository = quizRepository;
this.quizResponseMapper = quizResponseMapper;
Expand All @@ -51,27 +43,4 @@ public QuizResponse getQuizByTypeAndLevel(String type, int level) {

return new QuizResponse(type, level, quizResponses);
}

/**
* 퀴즈 완료 처리
*
* @param request 퀴즈 완료 요청 정보
* @return 완료 메시지
*/
@Transactional
public String completeQuiz(CompleteQuizRequest request) {
User user = userRepository.findById(request.getUserId())
.orElseThrow(() -> new IllegalArgumentException("User not found"));

if (request.getIsPassed()) {
user.clearStage(request.getStageType().name());
if (user.hasClearedRegion(request.getRegionId())) {
user.completeRegion(request.getRegionId());
return "Region completed successfully!";
}
return "Stage completed successfully.";
} else {
return "Stage failed. Retry is allowed.";
}
}
}

0 comments on commit de34a0a

Please sign in to comment.