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
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public class FieldBookmark extends BaseEntity {
@Column(name = "fbId", nullable = false)
private Integer id;

@Column(name = "fieldRecommend")
private Boolean isRecommend = false;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "fId", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ public class MajorBookmark extends BaseEntity {
@Column(name = "mbId", nullable = false)
private Integer id;

@Column(name = "majorRecommend")
private Boolean isRecommend = false;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "mId", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package hackerthon.likelion13th.canfly.domain.user;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Embeddable
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class Address {

@Column(name = "zipcode", length = 20, nullable = true)
private String zipcode;

@Column(name = "address", nullable = true)
private String address;

@Column(name = "address_detail", nullable = true)
private String addressDetail;

public boolean isEmpty() {
return (zipcode == null || zipcode.isBlank())
&& (address == null || address.isBlank())
&& (addressDetail == null || addressDetail.isBlank());
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package hackerthon.likelion13th.canfly.domain.user;

import hackerthon.likelion13th.canfly.domain.cst.Cst;
import hackerthon.likelion13th.canfly.domain.entity.BaseEntity;
import hackerthon.likelion13th.canfly.domain.entity.Sex;
import hackerthon.likelion13th.canfly.domain.field.FieldBookmark;
import hackerthon.likelion13th.canfly.domain.hmt.Hmt;
import hackerthon.likelion13th.canfly.domain.major.MajorBookmark;
import hackerthon.likelion13th.canfly.domain.mock.Mock;
import hackerthon.likelion13th.canfly.domain.report.Report;
Expand Down Expand Up @@ -50,6 +48,10 @@ public class User extends BaseEntity {
@Column(name = "gradeNum")
private Byte gradeNum;

@Setter
@Embedded
private Address address;

@Column(nullable = false)
@Builder.Default
private int token = 30;
Expand All @@ -73,7 +75,6 @@ public void addMock(Mock mock) {
mock.setUser(this);
}


@Builder.Default
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Report> reportList = new ArrayList<>();
Expand All @@ -82,5 +83,7 @@ public void addReport(Report report) {
report.setUser(this);
}


public void updateAddress(Address address) {
this.address = address;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public enum SuccessCode implements BaseCode { // 성공
USER_LOGOUT_SUCCESS(HttpStatus.OK, "USER_2001", "로그아웃 되었습니다."),
USER_REISSUE_SUCCESS(HttpStatus.OK, "USER_2002", "토큰 재발급이 완료되었습니다."),
USER_DELETE_SUCCESS(HttpStatus.OK, "USER_2003", "회원탈퇴가 완료되었습니다."),
USER_PROFILE_UPDATE_SUCCESS(HttpStatus.OK, "USER_2006", "프로필 저장이 완료되었습니다."),

MOCK_CREATE_SUCCESS(HttpStatus.CREATED, "MOCK_2011", "모의고사 등록이 완료되었습니다."),
MOCKSCORE_CREATE_SUCCESS(HttpStatus.CREATED, "MOCKSCORE_2011", "모의고사 성적 등록이 완료되었습니다."),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package hackerthon.likelion13th.canfly.login.auth.mapper;

import hackerthon.likelion13th.canfly.domain.user.Address;
import hackerthon.likelion13th.canfly.domain.user.OAuth;
import hackerthon.likelion13th.canfly.domain.user.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
Expand All @@ -25,6 +25,7 @@ public class CustomUserDetails implements UserDetails {
private String providerId;
private String username;
private String nickname;
private Address address;
private String email;
private String provider;
private String accessToken;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ public class OAuth2SuccessHandler implements AuthenticationSuccessHandler {
private List<String> getAuthorizedUris() {
return List.of(
defaultRedirect,
"http://localhost:3000"
"http://localhost:3000",
"http://localhost:3000/"
);
}

Expand Down Expand Up @@ -74,15 +75,19 @@ public void onAuthenticationSuccess(
JwtDto jwt = userService.jwtMakeSave(providerId);
log.info("🔑 JWT 발급 완료 | providerId={}", providerId);

/* 5. redirect_uri 검증 */
/* 5. 프로필 미완료 여부(needsProfile) 계산 */
boolean needsProfile = userService.needsProfile(providerId);

/* 6. redirect_uri 검증 */
String frontRedirect = request.getParameter("redirect_uri");
if (frontRedirect == null || !getAuthorizedUris().contains(frontRedirect)) {
frontRedirect = defaultRedirect;
}

/* 6. accessToken 쿼리 파라미터로 리다이렉트 */
/* 7. accessToken + needsProfile로 리다이렉트 */
String redirectUrl = UriComponentsBuilder.fromUriString(frontRedirect)
.queryParam("accessToken", jwt.getAccessToken())
.queryParam("needsProfile", needsProfile)
.build()
.toUriString();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import hackerthon.likelion13th.canfly.login.auth.mapper.CustomUserDetails;
import hackerthon.likelion13th.canfly.login.dto.CoinRequestDto;
import hackerthon.likelion13th.canfly.login.dto.CoinResponseDto;
import hackerthon.likelion13th.canfly.login.dto.ProfileRequestDto;
import hackerthon.likelion13th.canfly.login.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
Expand All @@ -17,8 +18,6 @@
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@Tag(name = "회원", description = "회원 관련 api 입니다.")
@RestController
@RequiredArgsConstructor
Expand Down Expand Up @@ -73,6 +72,22 @@ public ApiResponse<CoinResponseDto> updateUserCoins(
// 3. 최종적으로 변환된 DTO를 클라이언트에게 전달합니다.
return ApiResponse.onSuccess(SuccessCode.TOKEN_PROCESS_SUCCESS, responseDTO);
}

@Operation(summary = "프로필 수정", description = "팝업에서 입력한 전화번호/성별/학교/학년을 저장합니다 -> 성별 (MAN/WOMAN), 학년 (1, 2, 3)")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "USER_2006", description = "프로필 저장이 완료되었습니다.")
})
@PutMapping("/me/profile")
public ApiResponse<Boolean> completeProfile(
@AuthenticationPrincipal CustomUserDetails principal,
@RequestBody ProfileRequestDto req
) {
String providerId = principal.getUsername(); // providerId (CustomUserDetails.getUsername()가 providerId를 반환하도록 한 현재 설계)
boolean updated = userService.completeProfile(providerId, req);
return ApiResponse.onSuccess(SuccessCode.USER_PROFILE_UPDATE_SUCCESS, updated);
}

/*
@Operation(summary = "프로필 사진 첨부", description = "프로필 사진을 첨부하는 메서드입니다.")
@ApiResponses(value = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package hackerthon.likelion13th.canfly.login.dto;

import hackerthon.likelion13th.canfly.domain.entity.Sex;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Pattern;
import lombok.*;

@Schema(description = "ProfileReqDto")
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ProfileRequestDto {
@Schema(description = "전화번호")
@Pattern(
regexp = "^[0-9\\-]{9,15}$",
message = "전화번호 형식이 올바르지 않습니다."
)
private String phoneNumber;

@Schema(description = "성별")
private Sex sex;

@Schema(description = "고등학교")
private String highschool;

@Schema(description = "학년")
private Byte gradeNum;

@Schema(description = "우편번호")
private String zipcode;

@Schema(description = "주소")
private String address;

@Schema(description = "상세주소")
private String addressDetail;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package hackerthon.likelion13th.canfly.login.service;

import hackerthon.likelion13th.canfly.domain.user.Address;
import hackerthon.likelion13th.canfly.domain.user.User;
import hackerthon.likelion13th.canfly.global.api.ErrorCode;
import hackerthon.likelion13th.canfly.global.exception.GeneralException;
Expand All @@ -8,6 +9,7 @@
import hackerthon.likelion13th.canfly.login.auth.jwt.JwtTokenUtils;
import hackerthon.likelion13th.canfly.login.auth.service.JpaUserDetailsManager;
import hackerthon.likelion13th.canfly.login.converter.UserConverter;
import hackerthon.likelion13th.canfly.login.dto.ProfileRequestDto;
import hackerthon.likelion13th.canfly.login.dto.UserRequestDto;
import hackerthon.likelion13th.canfly.login.repository.OAuthRepository;
import hackerthon.likelion13th.canfly.login.repository.UserRepository;
Expand Down Expand Up @@ -126,6 +128,42 @@ public void deleteUser(String providerId) {
userRepository.delete(user);
}

public boolean needsProfile(String providerId) {
User user = findUserByProviderId(providerId);

boolean missingSex = (user.getSex() == null);
boolean missingPhone = (user.getPhoneNumber() == null || user.getPhoneNumber().isBlank());
boolean missingHighschool = (user.getHighschool() == null || user.getHighschool().isBlank());

Address addr = user.getAddress();
boolean missingAddress = (addr == null) || addr.isEmpty();

return missingSex || missingPhone || missingHighschool || missingAddress;
}

@Transactional
public boolean completeProfile(String providerId, ProfileRequestDto req) {
User user = findUserByProviderId(providerId);

user.setPhoneNumber(req.getPhoneNumber());
user.setSex(req.getSex());
user.setHighschool(req.getHighschool());
user.setGradeNum(req.getGradeNum());

String zipcode = req.getZipcode();
String address = req.getAddress();
String detail = req.getAddressDetail();

// 새로운 주소 설정
Address newAddress = new Address(zipcode, address, detail);
user.updateAddress(newAddress); // User 엔티티에 주소 업데이트
userRepository.save(user);

boolean stillNeeds = this.needsProfile(providerId);

return !stillNeeds;
}

public String checkMemberByName(String username) {
User user = findUserByUserName(username);
if (user.getPhoneNumber() != null) return "wasUser";
Expand Down