Skip to content

Commit

Permalink
Merge pull request #229 from BudgetBuddiesTeam/dev
Browse files Browse the repository at this point in the history
[feat] 기본정보 및 추가정보를 입력하는 API 구현
  • Loading branch information
SoulTree-Lovers authored Dec 9, 2024
2 parents 741d30a + df35cfe commit ebc6a48
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ ApiResponse<DiscountResponseDto> getDiscountInfo(
@PathVariable Long discountInfoId
);

@Operation(summary = "[ADMIN] 특정 사용자가 좋아요를 누른 할인정보 가져오기 API", description = "특정 사용자가 좋아요를 누른 할인정보들을 가져오는 API입니다. 페이징을 포함합니다.")
@Operation(summary = "[USER] 특정 사용자가 좋아요를 누른 할인정보 가져오기 API", description = "특정 사용자가 좋아요를 누른 할인정보들을 가져오는 API입니다. 페이징을 포함합니다.")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "PAGE4001", description = "요청된 페이지가 0보다 작습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ ApiResponse<SupportResponseDto> getSupportInfo(
@PathVariable Long supportInfoId
);

@Operation(summary = "[ADMIN] 특정 사용자가 좋아요를 누른 지원정보 가져오기 API", description = "특정 사용자가 좋아요를 누른 지원정보들을 가져오는 API입니다. 페이징을 포함합니다.")
@Operation(summary = "[USER] 특정 사용자가 좋아요를 누른 지원정보 가져오기 API", description = "특정 사용자가 좋아요를 누른 지원정보들을 가져오는 API입니다. 페이징을 포함합니다.")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "PAGE4001", description = "요청된 페이지가 0보다 작습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,18 @@ public static User toUser(UserDto.RegisterUserDto dto) {
// .photoUrl(dto.getPhotoUrl())
.build();
}

public static String ageToAgeGroup(Integer age) {
if (age < 20) {
return "20세미만";
} else if (age < 23) {
return "20-22세";
} else if (age < 26) {
return "23-25세";
} else if (age < 29) {
return "26-28세";
} else {
return "29세 이상";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class User extends BaseEntity {
@Column(nullable = false, unique = true)
private String phoneNumber;

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

@Min(value = 1, message = "나이는 0또는 음수가 될 수 없습니다.")
Expand All @@ -39,16 +39,16 @@ public class User extends BaseEntity {
@Column(columnDefinition = "varchar(20)")
private Gender gender;

@Column(nullable = false, length = 50, unique = true)
@Column(nullable = true, length = 50, unique = true)
private String email;

@Column(nullable = true)
private String mobileCarrier; // 통신사
@Column(nullable = true)
private String mobileCarrier; // 통신사

@Column(nullable = true)
private String region; // 거주지
@Column(nullable = true)
private String region; // 거주지

private LocalDateTime lastLoginAt;
private LocalDateTime lastLoginAt;


public void changeUserDate(String email, String name) {
Expand All @@ -59,4 +59,15 @@ public void changeUserDate(String email, String name) {
public List<GrantedAuthority> getAuthorities() {
return Collections.singletonList(new SimpleGrantedAuthority(role.name()));
}

public void setStandardInfo(String name, Gender gender, Integer age) {
this.name = name;
this.gender = gender;
this.age = age;
}

public void setAdditionalInfo(String mobileCarrier, String region) {
this.mobileCarrier = mobileCarrier;
this.region = region;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.UserConsumptionGoalResponse;
import com.bbteam.budgetbuddies.domain.user.dto.UserDto;
import com.bbteam.budgetbuddies.domain.user.entity.User;
import com.bbteam.budgetbuddies.global.security.auth.dto.AuthenticationRequest;
import com.bbteam.budgetbuddies.global.security.auth.dto.AuthenticationResponse;

import java.util.List;

Expand All @@ -19,4 +21,10 @@ public interface UserService {
List<UserDto.ResponseUserDto> findAll();

User getUser(Long userId);

AuthenticationResponse.StandardInfo saveStandardInfo(UserDto.AuthUserDto user, AuthenticationRequest.StandardInfo dto);

AuthenticationResponse.AdditionalInfo saveAdditionalInfo(UserDto.AuthUserDto user, AuthenticationRequest.AdditionalInfo dto);


}
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,24 @@
import com.bbteam.budgetbuddies.domain.user.dto.UserDto;
import com.bbteam.budgetbuddies.domain.user.entity.User;
import com.bbteam.budgetbuddies.domain.user.repository.UserRepository;
import com.bbteam.budgetbuddies.global.security.auth.dto.AuthenticationRequest;
import com.bbteam.budgetbuddies.global.security.auth.dto.AuthenticationResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
@Slf4j
public class UserServiceImpl implements UserService {

private final UserRepository userRepository;
Expand Down Expand Up @@ -113,4 +119,67 @@ public List<UserDto.ResponseUserDto> findAll() {
public User getUser(Long userId) {
return userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("Not found user"));
}

@Override
@Transactional
public AuthenticationResponse.StandardInfo saveStandardInfo(UserDto.AuthUserDto user, AuthenticationRequest.StandardInfo dto) {
log.info("dto.name: {}", dto.getName());
log.info("dto.gender: {}", dto.getGender());
log.info("dto.age: {}", dto.getAge());

User foundUser = userRepository.findById(user.getId()).orElseThrow(() -> new IllegalArgumentException("Not found user"));

foundUser.setStandardInfo(dto.getName(), dto.getGender(), dto.getAge());

foundUser = userRepository.save(foundUser);

// log.info("user id: {}", foundUser.getId());
// log.info("user name: {}", foundUser.getName());
// log.info("user phoneNumber: {}", foundUser.getPhoneNumber());
// log.info("user age: {}", foundUser.getAge());
// log.info("user gender: {}", foundUser.getGender());
// log.info("user mobileCarrier: {}", foundUser.getMobileCarrier());
// log.info("user region: {}", foundUser.getRegion());

return AuthenticationResponse.StandardInfo.builder()
.id(user.getId())
.name(foundUser.getName())
.gender(foundUser.getGender())
.ageGroup(UserConverter.ageToAgeGroup(foundUser.getAge()))
.build();

}

@Override
@Transactional
public AuthenticationResponse.AdditionalInfo saveAdditionalInfo(UserDto.AuthUserDto user, AuthenticationRequest.AdditionalInfo dto) {
// null 확인 및 초기화
List<Long> hashtagIds = Optional.ofNullable(dto.getHashtagIds()).orElse(Collections.emptyList());

dto.getHashtagIds().stream().map(it -> {
log.info("hashtagId: {}", it);
return null;
});

User foundUser = userRepository.findById(user.getId()).orElseThrow(() -> new IllegalArgumentException("Not found user"));

// log.info("user id: {}", foundUser.getId());
// log.info("user name: {}", foundUser.getName());
// log.info("user phoneNumber: {}", foundUser.getPhoneNumber());
// log.info("user age: {}", foundUser.getAge());
// log.info("user gender: {}", foundUser.getGender());
// log.info("user mobileCarrier: {}", foundUser.getMobileCarrier());
// log.info("user region: {}", foundUser.getRegion());

foundUser.setAdditionalInfo(dto.getMobileCarrier(), dto.getRegion());

foundUser = userRepository.save(foundUser);

return AuthenticationResponse.AdditionalInfo.builder()
.id(foundUser.getId())
.mobileCarrier(foundUser.getMobileCarrier())
.region(foundUser.getRegion())
.hashtagIds(dto.getHashtagIds())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.bbteam.budgetbuddies.global.security.auth.controller;

import com.bbteam.budgetbuddies.apiPayload.ApiResponse;
import com.bbteam.budgetbuddies.apiPayload.code.ErrorReasonDto;
import com.bbteam.budgetbuddies.domain.user.dto.UserDto;
import com.bbteam.budgetbuddies.global.security.auth.dto.AuthenticationRequest;
import com.bbteam.budgetbuddies.global.security.auth.dto.AuthenticationResponse;
import com.bbteam.budgetbuddies.global.security.utils.AuthUser;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
Expand Down Expand Up @@ -41,4 +44,35 @@ ApiResponse<AuthenticationResponse.SendTokens> login(
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ApiResponse.class)))
})
ApiResponse<AuthenticationResponse.SendAccessToken> reIssueAccessToken();

@Operation(summary = "[User] User 기본정보 입력 API", description = "첫 로그인 시 사용자의 기본정보를 등록하는 API입니다.")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class)))
})
ApiResponse<AuthenticationResponse.StandardInfo> saveStandardInfo(
@AuthUser UserDto.AuthUserDto user,
@RequestBody AuthenticationRequest.StandardInfo dto
);


@Operation(summary = "[User] User 추가정보 입력 API", description = "첫 로그인 시 사용자의 추가정보를 등록하는 API입니다.")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class)))
})
ApiResponse<AuthenticationResponse.AdditionalInfo> saveAdditionalInfo(
@AuthUser UserDto.AuthUserDto user,
@RequestBody AuthenticationRequest.AdditionalInfo dto
);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.bbteam.budgetbuddies.global.security.auth.controller;

import com.bbteam.budgetbuddies.apiPayload.ApiResponse;
import com.bbteam.budgetbuddies.domain.user.dto.UserDto;
import com.bbteam.budgetbuddies.domain.user.entity.User;
import com.bbteam.budgetbuddies.domain.user.service.UserService;
import com.bbteam.budgetbuddies.global.security.auth.dto.AuthenticationRequest;
import com.bbteam.budgetbuddies.global.security.auth.dto.AuthenticationResponse;
import com.bbteam.budgetbuddies.global.security.auth.service.AuthenticationService;
import com.bbteam.budgetbuddies.global.security.otp.OtpNumber;
import com.bbteam.budgetbuddies.global.security.utils.AuthUser;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
Expand All @@ -19,6 +22,8 @@ public class AuthenticationController implements AuthenticationApi {

private final AuthenticationService authenticationService; // 인증 관련 서비스

private final UserService userService;

/**
* OTP를 요청하는 엔드포인트.
* 전화번호를 입력받아 해당 번호로 OTP를 발송하고, 발송된 OTP 정보를 반환합니다.
Expand Down Expand Up @@ -80,5 +85,33 @@ public ApiResponse<AuthenticationResponse.SendAccessToken> reIssueAccessToken()
AuthenticationResponse.SendAccessToken response = authenticationService.reIssueAccessToken(user);
return ApiResponse.onSuccess(response); // 성공 응답 반환
}

@Override
@PostMapping("/standardInfo")
public ApiResponse<AuthenticationResponse.StandardInfo> saveStandardInfo(
@AuthUser UserDto.AuthUserDto user,
@RequestBody AuthenticationRequest.StandardInfo dto
) {
// 유저 정보 저장
AuthenticationResponse.StandardInfo savedUser = userService.saveStandardInfo(user, dto);

return ApiResponse.onSuccess(savedUser);
}

@Override
@PostMapping("/additionalInfo")
public ApiResponse<AuthenticationResponse.AdditionalInfo> saveAdditionalInfo(
@AuthUser UserDto.AuthUserDto user,
@RequestBody AuthenticationRequest.AdditionalInfo dto
) {
// 유저 정보 저장
AuthenticationResponse.AdditionalInfo savedUser = userService.saveAdditionalInfo(user, dto);

// 유저가 선택한 해시태그를 저장
userService.saveFavoriteHashtags(savedUser.getId(), dto.getHashtagIds());

return ApiResponse.onSuccess(savedUser);
}

}

Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.bbteam.budgetbuddies.global.security.auth.dto;


import com.bbteam.budgetbuddies.enums.Gender;
import com.bbteam.budgetbuddies.global.security.auth.validation.ValidPhoneNumber;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

public class AuthenticationRequest {

@Builder
Expand All @@ -30,5 +33,20 @@ public static class ToLogin {
private String otpNumber;
}

@Getter
@Builder
public static class StandardInfo {
private String name;
private Gender gender;
private Integer age;
}


@Getter
@Builder
public static class AdditionalInfo {
private String mobileCarrier;
private String region;
private List<Long> hashtagIds; // 사용자가 선택한 해시태그 ID 목록
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.bbteam.budgetbuddies.global.security.auth.dto;

import com.bbteam.budgetbuddies.enums.Gender;
import com.bbteam.budgetbuddies.global.security.otp.OtpNumber;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

public class AuthenticationResponse {

@Getter
Expand Down Expand Up @@ -59,4 +62,23 @@ public static class SendAccessToken {
@Schema(description = "액세스 토큰")
private String accessToken; // 액세스 토큰
}


@Getter
@Builder
public static class StandardInfo {
private Long id;
private String name;
private Gender gender;
private String ageGroup;
}

@Getter
@Builder
public static class AdditionalInfo {
private Long id;
private String mobileCarrier;
private String region;
private List<Long> hashtagIds; // 사용자가 선택한 해시태그 ID 목록
}
}

0 comments on commit ebc6a48

Please sign in to comment.