Skip to content

Commit

Permalink
Merge branch 'develop' into feature#65
Browse files Browse the repository at this point in the history
  • Loading branch information
rlarlgnszx authored Jul 11, 2024
2 parents 36c23ba + 0ff307c commit cb37a4b
Show file tree
Hide file tree
Showing 28 changed files with 480 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
import org.dateroad.code.FailureCode;
import org.dateroad.common.Constants;
import org.dateroad.exception.UnauthorizedException;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

Expand All @@ -20,6 +22,7 @@


@RequiredArgsConstructor
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtProvider jwtProvider;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ public class JwtGenerator {

public String generateAccessToken(final long userId) {
final Date now = new Date();
final Date expiryDate = generateExpirationDate(now);
final Date expireDate = generateExpirationDate(now);

return Jwts.builder()
.setHeaderParam(Header.TYPE, Header.JWT_TYPE)
.setSubject(String.valueOf(userId))
.setIssuedAt(now)
.setExpiration(expiryDate)
.setExpiration(expireDate)
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
.compact();
}
Expand Down
19 changes: 19 additions & 0 deletions dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@
import lombok.RequiredArgsConstructor;
import org.dateroad.auth.jwt.refreshtoken.RefreshTokenGenerator;
import org.dateroad.code.FailureCode;
import org.dateroad.exception.UnauthorizedException;
import org.dateroad.refreshtoken.domain.RefreshToken;
import org.dateroad.refreshtoken.repository.RefreshTokenRepository;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Base64;

@RequiredArgsConstructor
@Component
public class JwtProvider {
Expand All @@ -20,6 +27,18 @@ public Token issueToken(final long userId) {
);
}

//refreshToken 재발급할 때 검증
public void validateRefreshToken(LocalDateTime expireDate) {
if (expireDate.isBefore(LocalDateTime.now())) {
throw new UnauthorizedException(FailureCode.EXPIRED_REFRESH_TOKEN);
}
}

//Base64 인코딩된 리프레시 토큰 문자열을 바이트 배열
private byte[] toBinary(String refreshToken) {
return Base64.getDecoder().decode(refreshToken);
}

public long getUserIdFromSubject(String token) {
Jws<Claims> jws = jwtGenerator.parseToken(token);
String subject = jws.getBody().getSubject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import org.dateroad.code.FailureCode;
import org.dateroad.exception.UnauthorizedException;
import org.springframework.stereotype.Component;

public class JwtValidator {

public void equalRefreshToken(String refreshToken, String storedRefreshToken) {
if (!refreshToken.equals(storedRefreshToken)) {
throw new UnauthorizedException(FailureCode.UNAUTHORIZED);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Base64;
import java.util.Optional;

@RequiredArgsConstructor
@Component
Expand All @@ -22,30 +23,19 @@ public class RefreshTokenGenerator {
public String generateRefreshToken(final long userId) {
SecureRandom random = createSecureRandom();

//SecureRandom을 사용하여 45 바이트의 랜덤 토큰을 생성
byte[] token = new byte[TOKEN_BYTE_SIZE];
random.nextBytes(token);
LocalDateTime expireAt = LocalDateTime.now().plusWeeks(2);
// SecureRandom을 사용하여 45 바이트의 랜덤 토큰을 생성
byte[] tokenBytes = new byte[TOKEN_BYTE_SIZE];
random.nextBytes(tokenBytes);

RefreshToken newRefreshToken = RefreshToken.create(token, userId, expireAt);
refreshTokenRepository.save(newRefreshToken);

return Base64.getEncoder().encodeToString(token);
}
// 바이트 배열을 Base64 인코딩하여 문자열로 변환
String token = Base64.getEncoder().encodeToString(tokenBytes);

//refreshToken 재발급할 때 검증
public Long getUserIdOrThrow(final String refreshToken) {
byte[] convertedRefreshToken = toBinary(refreshToken);
LocalDateTime expireAt = LocalDateTime.now().plusWeeks(4);

RefreshToken findRefreshToken = refreshTokenRepository.findUserIdByToken(Arrays.toString(convertedRefreshToken).getBytes());
if (findRefreshToken == null) {
throw new UnauthorizedException(FailureCode.INVALID_REFRESH_TOKEN_VALUE);
}
RefreshToken newRefreshToken = RefreshToken.create(token, userId, expireAt);
refreshTokenRepository.save(newRefreshToken);

if (findRefreshToken.getExpiredAt().isBefore(LocalDateTime.now())) {
throw new UnauthorizedException(FailureCode.EXPIRED_REFRESH_TOKEN);
}
return findRefreshToken.getUserId();
return token;
}

public void deleteRefreshToken(final Long userId) {
Expand All @@ -60,8 +50,4 @@ private SecureRandom createSecureRandom() {
return new SecureRandom(buffer.array());
}

//Base64 인코딩된 리프레시 토큰 문자열을 바이트 배열
private byte[] toBinary(String refreshToken) {
return Base64.getDecoder().decode(refreshToken);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.dateroad.course.api;


import java.net.URI;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.dateroad.auth.argumentresolve.UserId;
Expand All @@ -19,15 +18,7 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

@RestController
Expand All @@ -39,21 +30,21 @@ public class CourseController {

@GetMapping
public ResponseEntity<CourseGetAllRes> getAllCourse(
@ModelAttribute CourseGetAllReq courseGetAllReq
final @ModelAttribute CourseGetAllReq courseGetAllReq
) {
CourseGetAllRes courseAll = courseService.getAllCourses(courseGetAllReq);
return ResponseEntity.ok(courseAll);
}

@GetMapping("/date-access")
public ResponseEntity<DateAccessGetAllRes> getAllDataAccesCourse(
@UserId Long userId
final @UserId Long userId
) {
DateAccessGetAllRes dateAccessGetAllRes = courseService.getAllDataAccessCourse(userId);
return ResponseEntity.ok(dateAccessGetAllRes);
}

@PostMapping(value = "/create", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
@PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<CourseCreateRes> createCourse(
@UserId final Long userId,
@RequestPart("course") final CourseCreateReq courseCreateReq,
Expand All @@ -76,6 +67,12 @@ public ResponseEntity<Void> openCourse(
@RequestBody final PointUseReq pointUseReq
) {
courseService.openCourse(userId,courseId,pointUseReq);
}

@PostMapping("/{courseId}/likes")
public ResponseEntity<Void> createCourseLlike(@UserId final Long userId,
@PathVariable final Long courseId) {
courseService.createCourseLike(userId, courseId);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
import org.dateroad.date.repository.CourseRepository;
import org.dateroad.dateAccess.domain.DateAccess;
import org.dateroad.dateAccess.repository.DateAccessRepository;
import org.dateroad.exception.DateRoadException;
import org.dateroad.exception.ConflictException;
import org.dateroad.exception.EntityNotFoundException;
import org.dateroad.image.domain.Image;
import org.dateroad.like.domain.Like;
import org.dateroad.like.repository.LikeRepository;
import org.dateroad.point.domain.Point;
import org.dateroad.point.repository.PointRepository;
Expand Down Expand Up @@ -48,6 +50,15 @@ public CourseGetAllRes getAllCourses(final CourseGetAllReq courseGetAllReq) {
return CourseGetAllRes.of(courseDtoGetResList);
}


@Transactional
public void createCourseLike(final Long userId, final Long courseId) {
User findUser = getUser(userId);
Course findCourse = getCourse(courseId);
validateCourseLike(findUser, findCourse);
saveCourseLike(findUser, findCourse);
}

private <T> List<CourseDtoGetRes> convertToDtoList(final List<T> entities, final Function<T, Course> converter) {
return entities.stream()
.map(converter)
Expand Down Expand Up @@ -78,16 +89,34 @@ public DateAccessGetAllRes getAllDataAccessCourse(final Long userId) {
return DateAccessGetAllRes.of(courseDtoGetResList);
}

private User getUser(final Long userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND));
}

private Course getCourse(final Long courseId) {
return courseRepository.findById(courseId)
.orElseThrow(() -> new EntityNotFoundException(FailureCode.COURSE_NOT_FOUND));
}

private void validateCourseLike(User findUser, Course findCourse) {
if (likeRepository.findByUserAndCourse(findUser, findCourse).isPresent()) {
throw new ConflictException(FailureCode.DUPLICATE_COURSE_LIKE);
}
}

private void saveCourseLike(User user, Course course) {
Like like = Like.create(course, user);
likeRepository.save(like);
}

@Transactional
public Course createCourse(final Long userId, final CourseCreateReq courseRegisterReq,
final List<CoursePlaceGetReq> places, final List<MultipartFile> images) {
final float totalTime = places.stream()
.map(CoursePlaceGetReq::getDuration)
.reduce(0.0f, Float::sum);
User user = userRepository.findById(userId)
.orElseThrow(
() -> new DateRoadException(FailureCode.ENTITY_NOT_FOUND)
);
User user = getUser(userId);
Course course = Course.create(
user,
courseRegisterReq.getTitle(),
Expand All @@ -101,8 +130,8 @@ public Course createCourse(final Long userId, final CourseCreateReq courseRegist
);
Course saveCourse = courseRepository.save(course);
List<Image> imageList = asyncService.createImage(images, saveCourse);
String thumnailUrl = imageList.getLast().getImageUrl();
course.setThumbnail(thumnailUrl);
String thumbnailUrl = imageList.getLast().getImageUrl();
course.setThumbnail(thumbnailUrl);
return saveCourse;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import org.dateroad.auth.argumentresolve.UserId;
import org.dateroad.date.dto.request.DateCreateReq;
import org.dateroad.date.dto.response.DateDetailRes;
import org.dateroad.date.dto.response.DatesGetRes;
import org.dateroad.date.dto.response.DateGetNearestRes;
import org.dateroad.date.service.DateService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -22,8 +24,15 @@ public ResponseEntity<Void> createDate(@UserId final Long userId,
return ResponseEntity.status(HttpStatus.CREATED).build();
}

@GetMapping
public ResponseEntity<DatesGetRes> getDates(@UserId final Long userId,
@RequestParam final String time) {
DatesGetRes datesGetRes = dateService.getDates(userId, time);
return ResponseEntity.ok(datesGetRes);
}

@GetMapping("/{dateId}")
public ResponseEntity<DateDetailRes> getDateDetail(@RequestHeader final Long userId,
public ResponseEntity<DateDetailRes> getDateDetail(@UserId final Long userId,
@PathVariable final Long dateId) {
DateDetailRes dateDetailRes = dateService.getDateDetail(userId, dateId);
return ResponseEntity.ok(dateDetailRes);
Expand All @@ -35,4 +44,11 @@ public ResponseEntity<Void> deleteDate(@UserId final Long userId,
dateService.deleteDate(userId, dateId);
return ResponseEntity.ok().build();
}

@GetMapping("/nearest")
public ResponseEntity<DateGetNearestRes> getNearestDate(@UserId final Long userId) {
DateGetNearestRes dateGetNearestRes = dateService.getNearestDate(userId);
return ResponseEntity
.ok(dateGetNearestRes);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.dateroad.date.dto.response;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AccessLevel;
import lombok.Builder;
import org.dateroad.date.domain.Date;
Expand All @@ -14,9 +15,11 @@
public record DateDetailRes(
Long dateId,
String title,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm", timezone = "Asia/Seoul")
LocalTime startAt,
String city,
List<TagGetRes> tags,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul")
LocalDate date,
List<PlaceGetRes> places
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.dateroad.date.dto.response;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AccessLevel;
import lombok.Builder;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

@Builder(access = AccessLevel.PRIVATE)
public record DateGetNearestRes(
Long dateId,
int dDay,
String dateName,
int month,
int day,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "hh:mm a", timezone = "Asia/Seoul")
LocalTime startAt
) {
public static DateGetNearestRes of(Long dateId,
int dDay,
String dateName,
int month,
int day,
LocalTime startAt) {
return DateGetNearestRes.builder()
.dateId(dateId)
.dDay(dDay)
.dateName(dateName)
.month(month)
.day(day)
.startAt(startAt)
.build();
}

}
Loading

0 comments on commit cb37a4b

Please sign in to comment.