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
10 changes: 0 additions & 10 deletions src/main/java/inha/gdgoc/GdgocApplication.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
package inha.gdgoc;

import jakarta.annotation.PostConstruct;
import java.util.TimeZone;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing
@SpringBootApplication
// @EnableConfigurationProperties(JwtProperties.class)
public class GdgocApplication {

public static void main(String[] args) {
SpringApplication.run(GdgocApplication.class, args);
}

@PostConstruct
public void init() {
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul"));
}

}
90 changes: 51 additions & 39 deletions src/main/java/inha/gdgoc/domain/auth/controller/AuthController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
package inha.gdgoc.domain.auth.controller;

import static inha.gdgoc.domain.auth.controller.message.AuthMessage.ACCESS_TOKEN_REFRESH_SUCCESS;
import static inha.gdgoc.domain.auth.controller.message.AuthMessage.CODE_CREATION_SUCCESS;
import static inha.gdgoc.domain.auth.controller.message.AuthMessage.LOGIN_WITH_PASSWORD_SUCCESS;
import static inha.gdgoc.domain.auth.controller.message.AuthMessage.LOGOUT_SUCCESS;
import static inha.gdgoc.domain.auth.controller.message.AuthMessage.OAUTH_LOGIN_SIGNUP_SUCCESS;
import static inha.gdgoc.domain.auth.controller.message.AuthMessage.PASSWORD_CHANGE_SUCCESS;
import static inha.gdgoc.domain.auth.controller.message.AuthMessage.PASSWORD_RESET_VERIFICATION_SUCCESS;
import static inha.gdgoc.domain.auth.exception.AuthErrorCode.UNAUTHORIZED_USER;
import static inha.gdgoc.domain.auth.exception.AuthErrorCode.USER_NOT_FOUND;

import inha.gdgoc.domain.auth.dto.request.CodeVerificationRequest;
import inha.gdgoc.domain.auth.dto.request.PasswordResetRequest;
import inha.gdgoc.domain.auth.dto.request.SendingCodeRequest;
Expand All @@ -14,19 +24,15 @@
import inha.gdgoc.domain.auth.service.RefreshTokenService;
import inha.gdgoc.domain.user.entity.User;
import inha.gdgoc.domain.user.repository.UserRepository;
import inha.gdgoc.global.common.ApiResponse;
import inha.gdgoc.global.common.ErrorResponse;

import inha.gdgoc.global.dto.response.ApiResponse;
import inha.gdgoc.global.error.BusinessException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
Expand All @@ -39,7 +45,7 @@
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RequestMapping("/auth")
@RequestMapping("/api/v1/auth")
@RestController
@RequiredArgsConstructor
public class AuthController {
Expand All @@ -51,18 +57,18 @@ public class AuthController {
private final AuthCodeService authCodeService;

@GetMapping("/oauth2/google/callback")
public ResponseEntity<ApiResponse<Map<String, Object>>> handleGoogleCallback(
public ResponseEntity<ApiResponse<Map<String, Object>, Void>> handleGoogleCallback(
@RequestParam String code,
HttpServletResponse response
) {
Map<String, Object> data = authService.processOAuthLogin(code, response);
return ResponseEntity.ok(ApiResponse.of(data, null));
return ResponseEntity.ok(ApiResponse.ok(OAUTH_LOGIN_SIGNUP_SUCCESS, data));
}

@PostMapping("/refresh")
public ResponseEntity<?> refreshAccessToken(
@CookieValue(value = "refresh_token", required = false) String refreshToken) {

@CookieValue(value = "refresh_token", required = false) String refreshToken
) {
log.info("리프레시 토큰 요청 받음. 토큰 존재 여부: {}", refreshToken != null);

if (refreshToken == null) {
Expand All @@ -74,36 +80,37 @@ public ResponseEntity<?> refreshAccessToken(
try {
String newAccessToken = refreshTokenService.refreshAccessToken(refreshToken);
AccessTokenResponse accessTokenResponse = new AccessTokenResponse(newAccessToken);
return ResponseEntity.ok(ApiResponse.of(accessTokenResponse, null));

return ResponseEntity.ok(
ApiResponse.ok(ACCESS_TOKEN_REFRESH_SUCCESS, accessTokenResponse, null));
} catch (Exception e) {
log.error("리프레시 토큰 처리 중 오류: {}", e.getMessage(), e);
throw new BusinessException(AuthErrorCode.INVALID_REFRESH_TOKEN);
}
}

@PostMapping("/login")
public ResponseEntity<ApiResponse<LoginResponse>> login(@RequestBody UserLoginRequest userLoginRequest,
HttpServletResponse response)
throws NoSuchAlgorithmException, InvalidKeyException {
public ResponseEntity<ApiResponse<LoginResponse, Void>> login(
@RequestBody UserLoginRequest userLoginRequest,
HttpServletResponse response
) throws NoSuchAlgorithmException, InvalidKeyException {
LoginResponse loginResponse = authService.loginWithPassword(userLoginRequest, response);
return ResponseEntity.ok(ApiResponse.of(loginResponse, null));

return ResponseEntity.ok(ApiResponse.ok(LOGIN_WITH_PASSWORD_SUCCESS, loginResponse));
}

@PostMapping("/logout")
public ResponseEntity<ApiResponse<Void>> logout(
HttpServletRequest request,
HttpServletResponse response
) {
public ResponseEntity<ApiResponse<Void, Void>> logout() {
// TODO 서비스로 넘기기
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

if (authentication == null || !authentication.isAuthenticated()) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(ApiResponse.of(null, "인증되지 않은 사용자"));
throw new BusinessException(UNAUTHORIZED_USER);
}

String email = authentication.getName();
User user = userRepository.findByEmail(email)
.orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다"));
.orElseThrow(() -> new BusinessException(USER_NOT_FOUND));
Long userId = user.getId();

log.info("로그아웃 시도: 사용자 ID: {}, 이메일: {}", userId, email);
Expand All @@ -117,47 +124,52 @@ public ResponseEntity<ApiResponse<Void>> logout(
log.info("사용자 ID: {}의 리프레시 토큰이 성공적으로 삭제되었습니다.", userId);
}
} else {
log.warn("사용자 ID: {}의 쿠키에서 리프레시 토큰을 찾을 수 없습니다", userId);
log.warn("사용자를 찾을 수 없습니다.");
}

return ResponseEntity.ok(ApiResponse.of(null, null));
return ResponseEntity.ok(ApiResponse.ok(LOGOUT_SUCCESS));
}

@PostMapping("/password-reset/request")
public ResponseEntity<ApiResponse<Void>> responseResponseEntity(
public ResponseEntity<ApiResponse<Void, Void>> responseResponseEntity(
@RequestBody SendingCodeRequest sendingCodeRequest
) {
if (userRepository.existsByNameAndEmail(sendingCodeRequest.name(), sendingCodeRequest.email())) {
// TODO 서비스로 넘기기
if (userRepository.existsByNameAndEmail(sendingCodeRequest.name(),
sendingCodeRequest.email())) {
String code = mailService.sendAuthCode(sendingCodeRequest.email());
authCodeService.saveAuthCode(sendingCodeRequest.email(), code);
return ResponseEntity.ok(ApiResponse.of(null));

return ResponseEntity.ok(ApiResponse.ok(CODE_CREATION_SUCCESS));
}
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(ApiResponse.of(null, null));
throw new BusinessException(USER_NOT_FOUND);
}

@PostMapping("/password-reset/verify")
public ResponseEntity<ApiResponse<CodeVerificationResponse>> verifyCode(
@RequestBody CodeVerificationRequest codeVerificationRequest
public ResponseEntity<ApiResponse<CodeVerificationResponse, Void>> verifyCode(
@RequestBody CodeVerificationRequest request
) {
return ResponseEntity.ok(ApiResponse.of(new CodeVerificationResponse(authCodeService.verify(
codeVerificationRequest.email(), codeVerificationRequest.code()))));
// TODO 서비스 단 DTO 추가
boolean verified = authCodeService.verify(request.email(), request.code());
CodeVerificationResponse response = new CodeVerificationResponse(verified);

return ResponseEntity.ok(ApiResponse.ok(PASSWORD_RESET_VERIFICATION_SUCCESS, response));
}

@PostMapping("/password-reset/confirm")
public ResponseEntity<ApiResponse<Void>> resetPassword(@RequestBody PasswordResetRequest passwordResetRequest)
throws NoSuchAlgorithmException, InvalidKeyException {
public ResponseEntity<ApiResponse<Void, Void>> resetPassword(
@RequestBody PasswordResetRequest passwordResetRequest
) throws NoSuchAlgorithmException, InvalidKeyException {
// TODO 서비스 단으로
Optional<User> user = userRepository.findByEmail(passwordResetRequest.email());
if (user.isEmpty()) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(ApiResponse.of(null, null));
throw new BusinessException(USER_NOT_FOUND);
}

User foundUser = user.get();
foundUser.updatePassword(passwordResetRequest.password());
userRepository.save(foundUser);

return ResponseEntity.ok(ApiResponse.of(null, null));
return ResponseEntity.ok(ApiResponse.ok(PASSWORD_CHANGE_SUCCESS));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package inha.gdgoc.domain.auth.controller.message;

public class AuthMessage {
public static final String OAUTH_LOGIN_SIGNUP_SUCCESS = "로그인/회원가입 요청이 성공적으로 실행됐습니다.";
public static final String ACCESS_TOKEN_REFRESH_SUCCESS = "액세스 토큰이 성공적으로 재발급되었습니다.";
public static final String LOGIN_WITH_PASSWORD_SUCCESS = "성공적으로 비밀번호를 사용하여 로그인했습니다.";
public static final String LOGOUT_SUCCESS = "성공적으로 로그아웃했습니다.";
public static final String CODE_CREATION_SUCCESS = "성공적으로 인증 코드를 발급했습니다.";
public static final String PASSWORD_RESET_VERIFICATION_SUCCESS = "성공적으로 비밀번호 변경을 위한 인증 코드 검증이 완료되었습니다.";
public static final String PASSWORD_CHANGE_SUCCESS = "성공적으로 비밀번호를 변경했습니다.";
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package inha.gdgoc.domain.auth.dto.request;

import inha.gdgoc.global.common.BaseEntity;
import inha.gdgoc.global.entity.BaseEntity;
import lombok.Getter;
import lombok.Setter;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package inha.gdgoc.domain.auth.dto.response;

import inha.gdgoc.global.common.BaseEntity;
import inha.gdgoc.global.entity.BaseEntity;
import lombok.Getter;

@Getter
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package inha.gdgoc.domain.auth.entity;

import inha.gdgoc.domain.user.entity.User;
import inha.gdgoc.global.common.BaseEntity;
import inha.gdgoc.global.entity.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@

public enum AuthErrorCode implements ErrorCode {

// 401 Unauthorized
UNAUTHORIZED_USER(HttpStatus.UNAUTHORIZED, "인증되지 않은 사용자입니다."),

// 403 Forbidden
INVALID_COOKIE(HttpStatus.FORBIDDEN, "Refresh Token 이 비어있습니다."),
INVALID_REFRESH_TOKEN(HttpStatus.FORBIDDEN, "잘못된 Refresh Token 값입니다.");
INVALID_REFRESH_TOKEN(HttpStatus.FORBIDDEN, "잘못된 Refresh Token 값입니다."),

// 404 Not Found
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "사용자를 찾을 수 없습니다");

private final HttpStatus status;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,42 @@
package inha.gdgoc.domain.game.controller;

import static inha.gdgoc.domain.game.controller.message.GameQuestionMessage.GAME_QUESTION_RETRIEVED_SUCCESS;
import static inha.gdgoc.domain.game.controller.message.GameQuestionMessage.GAME_QUESTION_SAVE_SUCCESS;

import inha.gdgoc.domain.game.dto.request.GameQuestionRequest;
import inha.gdgoc.domain.game.dto.response.GameQuestionResponse;
import inha.gdgoc.domain.game.entity.GameQuestion;
import inha.gdgoc.domain.game.service.GameQuestionService;
import inha.gdgoc.global.common.ApiResponse;
import inha.gdgoc.global.dto.response.ApiResponse;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/api/v1/game/questions")
@RequiredArgsConstructor
@RestController
public class GameQuestionController {

private final GameQuestionService gameQuestionService;

@PostMapping("/game/question")
public ResponseEntity<ApiResponse<GameQuestionRequest>> saveQuestion(
@RequestBody GameQuestionRequest gameQuestionRequest) {
// 얘 api 엔드포인트 바뀜!
@PostMapping
public ResponseEntity<ApiResponse<Void, Void>> saveQuestion(
@RequestBody GameQuestionRequest gameQuestionRequest
) {
gameQuestionService.saveQuestion(gameQuestionRequest);

return ResponseEntity.ok(ApiResponse.of(null));
return ResponseEntity.ok(ApiResponse.ok(GAME_QUESTION_SAVE_SUCCESS));
}

@GetMapping("/game/questions")
public ResponseEntity<ApiResponse<List<GameQuestionResponse>>> getRandomGameQuestions() {
return ResponseEntity.ok(ApiResponse.of(gameQuestionService.getRandomQuestionsByLanguage()));
@GetMapping
public ResponseEntity<ApiResponse<List<GameQuestionResponse>, Void>> getRandomGameQuestions() {
List<GameQuestionResponse> response = gameQuestionService.getRandomQuestionsByLanguage();

return ResponseEntity.ok(ApiResponse.ok(GAME_QUESTION_RETRIEVED_SUCCESS, response));
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,41 @@
package inha.gdgoc.domain.game.controller;

import static inha.gdgoc.domain.game.controller.message.GameUserMessage.GAME_RANK_RETRIEVED_SUCCESS;
import static inha.gdgoc.domain.game.controller.message.GameUserMessage.GAME_RANK_SAVE_SUCCESS;

import inha.gdgoc.domain.game.dto.request.GameUserRequest;
import inha.gdgoc.domain.game.dto.response.GameUserResponse;
import inha.gdgoc.domain.game.service.GameUserService;
import inha.gdgoc.global.common.ApiResponse;
import inha.gdgoc.global.dto.response.ApiResponse;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/api/v1/game")
@RequiredArgsConstructor
@RestController
public class GameUserController {

private final GameUserService gameUserService;

@PostMapping("/game/result")
public ResponseEntity<ApiResponse<List<GameUserResponse>>> saveGameResult(@RequestBody GameUserRequest request) {
return ResponseEntity.ok(ApiResponse.of(gameUserService.saveGameResultAndGetRanking(request)));
@PostMapping("/result")
public ResponseEntity<ApiResponse<List<GameUserResponse>, Void>> saveGameResult(
@RequestBody GameUserRequest request
) {
List<GameUserResponse> response = gameUserService.saveGameResultAndGetRanking(request);

return ResponseEntity.ok(ApiResponse.ok(GAME_RANK_SAVE_SUCCESS, response));
}

@GetMapping("/game/results")
public ResponseEntity<ApiResponse<List<GameUserResponse>>> getUserRankings() {
return ResponseEntity.ok(ApiResponse.of(gameUserService.findUserRankings()));
@GetMapping("/results")
public ResponseEntity<ApiResponse<List<GameUserResponse>, Void>> getUserRankings() {
List<GameUserResponse> response = gameUserService.findUserRankings();

return ResponseEntity.ok(ApiResponse.ok(GAME_RANK_RETRIEVED_SUCCESS, response));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package inha.gdgoc.domain.game.controller.message;

public class GameQuestionMessage {
public static final String GAME_QUESTION_SAVE_SUCCESS = "성공적으로 게임 질문을 저장했습니다.";
public static final String GAME_QUESTION_RETRIEVED_SUCCESS = "성공적으로 게임 질문 리스트를 조회했습니다.";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package inha.gdgoc.domain.game.controller.message;

public class GameUserMessage {
public static final String GAME_RANK_SAVE_SUCCESS = "성공적으로 유저 랭킹 정보를 저장했습니다.";
public static final String GAME_RANK_RETRIEVED_SUCCESS = "성공적으로 랭킹 정보를 반환했습니다.";
}
2 changes: 1 addition & 1 deletion src/main/java/inha/gdgoc/domain/game/entity/GameUser.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package inha.gdgoc.domain.game.entity;

import inha.gdgoc.global.common.BaseEntity;
import inha.gdgoc.global.entity.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
Expand Down
Loading
Loading