diff --git a/src/main/java/com/example/FixLog/config/SecurityConfig.java b/src/main/java/com/example/FixLog/config/SecurityConfig.java index ede3958..8509595 100644 --- a/src/main/java/com/example/FixLog/config/SecurityConfig.java +++ b/src/main/java/com/example/FixLog/config/SecurityConfig.java @@ -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() // 배포 확인용 임시 허용 diff --git a/src/main/java/com/example/FixLog/controller/AuthController.java b/src/main/java/com/example/FixLog/controller/AuthController.java index 2aa535c..4acd281 100644 --- a/src/main/java/com/example/FixLog/controller/AuthController.java +++ b/src/main/java/com/example/FixLog/controller/AuthController.java @@ -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.*; @@ -20,4 +22,18 @@ public ResponseEntity> login(@RequestBody LoginReques LoginResponseDto result = authService.login(requestDto); return ResponseEntity.ok(Response.success("로그인 성공", result)); } + + @PostMapping("/logout") + public ResponseEntity> 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())); + } + } + } diff --git a/src/main/java/com/example/FixLog/controller/MypageMemberController.java b/src/main/java/com/example/FixLog/controller/MypageMemberController.java index 05d115e..e5ace04 100644 --- a/src/main/java/com/example/FixLog/controller/MypageMemberController.java +++ b/src/main/java/com/example/FixLog/controller/MypageMemberController.java @@ -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; @@ -55,9 +57,9 @@ public ResponseEntity> 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)); @@ -86,4 +88,4 @@ public ResponseEntity> editBio( memberService.editBio(member, requestDto.getBio()); return ResponseEntity.ok(Response.success("소개글 수정 성공", "SUCCESS")); } -} \ No newline at end of file +} diff --git a/src/main/java/com/example/FixLog/dto/post/MyPostPageResponseDto.java b/src/main/java/com/example/FixLog/dto/post/MyPostPageResponseDto.java index 6089085..8bc8529 100644 --- a/src/main/java/com/example/FixLog/dto/post/MyPostPageResponseDto.java +++ b/src/main/java/com/example/FixLog/dto/post/MyPostPageResponseDto.java @@ -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()) diff --git a/src/main/java/com/example/FixLog/dto/s3/PresignedUploadResponseDto.java b/src/main/java/com/example/FixLog/dto/s3/PresignedUploadResponseDto.java new file mode 100644 index 0000000..3571185 --- /dev/null +++ b/src/main/java/com/example/FixLog/dto/s3/PresignedUploadResponseDto.java @@ -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 +} + diff --git a/src/main/java/com/example/FixLog/exception/ErrorCode.java b/src/main/java/com/example/FixLog/exception/ErrorCode.java index f60c48d..7e059da 100644 --- a/src/main/java/com/example/FixLog/exception/ErrorCode.java +++ b/src/main/java/com/example/FixLog/exception/ErrorCode.java @@ -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, "이미 팔로우 중입니다"), @@ -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; diff --git a/src/main/java/com/example/FixLog/service/AuthService.java b/src/main/java/com/example/FixLog/service/AuthService.java index 31cc96e..c2a0950 100644 --- a/src/main/java/com/example/FixLog/service/AuthService.java +++ b/src/main/java/com/example/FixLog/service/AuthService.java @@ -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); } diff --git a/src/main/java/com/example/FixLog/service/MainPageService.java b/src/main/java/com/example/FixLog/service/MainPageService.java index b8cd9e2..3b27b2d 100644 --- a/src/main/java/com/example/FixLog/service/MainPageService.java +++ b/src/main/java/com/example/FixLog/service/MainPageService.java @@ -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; } diff --git a/src/main/java/com/example/FixLog/service/PostService.java b/src/main/java/com/example/FixLog/service/PostService.java index d10bcd6..da8b4cc 100644 --- a/src/main/java/com/example/FixLog/service/PostService.java +++ b/src/main/java/com/example/FixLog/service/PostService.java @@ -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; } diff --git a/src/main/java/com/example/FixLog/service/S3Service.java b/src/main/java/com/example/FixLog/service/S3Service.java index afd6158..5af4290 100644 --- a/src/main/java/com/example/FixLog/service/S3Service.java +++ b/src/main/java/com/example/FixLog/service/S3Service.java @@ -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; @@ -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); @@ -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(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/example/FixLog/util/DefaultImage.java b/src/main/java/com/example/FixLog/util/DefaultImage.java index fa1fd90..701b2af 100644 --- a/src/main/java/com/example/FixLog/util/DefaultImage.java +++ b/src/main/java/com/example/FixLog/util/DefaultImage.java @@ -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"; }