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/FixLog/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.requestMatchers(HttpMethod.GET, "/members/check-nickname").permitAll()
.requestMatchers(HttpMethod.GET, "/", "/main", "/main/**").permitAll()
.requestMatchers(HttpMethod.GET, "/posts/**").permitAll()
.requestMatchers(HttpMethod.GET, "/tags").permitAll()
.requestMatchers("/api/s3/**").permitAll()
// h2-console (로컬 테스트용)
.requestMatchers(HttpMethod.GET, "/h2-console/**").permitAll()
// 배포 확인용 임시 허용
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/com/example/FixLog/controller/AuthController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import com.example.FixLog.dto.Response;
import com.example.FixLog.dto.member.LoginRequestDto;
import com.example.FixLog.dto.member.LoginResponseDto;
import com.example.FixLog.exception.ErrorCode;
import com.example.FixLog.service.AuthService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand All @@ -20,4 +22,18 @@ public ResponseEntity<Response<LoginResponseDto>> login(@RequestBody LoginReques
LoginResponseDto result = authService.login(requestDto);
return ResponseEntity.ok(Response.success("로그인 성공", result));
}

@PostMapping("/logout")
public ResponseEntity<Response<String>> logout(HttpServletRequest request) {
String token = request.getHeader("Authorization");

if (token != null && token.startsWith("Bearer ")) {
return ResponseEntity.ok(Response.success("로그아웃 완료. 클라이언트에서 토큰을 삭제하세요.", null));
} else {
return ResponseEntity
.badRequest()
.body(Response.fail(ErrorCode.UNAUTHORIZED.getMessage()));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import jakarta.validation.Valid;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import com.example.FixLog.dto.s3.PresignedUploadResponseDto;


import java.util.Map;

Expand Down Expand Up @@ -55,9 +57,9 @@ public ResponseEntity<Response<PresignResponseDto>> presignProfileImage(
) {
if (member == null) throw new CustomException(ErrorCode.UNAUTHORIZED);

String key = s3Service.generateKey("profile", filename);
String uploadUrl = s3Service.generatePresignedUrl("profile", filename, 15);
String fileUrl = s3Service.getObjectUrl(key);
PresignedUploadResponseDto responseDto = s3Service.generatePresignedUploadUrl("profile", filename, 15);
String uploadUrl = responseDto.getPresignedUrl();
String fileUrl = responseDto.getFileUrl();

PresignResponseDto dto = new PresignResponseDto(uploadUrl, fileUrl);
return ResponseEntity.ok(Response.success("Presigned URL 발급 성공", dto));
Expand Down Expand Up @@ -86,4 +88,4 @@ public ResponseEntity<Response<String>> editBio(
memberService.editBio(member, requestDto.getBio());
return ResponseEntity.ok(Response.success("소개글 수정 성공", "SUCCESS"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ public class MyPostPageResponseDto {
private LocalDateTime createdAt;
private int likeCount;
private int forkCount;
private String nickname;

public static MyPostPageResponseDto from(Post post, int forkCount) {
return MyPostPageResponseDto.builder()
.postId(post.getPostId())
.nickname(post.getUserId().getNickname())
.postTitle(post.getPostTitle())
.postSummary(generateSummary(post.getProblem()))
.imageUrl(post.getCoverImage())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.example.FixLog.dto.s3;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class PresignedUploadResponseDto {
private String presignedUrl; // PUT 요청용 presigned URL
private String fileUrl; // 업로드 완료 후 접근 가능한 S3 URL
}

4 changes: 3 additions & 1 deletion src/main/java/com/example/FixLog/exception/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
public enum ErrorCode {
USER_NICKNAME_NOT_FOUND(HttpStatus.NOT_FOUND,"존재하지 않는 사용자 아이디입니다."),
USER_EMAIL_NOT_FOUND(HttpStatus.NOT_FOUND, "회원 이메일을 찾을 수 없습니다."),
USER_DELETED(HttpStatus.FORBIDDEN, "탈퇴한 회원입니다."),
EMAIL_DUPLICATED(HttpStatus.CONFLICT, "중복된 이메일입니다"),
NICKNAME_DUPLICATED(HttpStatus.CONFLICT, "중복된 닉네임입니다"),
ALREADY_FOLLOWING(HttpStatus.CONFLICT, "이미 팔로우 중입니다"),
Expand All @@ -29,7 +30,8 @@ public enum ErrorCode {
UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "권한이 없습니다."),
INVALID_REQUEST(HttpStatus.BAD_REQUEST, "요청 데이터가 유효하지 않습니다."),
S3_UPLOAD_FAILED(HttpStatus.BAD_REQUEST, "S3 파일 업로드에 실패했습니다."),
IMAGE_UPLOAD_FAILED(HttpStatus.NOT_FOUND, "이미지 파일이 업로드되지 않았습니다.");
IMAGE_UPLOAD_FAILED(HttpStatus.NOT_FOUND, "이미지 파일이 업로드되지 않았습니다."),
LOGOUT_SUCCESS(HttpStatus.OK, "로그아웃이 정상적으로 처리되었습니다.");

private final HttpStatus status;
private final String message;
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/example/FixLog/service/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ public LoginResponseDto login(LoginRequestDto requestDto) {
Member member = memberRepository.findByEmail(requestDto.getEmail())
.orElseThrow(() -> new CustomException(ErrorCode.USER_NICKNAME_NOT_FOUND));

if (member.getIsDeleted()) {
throw new CustomException(ErrorCode.USER_DELETED);
}

if (!passwordEncoder.matches(requestDto.getPassword(), member.getPassword())) {
throw new CustomException(ErrorCode.INVALID_PASSWORD);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public MainPageService(PostRepository postRepository, MemberService memberServic
// 이미지 null일 때 default 사진으로 변경 (프로필 사진,
public String getDefaultImage(String image){
String imageUrl = (image == null || image.isBlank())
? "https://example.com/default-cover-image.png" : image;
? "https://fixlog-bucket.s3.ap-northeast-2.amazonaws.com/default/profile.png" : image;
System.out.println(imageUrl);
return imageUrl;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/example/FixLog/service/PostService.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public PostService(PostRepository postRepository, PostLikeRepository postLikeRep
// 이미지 null일 때 default 사진으로 변경 (프로필 사진,
public String getDefaultImage(String image){
String imageUrl = (image == null || image.isBlank())
? "https://example.com/default-cover-image.png" : image;
? "https://fixlog-bucket.s3.ap-northeast-2.amazonaws.com/default/profile.png" : image;
System.out.println(imageUrl);
return imageUrl;
}
Expand Down
8 changes: 5 additions & 3 deletions src/main/java/com/example/FixLog/service/S3Service.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.example.FixLog.dto.s3.PresignedUploadResponseDto;
import com.example.FixLog.exception.CustomException;
import com.example.FixLog.exception.ErrorCode;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -46,7 +47,7 @@ public String generateKey(String dirName, String filename) {
return dirName + "/" + UUID.randomUUID() + "_" + filename;
}

public String generatePresignedUrl(String dirName, String filename, int minutes) {
public PresignedUploadResponseDto generatePresignedUploadUrl(String dirName, String filename, int minutes) {
String key = generateKey(dirName, filename);
Date expiration = new Date(System.currentTimeMillis() + minutes * 60L * 1000L);

Expand All @@ -55,10 +56,11 @@ public String generatePresignedUrl(String dirName, String filename, int minutes)
.withExpiration(expiration);

URL url = amazonS3.generatePresignedUrl(request);
return url.toString();

return new PresignedUploadResponseDto(url.toString(), getObjectUrl(key));
}

public String getObjectUrl(String key) {
return amazonS3.getUrl(bucket, key).toString();
}
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/example/FixLog/util/DefaultImage.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.example.FixLog.util;

public class DefaultImage {
public static final String PROFILE = "https://dummyimage.com/200x200/cccccc/ffffff&text=Profile"; // 임시 기본 프로필 이미지
public static final String PROFILE = "https://fixlog-bucket.s3.ap-northeast-2.amazonaws.com/default/profile.png";
}