Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly('io.jsonwebtoken:jjwt-jackson:0.11.5')
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/example/FixLog/FixLogApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

//Create_At 어노테이션
@EnableJpaAuditing
@SpringBootApplication
public class FixLogApplication {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.example.FixLog.domain.member.Member;
import com.example.FixLog.dto.Response;
import com.example.FixLog.dto.WithdrawRequestDto;
import com.example.FixLog.dto.member.MemberInfoResponseDto;
import com.example.FixLog.dto.member.SignupRequestDto;
import com.example.FixLog.dto.member.DuplicateCheckResponseDto;
Expand Down Expand Up @@ -51,8 +52,11 @@ public ResponseEntity<Response<MemberInfoResponseDto>> getMyInfo(@Authentication
}

@DeleteMapping("/me")
public ResponseEntity<Response<Void>> withdraw(@AuthenticationPrincipal Member member) {
memberService.withdraw(member);
public ResponseEntity<Response<Void>> withdraw(
@AuthenticationPrincipal Member member,
@RequestBody WithdrawRequestDto request
) {
memberService.withdraw(member, request.getPassword());
return ResponseEntity.ok(Response.success("회원 탈퇴 성공", null));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.example.FixLog.controller;

import com.example.FixLog.dto.Response;
import com.example.FixLog.dto.member.edit.EditNicknameRequestDto;
import com.example.FixLog.dto.member.edit.EditPasswordRequestDto;
import com.example.FixLog.dto.member.edit.EditProfileImageRequestDto;
import com.example.FixLog.dto.member.edit.EditBioRequestDto;
import com.example.FixLog.service.MemberService;
import com.example.FixLog.domain.member.Member;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/mypage")
public class MypageMemberController {

private final MemberService memberService;

@PatchMapping("/members/nickname")
public ResponseEntity<Response<String>> editNickname(
@RequestBody @Valid EditNicknameRequestDto requestDto
) {
Member member = memberService.getCurrentMemberInfo();
memberService.editNickname(member, requestDto.getNickname());
return ResponseEntity.ok(Response.success("닉네임 수정 성공", "SUCCESS"));
}

@PatchMapping("/members/password")
public ResponseEntity<Response<String>> editPassword(
@RequestBody @Valid EditPasswordRequestDto requestDto
) {
Member member = memberService.getCurrentMemberInfo();
memberService.editPassword(member, requestDto);
return ResponseEntity.ok(Response.success("비밀번호 변경 성공", "SUCCESS"));
}

@PatchMapping("/members/profile-image")
public ResponseEntity<Response<String>> editProfileImage(
@RequestBody @Valid EditProfileImageRequestDto requestDto
) {
Member member = memberService.getCurrentMemberInfo();
memberService.editProfileImage(member, requestDto.getProfileImageUrl());
return ResponseEntity.ok(Response.success("프로필 이미지 수정 성공", "SUCCESS"));
}

@PatchMapping("/members/bio")
public ResponseEntity<Response<String>> editBio(
@RequestBody @Valid EditBioRequestDto requestDto
) {
Member member = memberService.getCurrentMemberInfo();
memberService.editBio(member, requestDto.getBio());
return ResponseEntity.ok(Response.success("소개글 수정 성공", "SUCCESS"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,18 @@ public ResponseEntity<Response<PageResponseDto<MyPostPageResponseDto>>> getMyPos
return ResponseEntity.ok(Response.success("내가 작성한 글 보기 성공", data));
}

// 내가 좋아요한 글
@GetMapping("/likes")
public ResponseEntity<Response<PageResponseDto<MyPostPageResponseDto>>> getLikedPosts(
@AuthenticationPrincipal UserDetails userDetails,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "4") int size,
@RequestParam(defaultValue = "0") int sort) {

String email = userDetails.getUsername();
PageResponseDto<MyPostPageResponseDto> result = mypagePostService.getLikedPosts(email, page, sort, size);
return ResponseEntity.ok(Response.success("내가 좋아요한 글 보기 성공", result));
}
// // 내가 좋아요한 글
// @GetMapping("/likes")
// public ResponseEntity<Response<PageResponseDto<MyPostPageResponseDto>>> getLikedPosts(
// @AuthenticationPrincipal UserDetails userDetails,
// @RequestParam(defaultValue = "0") int page,
// @RequestParam(defaultValue = "4") int size,
// @RequestParam(defaultValue = "0") int sort) {
//
// String email = userDetails.getUsername();
// PageResponseDto<MyPostPageResponseDto> result = mypagePostService.getLikedPosts(email, page, sort, size);
// return ResponseEntity.ok(Response.success("내가 좋아요한 글 보기 성공", result));
// }


}
56 changes: 34 additions & 22 deletions src/main/java/com/example/FixLog/domain/member/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ public class Member implements UserDetails {
@Column(nullable = false)
private Boolean isDeleted = false;

public void setIsDeleted(boolean isDeleted) {
this.isDeleted = isDeleted;
}

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private SocialType socialType = SocialType.EMAIL;
Expand All @@ -57,68 +53,84 @@ public void setIsDeleted(boolean isDeleted) {
@Column
private LocalDateTime updatedAt;

// 프로필 사진 url, 지금은 nullable 이지만 나중에 기본값 설정
// 프로필 사진 URL
@Column
private String profileImageUrl;

@Column(length = 200)
private String bio;

// 게시글 연관관계
@OneToMany(mappedBy = "userId", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Post> posts = new ArrayList<>();

// 북마크 폴더
// 북마크 폴더 (계정당 1개)
@OneToOne(mappedBy = "userId", cascade = CascadeType.ALL, orphanRemoval = true)
private BookmarkFolder bookmarkFolderId;
// 우선은 계정 당 폴더 하나만 있는 걸로 생성
// @OneToMany(mappedBy = "userId", cascade = CascadeType.ALL, orphanRemoval = true)
// private List<BookmarkFolder> bookmarkFolders = new ArrayList<>();

// Member 객체를 정적 팩토리 방식으로 회원가입 시에 생성하는 메서드
// Member 객체를 정적 팩토리 방식으로 생성하는 메서드
// Creates a Member object using a static factory method
private BookmarkFolder bookmarkFolder;

// 정적 팩토리 메서드
public static Member of(String email, String password, String nickname, SocialType socialType) {
Member member = new Member();
member.email = email;
member.password = password;
member.nickname = nickname;
member.socialType = socialType;
member.isDeleted = false;
member.profileImageUrl = "https://dummyimage.com/200x200/cccccc/ffffff&text=Profile"; // 기본 프로필 이미지(임시)
member.profileImageUrl = null; // 기본 이미지는 응답 시 처리
return member;
}

public void setProfileImageUrl(String profileImageUrl) {
this.profileImageUrl = profileImageUrl;
// -------------------- 도메인 메서드 --------------------

public void updateNickname(String nickname) {
this.nickname = nickname;
}

public void updatePassword(String encodedPassword) {
this.password = encodedPassword;
}

public void updateProfileImage(String url) {
this.profileImageUrl = url;
}

public void updateBio(String bio) {
this.bio = bio;
}

public void markAsDeleted() {
this.isDeleted = true;
}

// -------------------- Spring Security --------------------

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority("ROLE_USER")); // 기본 권한
}

@Override
public String getUsername() {
return this.email; // 로그인 시 사용할 사용자 식별자
return this.email; // 로그인 시 사용할 식별자
}

@Override
public boolean isAccountNonExpired() {
return true; // 계정 만료 여부 (true = 사용 가능)
return true; // 계정 만료 안 됨
}

@Override
public boolean isAccountNonLocked() {
return true; // 계정 잠금 여부 (true = 잠금 아님)
return true; // 잠금 아님
}

@Override
public boolean isCredentialsNonExpired() {
return true; // 비밀번호 만료 여부
return true; // 비밀번호 만료 안 됨
}

@Override
public boolean isEnabled() {
return !this.isDeleted; // 탈퇴 여부 기반 활성 상태
return !this.isDeleted; // 탈퇴 계정은 비활성화
}
}
8 changes: 8 additions & 0 deletions src/main/java/com/example/FixLog/dto/WithdrawRequestDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.FixLog.dto;

import lombok.Getter;

@Getter
public class WithdrawRequestDto {
private String password;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.example.FixLog.dto.member;

import com.example.FixLog.domain.member.Member;
import com.example.FixLog.util.DefaultImage;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Getter;
Expand All @@ -12,4 +14,15 @@ public class LoginResponseDto {
private String accessToken;
private String nickname;
private String profileImageUrl;
}

public static LoginResponseDto from(Member member, String accessToken) {
return new LoginResponseDto(
member.getUserId(),
accessToken,
member.getNickname(),
member.getProfileImageUrl() != null
? member.getProfileImageUrl()
: DefaultImage.PROFILE
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import lombok.AllArgsConstructor;
import lombok.Getter;

// 서비스단에서 최대한 처리하도록 수정
@Getter
@AllArgsConstructor
public class MemberInfoResponseDto {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.FixLog.dto.member.edit;

import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class EditBioRequestDto {

@Size(max = 200, message = "소개글은 최대 200자까지 입력 가능합니다.")
private String bio;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.example.FixLog.dto.member.edit;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class EditNicknameRequestDto {

@NotBlank(message = "닉네임은 비어 있을 수 없습니다.")
@Size(min = 2, max = 20, message = "닉네임은 2자 이상 20자 이하로 입력해주세요.")
private String nickname;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.FixLog.dto.member.edit;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class EditPasswordRequestDto {

@NotBlank(message = "현재 비밀번호를 입력해주세요.")
private String currentPassword;

@NotBlank(message = "새 비밀번호를 입력해주세요.")
@Size(min = 8, max = 30, message = "비밀번호는 8자 이상 30자 이하로 입력해주세요.")
private String newPassword;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.FixLog.dto.member.edit;

import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class EditProfileImageRequestDto {

@NotBlank(message = "프로필 이미지 URL은 필수입니다.")
private String profileImageUrl;
}
3 changes: 2 additions & 1 deletion src/main/java/com/example/FixLog/exception/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public enum ErrorCode {
SORT_NOT_EXIST(HttpStatus.BAD_REQUEST, "사용할 수 없는 정렬입니다."),
INVALID_PASSWORD(HttpStatus.UNAUTHORIZED, "비밀번호가 일치하지 않습니다."),
REQUIRED_TAGS_MISSING(HttpStatus.BAD_REQUEST, "태그를 선택해주세요."),
REQUIRED_CONTENT_MISSING(HttpStatus.BAD_REQUEST, "필수 본문이 입력되지 않았습니다.");
REQUIRED_CONTENT_MISSING(HttpStatus.BAD_REQUEST, "필수 본문이 입력되지 않았습니다."),
SAME_AS_OLD_PASSWORD(HttpStatus.BAD_REQUEST, "다른 비밀번호 입력 바랍니다.");

private final HttpStatus status;
private final String message;
Expand Down
16 changes: 3 additions & 13 deletions src/main/java/com/example/FixLog/service/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,7 @@ public LoginResponseDto login(LoginRequestDto requestDto) {

String token = jwtUtil.createToken(member.getUserId(), member.getEmail());

// 로그인 응답 시에도 null-safe하게 처리
String profileUrl = member.getProfileImageUrl() != null
? member.getProfileImageUrl()
: "https://dummyimage.com/200x200/cccccc/ffffff&text=Profile";

return new LoginResponseDto(
member.getUserId(),
token,
member.getNickname(),
member.getProfileImageUrl() != null
? member.getProfileImageUrl()
: "https://your-cdn.com/images/default-profile.png");
// 응답에서 null-safe하게 기본 이미지 처리 포함
return LoginResponseDto.from(member, token);
}
}
}
Loading