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
2 changes: 2 additions & 0 deletions src/main/java/com/example/be/BeApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
@SpringBootApplication
public class BeApplication {

Expand Down
13 changes: 11 additions & 2 deletions src/main/java/com/example/be/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import com.example.be.domain.enums.LoginType;
import jakarta.persistence.*;
import lombok.*;
import org.springframework.cglib.core.Local;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
Expand Down Expand Up @@ -34,10 +37,16 @@ public class User {

private String providerId;

private String gptKey;

private LocalDateTime createDate;

@Column(columnDefinition = "int default 0")
private int todayStudyTime;

@Column(columnDefinition = "int default 0")
private int totalStudyTime;

@Column(columnDefinition = "int default 0")
private int goalStudyTime;

//Relationships
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/example/be/repository/UserRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.example.be.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.util.Optional;
import java.util.UUID;
Expand All @@ -15,4 +16,8 @@ public interface UserRepository extends JpaRepository<User, Long> {
boolean existsByEmail(String email);

Optional<User> findByEmail(String email);

@Modifying
@Query("update User u Set u.todayStudyTime = 0")
void updateTodayStudyTime();
}
3 changes: 0 additions & 3 deletions src/main/java/com/example/be/service/PostServiceImpl.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.example.be.service;


import com.example.be.apiPayload.ApiResponse;
import com.example.be.apiPayload.code.status.ErrorStatus;
import com.example.be.apiPayload.exception.handler.PostHandler;
import com.example.be.apiPayload.exception.handler.UserHandler;
Expand All @@ -13,10 +12,8 @@
import com.example.be.web.dto.CommentDTO;
import com.example.be.web.dto.CommonDTO;
import com.example.be.web.dto.PostDTO;
import com.example.be.web.dto.UserDTO;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
Expand Down
83 changes: 83 additions & 0 deletions src/main/java/com/example/be/service/StudyServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.example.be.service;

import com.example.be.apiPayload.code.status.ErrorStatus;
import com.example.be.apiPayload.exception.handler.UserHandler;
import com.example.be.domain.User;
import com.example.be.repository.UserRepository;
import com.example.be.web.dto.CommonDTO;
import com.example.be.web.dto.UserDTO;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

@Service
@RequiredArgsConstructor
public class StudyServiceImpl {
private final JwtUtilServiceImpl jwtUtilService;
private final UserRepository userRepository;

private User getUserFromRequest(HttpServletRequest request) {
try {
String accessToken = jwtUtilService.extractTokenFromCookie(request, "accessToken");
if (accessToken != null) {
String userId = jwtUtilService.getUserIdFromToken(accessToken);
return userRepository.findByUserId(UUID.fromString(userId)).orElse(null);
}
} catch (Exception e) {
throw new UserHandler(ErrorStatus._NOT_FOUND_COOKIE);
}
return null;
}

public CommonDTO.IsSuccessDTO addStudyTime(HttpServletRequest request, int time) {
User user= getUserFromRequest(request);

if (user != null) {
user.setTodayStudyTime(user.getTodayStudyTime()+ time);
user.setTotalStudyTime(user.getTotalStudyTime()+ time);
userRepository.save(user);
}

return CommonDTO.IsSuccessDTO.builder().isSuccess(true).build();
}

public CommonDTO.IsSuccessDTO addStudyGoalTime(HttpServletRequest request, int time) {
User user= getUserFromRequest(request);

if (user != null) {
user.setGoalStudyTime(time);
userRepository.save(user);
}

return CommonDTO.IsSuccessDTO.builder().isSuccess(true).build();
}

public UserDTO.studyTimeResponseDto getStudyTime(HttpServletRequest request) {
User user= getUserFromRequest(request);

int today = user.getTodayStudyTime();
int total = user.getTotalStudyTime();
int goal = user.getGoalStudyTime();

return UserDTO.studyTimeResponseDto.builder()
.userId(user.getId())
.todayStudyTime(today/60 +"시간 " + today%60+"분")
.totalStudyTime(total/60 + "시간 " + total%60 + "분")
.goalStudyTime(goal/60 + "시간 " + goal%60 + "분")
.build();
}

//매일 자정에 오늘 공부 시간 초기화
@Scheduled(cron = "0 0 0 * * *")
@Transactional
public void resetTodayStudyTime() {
userRepository.updateTodayStudyTime();
}



}
46 changes: 8 additions & 38 deletions src/main/java/com/example/be/service/UserServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.example.be.apiPayload.exception.handler.UserHandler;
import com.example.be.domain.RefreshToken;
import com.example.be.domain.User;
import com.example.be.domain.enums.LoginType;
import com.example.be.repository.RefreshTokenRepository;
import com.example.be.repository.UserRepository;
import com.example.be.web.dto.CommonDTO;
Expand All @@ -15,10 +14,11 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.UUID;

Expand All @@ -27,7 +27,7 @@
@RequiredArgsConstructor
public class UserServiceImpl extends SimpleUrlAuthenticationSuccessHandler {
private final UserRepository userRepository;
private final JwtUtilServiceImpl jwtUtil;
private final JwtUtilServiceImpl jwtUtilService;
private final RefreshTokenRepository refreshTokenRepository;

@Value("${jwt.access-token.expiration-time}")
Expand Down Expand Up @@ -72,7 +72,7 @@ public CommonDTO.IsSuccessDTO login(UserDTO.LoginRequestDto request, HttpServlet
refreshTokenRepository.deleteByUserId(user.getUserId());

// RefreshToken 재발급
String refreshToken = jwtUtil.generateRefreshToken(user.getUserId(), REFRESH_TOKEN_EXPIRATION_TIME);
String refreshToken = jwtUtilService.generateRefreshToken(user.getUserId(), REFRESH_TOKEN_EXPIRATION_TIME);

RefreshToken newRefreshToken = RefreshToken.builder()
.userId(user.getUserId())
Expand All @@ -82,29 +82,14 @@ public CommonDTO.IsSuccessDTO login(UserDTO.LoginRequestDto request, HttpServlet
refreshTokenRepository.save(newRefreshToken);

// AccessToken 발급
String accessToken = jwtUtil.generateAccessToken(user.getUserId(), ACCESS_TOKEN_EXPIRATION_TIME);

String origin = httpRequest.getHeader("Origin");
// boolean isLocalhost = origin != null && origin.contains("localhost");
//
// // 액세스 토큰 쿠키 설정
// if (isLocalhost) {
// // 로컬 개발 환경: SameSite=None, Secure=false
// response.addHeader("Set-Cookie",
// String.format("accessToken=%s; Path=/; Max-Age=%d; HttpOnly; SameSite=None",
// accessToken, (int) (ACCESS_TOKEN_EXPIRATION_TIME / 1000)));
// response.addHeader("Set-Cookie",
// String.format("refreshToken=%s; Path=/; Max-Age=%d; HttpOnly; SameSite=None",
// refreshToken, (int) (REFRESH_TOKEN_EXPIRATION_TIME / 1000)));
// } else {
// 배포 환경: SameSite=None, Secure=true
String accessToken = jwtUtilService.generateAccessToken(user.getUserId(), ACCESS_TOKEN_EXPIRATION_TIME);

response.addHeader("Set-Cookie",
String.format("accessToken=%s; Path=/; Max-Age=%d; HttpOnly; Secure; SameSite=None",
accessToken, (int) (ACCESS_TOKEN_EXPIRATION_TIME / 1000)));
response.addHeader("Set-Cookie",
String.format("refreshToken=%s; Path=/; Max-Age=%d; HttpOnly; Secure; SameSite=None",
refreshToken, (int) (REFRESH_TOKEN_EXPIRATION_TIME / 1000)));
// }

return CommonDTO.IsSuccessDTO.builder().isSuccess(true).build();
}
Expand All @@ -116,7 +101,7 @@ public UserDTO.UserResponseDto getUserInfo(String accessToken) {
}

// 토큰에서 사용자 ID 추출
String userId = jwtUtil.getUserIdFromToken(accessToken);
String userId = jwtUtilService.getUserIdFromToken(accessToken);

// 사용자 정보 조회
User user = userRepository.findByUserId(UUID.fromString(userId))
Expand All @@ -138,27 +123,12 @@ public CommonDTO.IsSuccessDTO logout(HttpServletResponse response, HttpServletRe
if(cookies == null) {
throw new UserHandler(ErrorStatus._NOT_FOUND_COOKIE);
}

// Origin 헤더로 환경 판단
// String origin = request.getHeader("Origin");
// boolean isSecure = origin == null || !origin.contains("localhost");

// 쿠키 삭제 - addHeader 방식 사용
// if (isSecure) {
// 배포 환경
response.addHeader("Set-Cookie",
"accessToken=; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=None");
response.addHeader("Set-Cookie",
"refreshToken=; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=None");
// } else {
// // 로컬 환경
// response.addHeader("Set-Cookie",
// "accessToken=; Path=/; Max-Age=0; HttpOnly; SameSite=None");
// response.addHeader("Set-Cookie",
// "refreshToken=; Path=/; Max-Age=0; HttpOnly; SameSite=None");
// }

return CommonDTO.IsSuccessDTO.builder().isSuccess(true).build();
}

}

Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
package com.example.be.web.controller;

import com.example.be.apiPayload.ApiResponse;
import com.example.be.apiPayload.code.status.ErrorStatus;
import com.example.be.apiPayload.exception.handler.UserHandler;
import com.example.be.domain.User;
import com.example.be.repository.UserRepository;
import com.example.be.service.JwtUtilServiceImpl;
import com.example.be.service.PostLikeServiceImpl;
import com.example.be.service.PostServiceImpl;
import com.example.be.service.UserServiceImpl;
import com.example.be.web.dto.CommonDTO;
import com.example.be.web.dto.PostDTO;
import com.example.be.web.dto.UserDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/post")
@RequiredArgsConstructor
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/com/example/be/web/controller/StudyController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.example.be.web.controller;

import com.example.be.apiPayload.ApiResponse;
import com.example.be.service.StudyServiceImpl;
import com.example.be.service.UserServiceImpl;
import com.example.be.web.dto.CommonDTO;
import com.example.be.web.dto.UserDTO;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/study")
@RequiredArgsConstructor
public class StudyController {

private final StudyServiceImpl studyService;

@PostMapping("/{time}")
@Operation(summary = "오늘, 누적 공부 시간 추가 API")
public ApiResponse<CommonDTO.IsSuccessDTO> addStudyTime(HttpServletRequest request, @PathVariable("time")int time) {
return ApiResponse.onSuccess(studyService.addStudyTime(request, time));
}

@PostMapping("/goal/{time}")
@Operation(summary = "목표 공부 시간 수정 API")
public ApiResponse<CommonDTO.IsSuccessDTO> addStudyGoalTime(HttpServletRequest request, @PathVariable("time")int time) {
return ApiResponse.onSuccess(studyService.addStudyGoalTime(request, time));
}

@GetMapping("/time")
@Operation(summary = "오늘, 누적, 목표 공부 시간 조회 API")
public ApiResponse<UserDTO.studyTimeResponseDto> getStudyTime(HttpServletRequest request) {
return ApiResponse.onSuccess(studyService.getStudyTime(request));
}


}
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package com.example.be.web.controller;

import com.example.be.apiPayload.ApiResponse;
import com.example.be.apiPayload.code.status.ErrorStatus;
import com.example.be.apiPayload.exception.handler.UserHandler;
import com.example.be.service.JwtUtilServiceImpl;
import com.example.be.service.UserServiceImpl;
import com.example.be.web.dto.CommonDTO;
import com.example.be.web.dto.UserDTO;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
Expand Down Expand Up @@ -49,4 +45,6 @@ public ApiResponse<UserDTO.UserResponseDto> userInfo(HttpServletRequest request)
public ApiResponse<CommonDTO.IsSuccessDTO> logout(HttpServletResponse response, HttpServletRequest request) {
return ApiResponse.onSuccess(userService.logout(response, request));
}


}
11 changes: 11 additions & 0 deletions src/main/java/com/example/be/web/dto/UserDTO.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,15 @@ public static class LoginRequestDto {
private String email;
private String password;
}

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class studyTimeResponseDto {
private Long userId;
private String todayStudyTime;
private String totalStudyTime;
private String goalStudyTime;
}
}